diff --git a/.coderabbit.yml b/.coderabbit.yml new file mode 100644 index 0000000000..38a7733ed3 --- /dev/null +++ b/.coderabbit.yml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +language: "en-US" +early_access: false +reviews: + profile: "chill" + request_changes_workflow: false + high_level_summary: false + poem: false + review_status: false + collapse_walkthrough: true + abort_on_close: true + auto_review: + enabled: true + drafts: false + path_filters: + - "!*.po" + - "!*.md" + - "!*.rst" +chat: + auto_reply: false diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index af67b0e349..288684eb7e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -34,11 +34,6 @@ tsconfig.json @centreon/owners-react *.jsx @centreon/owners-react **/cypress/** @centreon/owners-react -centreon-gorgone/ @centreon/owners-perl -centreon-gorgone/docs/ @centreon/owners-doc -centreon-gorgone/tests/ @centreon/owners-robot-e2e - -centreon-gorgone/tests/robot/config/ @centreon/owners-perl *.pm @centreon/owners-perl *.pl @centreon/owners-perl @@ -55,5 +50,8 @@ centreon-gorgone/tests/robot/config/ @centreon/owners-perl **/project/ @centreon/owners-pipelines **/packaging/ @centreon/owners-pipelines dependencies/** @centreon/owners-pipelines +.coderabbit.yml @centreon/owners-pipelines + +**/config/features.json @centreon/release-management -**/config/features.json @centreon/release-management +**/tests/rest_api/** @centreon/owners-api-testing diff --git a/.github/actions/check-latest-nightly-status/action.yml b/.github/actions/check-latest-nightly-status/action.yml new file mode 100644 index 0000000000..70df8db4cb --- /dev/null +++ b/.github/actions/check-latest-nightly-status/action.yml @@ -0,0 +1,28 @@ +name: "check-latest-nightly-status" +description: "Check the status of the latest nightly build" +outputs: + last_nightly_result: + description: "The status of the latest nightly build (success or failure)" + value: ${{ steps.check-latest-nightly-status.outputs.last_nightly_result }} + +runs: + using: "composite" + steps: + - name: Check the status of the latest nightly build + id: check-latest-nightly-status + run: | + set -x + + echo "[INFO]: Filtering the results of the last nightly build" + lastNightlyRunDetails=$(gh run ls \ + --json number,status,conclusion \ + --event schedule \ + --workflow web.yml \ + --branch develop \ + --limit 1) + + echo "Last nightly run details:" + echo "$lastNightlyRunDetails" + + echo "last_nightly_result=$(echo "$lastNightlyRunDetails" | jq -r '.[0].conclusion')" >> $GITHUB_OUTPUT + shell: bash diff --git a/.github/actions/chromatic/action.yml b/.github/actions/chromatic/action.yml index 78b42ed219..314d2bd406 100644 --- a/.github/actions/chromatic/action.yml +++ b/.github/actions/chromatic/action.yml @@ -21,7 +21,7 @@ runs: using: "composite" steps: - - uses: pnpm/action-setup@d882d12c64e032187b2edb46d3a0d003b7a43598 # v2.4.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 run_install: false diff --git a/.github/actions/code-coverage-gate-keeper/action.yml b/.github/actions/code-coverage-gate-keeper/action.yml index 76ce7fb088..df7cc748c0 100644 --- a/.github/actions/code-coverage-gate-keeper/action.yml +++ b/.github/actions/code-coverage-gate-keeper/action.yml @@ -12,6 +12,16 @@ inputs: name: description: 'The name for display purpose' required: true + dynamicCodeCoveragesFilePath: + required: true + description: 'The path to the dynamic code coverages file' + generateNewCodeCoverages: + required: false + default: 'false' + description: 'Generates new code coverages bas stats or not' +outputs: + has_new_code_coverage: + description: 'This tells if a new code coverages file has been generated' runs: using: 'node20' diff --git a/.github/actions/code-coverage-gate-keeper/index.js b/.github/actions/code-coverage-gate-keeper/index.js index 28236a987e..0fa50e449e 100644 --- a/.github/actions/code-coverage-gate-keeper/index.js +++ b/.github/actions/code-coverage-gate-keeper/index.js @@ -1,92 +1,132 @@ -const core = require('@actions/core'); -const { getOctokit, context } = require('@actions/github'); -const fs = require('fs'); -const { execSync } = require('child_process'); - -const limit = 20; - -const getExistingComments = async ({ octokit, context, title }) => { - let page = 0; - let results = []; - let response; - - do { - response = await octokit.rest.issues.listComments({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - per_page: limit, - page: page, - }); - results = results.concat(response.data); - page = page + 1; - } while (response.data.length === limit) - - return results.filter( - comment => !!comment.user && comment.body.includes(title), - ) -} - -const deleteOldComments = async ({ octokit, context, title }) => { - const existingComments = await getExistingComments({ octokit, context, title }) - - existingComments.forEach((existingComment) => { - core.debug(`Deleting comment: ${existingComment.id}`) - try { - octokit.rest.issues.deleteComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: existingComment.id, - }) - } catch (error) { - console.error(error) - } - }) -} - -const run = async () => { - try { - const modulePath = core.getInput('module_path'); - const githubToken = core.getInput('github_token'); - const name = core.getInput('name'); - - if (context.payload.pull_request === null) { - return; - } - - execSync('pnpx nyc report --reporter json-summary --report-dir /tmp'); - - const coverageFile = fs.readFileSync('/tmp/coverage-summary.json'); - const coverage = JSON.parse(coverageFile); - - const package = fs.readFileSync(`${modulePath}/package.json`); - const baseCodeCoveragePercentage =JSON.parse(package).baseCodeCoveragePercentage - - const codeCoverageLines = coverage.total.lines.pct; - - const passGateKeep = codeCoverageLines >= baseCodeCoveragePercentage; - - const octokit = getOctokit(githubToken); - - const title = `Code Coverage Check on ${name}`; - - await deleteOldComments({ octokit, context, title }) - - core.info(`Pass the gate keep? ${passGateKeep} (INFO: lines: ${codeCoverageLines}, base percentage: ${baseCodeCoveragePercentage})`) - - if (!passGateKeep) { - const pull_request_number = context.payload.pull_request.number; - octokit.rest.issues.createComment({ - ...context.repo, - issue_number: pull_request_number, - body: `

📋 ${title} ❌

- Your code coverage is ${codeCoverageLines}% but the required code coverage is ${baseCodeCoveragePercentage}%.` - }); - core.setFailed(`Does not pass the code coverage check (${codeCoverageLines}% instead of ${baseCodeCoveragePercentage}%)`); - } - } catch (error) { - core.setFailed(error.message); - } -} - -run(); \ No newline at end of file +const core = require('@actions/core'); +const { getOctokit, context } = require('@actions/github'); +const fs = require('fs'); +const { execSync } = require('child_process'); + +const limit = 20; + +const getExistingComments = async ({ octokit, context, title }) => { + let page = 0; + let results = []; + let response; + + do { + response = await octokit.rest.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + per_page: limit, + page: page + }); + results = results.concat(response.data); + page = page + 1; + } while (response.data.length === limit); + + return results.filter( + (comment) => !!comment.user && comment.body.includes(title) + ); +}; + +const deleteOldComments = async ({ octokit, context, title }) => { + const existingComments = await getExistingComments({ + octokit, + context, + title + }); + + existingComments.forEach((existingComment) => { + core.info(`Deleting comment: ${existingComment.id}`); + try { + octokit.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.id + }); + } catch (error) { + console.error(error); + } + }); +}; + +const run = async () => { + try { + const modulePath = core.getInput('module_path'); + const githubToken = core.getInput('github_token'); + const name = core.getInput('name'); + const dynamicCodeCoveragesFilePath = core.getInput( + 'dynamicCodeCoveragesFilePath' + ); + const generateNewCodeCoverages = core.getBooleanInput( + 'generateNewCodeCoverages' + ); + + execSync('pnpx nyc report --reporter json-summary --report-dir /tmp'); + + const coverageFile = fs.readFileSync('/tmp/coverage-summary.json'); + const coverage = JSON.parse(coverageFile); + const module = modulePath.replaceAll('/', '-'); + const codeCoverageLines = coverage.total.lines.pct; + const codeCoverages = JSON.parse( + fs.readFileSync(dynamicCodeCoveragesFilePath) + ); + const baseCodeCoveragePercentage = codeCoverages[module]; + const lowerBaseCodeCoverage = baseCodeCoveragePercentage - 0.04; + + const passGateKeep = + codeCoverageLines >= lowerBaseCodeCoverage || + codeCoverageLines >= baseCodeCoveragePercentage; + const strictlyPassGateKeep = + codeCoverageLines >= baseCodeCoveragePercentage; + + if (generateNewCodeCoverages) { + if (!strictlyPassGateKeep) { + core.info( + `Cannot update base percentage for ${module}. Requirement: ${baseCodeCoveragePercentage}%. Current: ${codeCoverageLines}%` + ); + return; + } + const newCodeCoverages = { + ...codeCoverages, + [module]: codeCoverageLines + }; + fs.writeFileSync( + '/tmp/newBaseCodeCoverages.json', + JSON.stringify(newCodeCoverages) + ); + core.info(`New code coverage for ${module}: ${codeCoverageLines}%`); + core.setOutput('has_new_code_coverage', 'true'); + return; + } + + const octokit = getOctokit(githubToken); + + const title = `Code Coverage Check on ${name}`; + + if (context.payload.pull_request) { + await deleteOldComments({ octokit, context, title }); + } + + core.info( + `Does it pass the gate keep? ${passGateKeep} (INFO: lines: ${codeCoverageLines}, base percentage: ${baseCodeCoveragePercentage})` + ); + + if (!passGateKeep) { + if (context.payload.pull_request) { + core.info(`Creating comment on pull request.`); + octokit.rest.issues.createComment({ + ...context.repo, + issue_number: context.payload.pull_request.number, + body: `

📋 ${title} ❌

+ Your code coverage is ${codeCoverageLines}% but the required code coverage is ${baseCodeCoveragePercentage}%.` + }); + } + core.setFailed( + `Does not pass the code coverage check (${codeCoverageLines}% instead of ${baseCodeCoveragePercentage}%)` + ); + } + } catch (error) { + core.setFailed(error.message); + } +}; + +run(); diff --git a/.github/actions/cypress-e2e-testing/action.yml b/.github/actions/cypress-e2e-testing/action.yml index e0c051ce37..0c36178935 100644 --- a/.github/actions/cypress-e2e-testing/action.yml +++ b/.github/actions/cypress-e2e-testing/action.yml @@ -25,17 +25,33 @@ inputs: feature_file_path: description: "feature file" required: true + test_tags: + description: "filter tests by tags" + required: false + default: "not @ignore" dependencies_lock_file: description: "The frontend dependencies lock file path" required: true test_execution_key: description: "xray test execution key" required: true + stability: + description: "Branch stability" + required: true + is_cloud: + description: "Define if the version is targeting cloud" + required: false + artifactory_internal_repo_username: + description: "Artifactory internal repository username" + required: false + artifactory_internal_repo_password: + description: "Artifactory internal repository password" + required: false runs: using: "composite" steps: - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 run_install: false @@ -67,7 +83,7 @@ runs: - name: Cypress end-to-end testing uses: cypress-io/github-action@1b70233146622b69e789ccdd4f9452adc638d25a # v6.6.1 with: - command: pnpm run cypress:run --browser electron --spec features/**/${{ inputs.feature_file_path }} + command: pnpm run cypress:run --browser electron --spec features/**/${{ inputs.feature_file_path }} --env tags="${{ inputs.test_tags }}" install: false working-directory: ${{ inputs.module }}/tests/e2e publish-summary: false @@ -78,6 +94,10 @@ runs: CYPRESS_WEB_IMAGE_VERSION: ${{ inputs.web_image_version }} CYPRESS_OPENID_IMAGE_VERSION: ${{ inputs.openid_image_version }} CYPRESS_SAML_IMAGE_VERSION: ${{ inputs.saml_image_version }} + CYPRESS_STABILITY: ${{ inputs.stability }} + CYPRESS_IS_CLOUD: ${{ inputs.is_cloud }} + CYPRESS_INTERNAL_REPO_USERNAME: ${{ inputs.artifactory_internal_repo_username }} + CYPRESS_INTERNAL_REPO_PASSWORD: ${{ inputs.artifactory_internal_repo_password }} - name: Ensure logs directory exists run: mkdir -p ${{ inputs.module }}/tests/e2e/results/cucumber-logs/ diff --git a/.github/actions/frontend-build/action.yml b/.github/actions/frontend-build/action.yml index 14c20a3aa4..f891d45621 100644 --- a/.github/actions/frontend-build/action.yml +++ b/.github/actions/frontend-build/action.yml @@ -27,7 +27,7 @@ inputs: runs: using: "composite" steps: - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 run_install: false diff --git a/.github/actions/frontend-lint/action.yml b/.github/actions/frontend-lint/action.yml index 9134df7841..b6229a49e7 100644 --- a/.github/actions/frontend-lint/action.yml +++ b/.github/actions/frontend-lint/action.yml @@ -14,12 +14,19 @@ inputs: description: The eslint command required: false default: eslint + pat: + description: "The personal access token" + required: true + lint_path: + required: false + description: "The path to lint" + default: '.' runs: using: "composite" steps: - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 run_install: false @@ -39,14 +46,17 @@ runs: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true" - - name: Run ESLint - run: pnpm eslint -f json -o eslint-report.json --max-warnings 0 - working-directory: ${{ inputs.frontend_directory }} - shell: bash + - name: Setup Biome CLI + uses: biomejs/setup-biome@0de019f8c69e70cd3dc5535e7943afa3b05f94b7 # v2.2.1 + with: + working-dir: ${{ inputs.frontend_directory }} + token: ${{ inputs.pat }} - - if: failure() - uses: ./.github/actions/publish-report + - uses: mongolyy/reviewdog-action-biome@6b01155716493e5cc365df64aa0946ec9adc53c2 # v1.6.1 with: - path: ${{ inputs.frontend_directory }}/eslint-report.json - format: eslint - check_name: ${{ inputs.module_name }}-eslint-report + workdir: ${{ inputs.frontend_directory }} + github_token: ${{ inputs.pat }} + reporter: github-pr-check + fail_on_error: true + level: 'error' + biome_flags: ${{ inputs.lint_path }} diff --git a/.github/actions/gherkin-lint/.gherkin-lintrc b/.github/actions/gherkin-lint/.gherkin-lintrc index 7978147e71..b133f3a148 100644 --- a/.github/actions/gherkin-lint/.gherkin-lintrc +++ b/.github/actions/gherkin-lint/.gherkin-lintrc @@ -38,7 +38,8 @@ "on", { "tags": [ - "@ignore" + "@ignore", + "@system" ], "patterns": [ "^@REQ_MON-[1-9]\\d+$", diff --git a/.github/actions/gherkin-lint/action.yml b/.github/actions/gherkin-lint/action.yml index 6b6de807ca..f76925e4f5 100644 --- a/.github/actions/gherkin-lint/action.yml +++ b/.github/actions/gherkin-lint/action.yml @@ -3,7 +3,7 @@ description: Gherkin linter inputs: features_path: - description: The path to the feature files + description: "The path to the feature files" required: true runs: diff --git a/.github/actions/lighthouse-performance-testing/action.yml b/.github/actions/lighthouse-performance-testing/action.yml index ea7b9cd7c2..bf4939b53f 100644 --- a/.github/actions/lighthouse-performance-testing/action.yml +++ b/.github/actions/lighthouse-performance-testing/action.yml @@ -26,7 +26,7 @@ inputs: runs: using: "composite" steps: - - uses: pnpm/action-setup@d882d12c64e032187b2edb46d3a0d003b7a43598 # v2.4.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 run_install: false @@ -45,7 +45,7 @@ runs: php-version: 8.1 extensions: yaml, xml, mysql, dom, mbstring, intl, pdo, zip coverage: none - tools: composer:v2.6 + tools: composer:v2 - name: Start Centreon Web and database containers env: @@ -66,7 +66,7 @@ runs: MYSQL_IMAGE: ${{ inputs.database_image }} run: | cd centreon-injector - composer install + composer install --no-plugins --no-scripts cd .. docker compose -f .github/docker/docker-compose.yml cp centreon-injector web:/usr/share docker compose -f .github/docker/docker-compose.yml exec web sed -i 's/127.0.0.1/db/g' /usr/share/centreon-injector/.env diff --git a/.github/actions/nightly-platform-deploy/action.yml b/.github/actions/nightly-platform-deploy/action.yml deleted file mode 100644 index f97adb3b2f..0000000000 --- a/.github/actions/nightly-platform-deploy/action.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: "nightly-platform-deploy" -description: "Deploy a platform with packages from nightly builds." -inputs: - deploy_type: - description: "The type of platform deployment (install or update)" - required: false - ref: - description: "Reference branch for centreon on demand" - required: true - bu: - description: "Business unit to use" - required: true - poller_number: - description: "Instance poller number" - required: true - instance_features: - description: "Operating System name" - required: true - centreon_branch: - description: "centreon OSS branch" - required: true - configured_resources: - description: "Preconfigure resources on Central" - required: true - install_business_modules: - description: "Pre install business modules" - required: true - instance_password: - description: "Instance central password" - required: true - cod_service_token: - description: "COD service token" - required: true - -runs: - using: "composite" - steps: - - name: Destroy any previous nightly COD platform - run: | - set -x - - # Destroy the previous existing instance everytime - echo "[INFO]: Destroying previous nightly COD instance." - curl --fail \ - -s \ - -o /dev/null \ - -X POST \ - -H "Authorization: Bearer ${{inputs.cod_service_token}}" \ - -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/centreon/centreon-on-demand/actions/workflows/destroy.yml/dispatches \ - -d '{"ref": "main", "inputs":{"confirm":"true"} }' \ - -w %http_code - - shell: bash - - - name: Deploy a COD platform with nightly build artifacts - run: | - set -x - - # Deploy a new fresh instance if destroy suceeded - echo "[INFO]: Deploying nightly COD instance with latest ${{ inputs.centreon_branch }} state." - curl --fail \ - -s \ - -o /dev/null \ - -X POST \ - -H "Authorization: Bearer ${{inputs.cod_service_token}}" \ - -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/centreon/centreon-on-demand/actions/workflows/deploy.yml/dispatches \ - -d '{"ref": "main", "inputs":{"bu":"${{ inputs.bu }}", "deployment_profile":"Standard profile", "poller_number":"${{ inputs.poller_number }}", "instance_features":"${{ inputs.instance_features }}", "centreon_branch":"${{ inputs.centreon_branch }}", "custom_centreon_web_admin_password":"${{ inputs.instance_password }}", "configured_resources":"${{ inputs.configured_resources }}", "install_business_modules":"${{ inputs.install_business_modules }}" }}' - shell: bash diff --git a/.github/actions/npm-publish-package-beta/action.yml b/.github/actions/npm-publish-package-beta/action.yml index 6dfa7abdce..e75a69a49b 100644 --- a/.github/actions/npm-publish-package-beta/action.yml +++ b/.github/actions/npm-publish-package-beta/action.yml @@ -28,7 +28,7 @@ runs: with: node-version: 20 - - uses: pnpm/action-setup@d882d12c64e032187b2edb46d3a0d003b7a43598 # v2.4.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 @@ -72,7 +72,7 @@ runs: shell: bash - name: Publish package to NPM (${{ env.TAG }}) - uses: JS-DevTools/npm-publish@v2 + uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c # v3.1.1 with: access: public package: ${{ env.directory }}/package.json diff --git a/.github/actions/npm-publish-package-stable/action.yml b/.github/actions/npm-publish-package-stable/action.yml index 123f2764dc..18eacaddaf 100644 --- a/.github/actions/npm-publish-package-stable/action.yml +++ b/.github/actions/npm-publish-package-stable/action.yml @@ -28,7 +28,7 @@ runs: with: node-version: 20 - - uses: pnpm/action-setup@d882d12c64e032187b2edb46d3a0d003b7a43598 # v2.4.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 @@ -72,7 +72,7 @@ runs: shell: bash - name: Publish package to NPM (${{ env.TAG }}) - uses: JS-DevTools/npm-publish@v2 + uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c # v3.1.1 with: access: public package: ${{ env.directory }}/package.json diff --git a/.github/actions/promote-to-stable/action.yml b/.github/actions/promote-to-stable/action.yml index 59665d9f74..42bf4e884b 100644 --- a/.github/actions/promote-to-stable/action.yml +++ b/.github/actions/promote-to-stable/action.yml @@ -108,7 +108,7 @@ runs: shell: bash - name: Promote DEB packages to stable - if: ${{ contains(fromJSON('["bullseye", "bookworm"]') , inputs.distrib) }} + if: ${{ contains(fromJSON('["bullseye", "bookworm"]') , inputs.distrib) && !inputs.release_cloud }} run: | set -eux diff --git a/.github/actions/publish-cypress-report/action.yml b/.github/actions/publish-cypress-report/action.yml index 1f9cd4370a..5028ffe43c 100644 --- a/.github/actions/publish-cypress-report/action.yml +++ b/.github/actions/publish-cypress-report/action.yml @@ -15,7 +15,7 @@ runs: with: node-version: 20 - - uses: pnpm/action-setup@d882d12c64e032187b2edb46d3a0d003b7a43598 # v2.4.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 diff --git a/.github/actions/publish-storybook/action.yml b/.github/actions/publish-storybook/action.yml index 3505720be1..3d828f8e28 100644 --- a/.github/actions/publish-storybook/action.yml +++ b/.github/actions/publish-storybook/action.yml @@ -16,7 +16,7 @@ runs: with: node-version: 20 - - uses: pnpm/action-setup@d882d12c64e032187b2edb46d3a0d003b7a43598 # v2.4.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0 with: version: 8 diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml index a361800565..9162c91ad2 100644 --- a/.github/actions/release/action.yml +++ b/.github/actions/release/action.yml @@ -25,13 +25,15 @@ runs: steps: - name: Checkout sources uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 - name: Get released versions for components run: | set -eux # Variables - COMPONENTS_OSS=("centreon-awie" "centreon-dsm" "centreon-gorgone" "centreon-ha" "centreon-open-tickets" "centreon-web") + COMPONENTS_OSS=("centreon-awie" "centreon-dsm" "centreon-ha" "centreon-open-tickets" "centreon-web") CURRENT_STABLE_BRANCH_MAJOR_VERSION="" declare -a TMP_STABLE_TAGS=() declare -a NEW_STABLE_TAGS=() @@ -187,6 +189,7 @@ runs: JIRA_RELEASE_NAME="" JIRA_PROJECT_ID="${{ inputs.jira_project_id }}" JIRA_RELEASE_RELEASED="false" + JIRA_RELEASE_ID="$(git log |grep -E "Centreon\ next.*\#[0-9]{5,}\#\)" |grep -o -P "(?<=#)[0-9]{5,}(?=#)" |head -n 1)" # Create JIRA version for each released component echo "Creating JIRA releases." @@ -196,7 +199,7 @@ runs: # Build JSON with release information for JIRA API JIRA_RELEASE_DATA=$(jq -nc \ --arg archived "$JIRA_RELEASE_ARCHIVED" \ - --arg description "$TAG" \ + --arg description "$JIRA_RELEASE_ID $TAG" \ --arg releaseDate "$JIRA_RELEASE_DATE" \ --arg name "$TAG" \ --arg projectId "$JIRA_PROJECT_ID" \ diff --git a/.github/actions/web-frontend-component-test/action.yml b/.github/actions/web-frontend-component-test/action.yml deleted file mode 100644 index 3bd134febf..0000000000 --- a/.github/actions/web-frontend-component-test/action.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: "Web Cypress Component Testing" -description: "Web Cypress Component Testing" -inputs: - module: - description: "Module on which the test will be run" - required: true - spec_file_path: - description: "Path of spec file." - required: true - dependencies_lock_file: - description: "The frontend dependencies lock file path" - required: true - -runs: - using: "composite" - steps: - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 8 - run_install: false - - - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - with: - node-version: 20 - cache: pnpm - cache-dependency-path: ${{ inputs.dependencies_lock_file }} - - - name: Install dependencies - run: pnpm install --frozen-lockfile - working-directory: ${{ inputs.module }} - shell: bash - env: - CYPRESS_INSTALL_BINARY: "0" - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" - PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true" - - - name: Install Cypress binary - uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0 - with: - timeout_seconds: 120 - max_attempts: 10 - retry_wait_seconds: 30 - retry_on: error - command: cd ${{ inputs.module }} && pnpm cypress install --force - - - name: Cypress web component testing - uses: cypress-io/github-action@1b70233146622b69e789ccdd4f9452adc638d25a # v6.6.1 - with: - browser: chrome - component: true - install: false - cache-key: cypress-cache-${{ runner.os }}-${{ hashFiles(inputs.dependencies_lock_file) }} - working-directory: ${{ inputs.module }} - spec: ${{ inputs.spec_file_path }} - publish-summary: false - env: codeCoverageTasksRegistered=true - - - name: Clean up code coverage results - shell: bash - run: node centreon/packages/js-config/cypress/component/excludeNodeModulesFromCoverage.js ${{ inputs.module }}/.nyc_output/out.json - - - name: Archive test results - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - if: ${{ failure() }} - with: - name: component-test-results - path: | - ${{ inputs.module }}/cypress/results/videos - ${{ inputs.module }}/cypress/screenshots - ${{ inputs.module }}/cypress/visual-testing-snapshots/**/*.diff.png - retention-days: 1 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3f83b6aa3b..06c60c3390 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,8 +12,8 @@ updates: - package-ecosystem: npm directory: '/' schedule: - interval: weekly - open-pull-requests-limit: 10 + interval: daily + open-pull-requests-limit: 0 labels: - 'dependencies' - 'javascript' @@ -24,8 +24,8 @@ updates: - package-ecosystem: composer directory: '/' schedule: - interval: weekly - open-pull-requests-limit: 10 + interval: daily + open-pull-requests-limit: 0 labels: - 'dependencies' - 'php' diff --git a/.github/docker/.env b/.github/docker/.env index 6406ee4872..5f23dddc67 100644 --- a/.github/docker/.env +++ b/.github/docker/.env @@ -1,12 +1,14 @@ MYSQL_IMAGE=bitnami/mariadb:10.11 -OPENID_IMAGE=docker.centreon.com/centreon/keycloak:24.05 -SAML_IMAGE=docker.centreon.com/centreon/keycloak:24.05 +OPENID_IMAGE=docker.centreon.com/centreon/keycloak:24.07 +SAML_IMAGE=docker.centreon.com/centreon/keycloak:24.07 MYSQL_ROOT_PASSWORD=centreon MYSQL_USER=centreon MYSQL_PASSWORD=centreon MYSQL_AUTHENTICATION_PLUGIN=mysql_native_password +MYSQL_EXTRA_FLAGS="--secure-file-priv=" MARIADB_ROOT_PASSWORD=centreon MARIADB_USER=centreon MARIADB_PASSWORD=centreon +MARIADB_EXTRA_FLAGS="--secure-file-priv=" diff --git a/.github/docker/Dockerfile.gorgone-testing-alma8 b/.github/docker/Dockerfile.gorgone-testing-alma8 deleted file mode 100644 index c3a7b9cb7a..0000000000 --- a/.github/docker/Dockerfile.gorgone-testing-alma8 +++ /dev/null @@ -1,16 +0,0 @@ -FROM almalinux:8 - -RUN bash -e < /dev/null 2>&1 -apt-get update - -EOF diff --git a/.github/docker/centreon-web/alma8/Dockerfile b/.github/docker/centreon-web/alma8/Dockerfile index e84c8137dd..9738ee9a84 100644 --- a/.github/docker/centreon-web/alma8/Dockerfile +++ b/.github/docker/centreon-web/alma8/Dockerfile @@ -4,6 +4,7 @@ ARG VERSION FROM ${REGISTRY_URL}/centreon-web-dependencies-alma8:${VERSION} AS web_fresh ARG VERSION +ARG MYDUMPER_VERSION COPY *.rpm /tmp/rpms-centreon/ @@ -49,7 +50,7 @@ sed -i 's#severity=error#severity=debug#' /etc/sysconfig/gorgoned sed -i "5s/.*/ id: 1/" /etc/centreon-gorgone/config.d/40-gorgoned.yaml sed -i 's#enable: true#enable: false#' /etc/centreon-gorgone/config.d/50-centreon-audit.yaml -dnf install -y https://github.com/mydumper/mydumper/releases/download/v0.15.2-7/mydumper-0.15.2-7.el8.x86_64.rpm zstd +dnf install -y https://github.com/mydumper/mydumper/releases/download/v${MYDUMPER_VERSION}/mydumper-${MYDUMPER_VERSION}.el8.x86_64.rpm zstd mkdir -p /usr/local/src/sql/databases mydumper -h localhost -P 3306 -u root -G -o /usr/local/src/sql/databases/centreon -B centreon mydumper -h localhost -P 3306 -u root -G -o /usr/local/src/sql/databases/centreon_storage -B centreon_storage diff --git a/.github/docker/centreon-web/alma8/Dockerfile.dependencies b/.github/docker/centreon-web/alma8/Dockerfile.dependencies index 40830c76bb..9257354431 100644 --- a/.github/docker/centreon-web/alma8/Dockerfile.dependencies +++ b/.github/docker/centreon-web/alma8/Dockerfile.dependencies @@ -20,8 +20,8 @@ dnf config-manager --set-enabled powertools dnf install -y epel-release if [[ ${RELEASE_CLOUD} -eq 1 ]]; then - dnf config-manager --add-repo https://$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_USERNAME):$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_PASSWORD)@packages.centreon.com/rpm-standard-internal/24.05/el8/centreon-24.05-internal.repo - sed -i "s#packages.centreon.com/rpm-standard-internal#$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_USERNAME):$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_PASSWORD)@packages.centreon.com/rpm-standard-internal#" /etc/yum.repos.d/centreon-24.05-internal.repo + dnf config-manager --add-repo https://$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_USERNAME):$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_PASSWORD)@packages.centreon.com/rpm-standard-internal/24.09/el8/centreon-24.09-internal.repo + sed -i "s#packages.centreon.com/rpm-standard-internal#$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_USERNAME):$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_PASSWORD)@packages.centreon.com/rpm-standard-internal#" /etc/yum.repos.d/centreon-24.09-internal.repo else dnf config-manager --add-repo https://packages.centreon.com/rpm-standard/${VERSION}/el8/centreon-${VERSION}.repo fi @@ -118,8 +118,21 @@ dnf install -y \ # install and configure mariadb # ################################# -curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup \ - | bash -s -- --os-type=rhel --skip-check-installed --os-version=8 --mariadb-server-version="mariadb-10.5" +# curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup \ +# | bash -s -- --os-type=rhel --skip-check-installed --os-version=8 --mariadb-server-version="mariadb-10.11" + +cat <> /etc/yum.repos.d/mariadb.repo +[mariadb-main] +name = MariaDB Server +baseurl = https://dlm.mariadb.com/repo/mariadb-server/10.11/yum/rhel/8/x86_64 +gpgkey = file:///etc/pki/rpm-gpg/MariaDB-Server-GPG-KEY +gpgcheck = 1 +enabled = 1 +module_hotfixes = 1 +EOT + +rpm --import https://rpm.mariadb.org/RPM-GPG-KEY-MariaDB + dnf install -y mariadb-server mariadb echo "[server] diff --git a/.github/docker/centreon-web/alma8/slim-configuration/exec.txt b/.github/docker/centreon-web/alma8/slim-configuration/exec.txt index 1e5e107ed6..ee743c2bb7 100644 --- a/.github/docker/centreon-web/alma8/slim-configuration/exec.txt +++ b/.github/docker/centreon-web/alma8/slim-configuration/exec.txt @@ -21,4 +21,5 @@ systemctl stop cbd systemctl stop php-fpm systemctl stop httpd -rm -f /tmp/gorgone/*.ipc /var/log/centreon*/*.log /var/lib/centreon-gorgone/history.sdb +rm -f /tmp/gorgone/*.ipc /var/lib/centreon-gorgone/history.sdb +bash -c "find /var/log/centreon{,-engine,-broker,-gorgone} /var/lib/centreon-{engine,broker} /var/lib/centreon/{centcore,metrics,status} -type f -delete" diff --git a/.github/docker/centreon-web/alma9/Dockerfile b/.github/docker/centreon-web/alma9/Dockerfile index 670dfa822a..2bb3f2a7a5 100644 --- a/.github/docker/centreon-web/alma9/Dockerfile +++ b/.github/docker/centreon-web/alma9/Dockerfile @@ -4,6 +4,7 @@ ARG VERSION FROM ${REGISTRY_URL}/centreon-web-dependencies-alma9:${VERSION} ARG VERSION +ARG MYDUMPER_VERSION COPY *.rpm /tmp/rpms-centreon/ @@ -49,7 +50,7 @@ sed -i 's#severity=error#severity=debug#' /etc/sysconfig/gorgoned sed -i "5s/.*/ id: 1/" /etc/centreon-gorgone/config.d/40-gorgoned.yaml sed -i 's#enable: true#enable: false#' /etc/centreon-gorgone/config.d/50-centreon-audit.yaml -dnf install -y https://github.com/mydumper/mydumper/releases/download/v0.15.2-7/mydumper-0.15.2-7.el9.x86_64.rpm zstd +dnf install -y https://github.com/mydumper/mydumper/releases/download/v${MYDUMPER_VERSION}/mydumper-${MYDUMPER_VERSION}.el9.x86_64.rpm zstd mkdir -p /usr/local/src/sql/databases mydumper -h localhost -P 3306 -u root -G -o /usr/local/src/sql/databases/centreon -B centreon mydumper -h localhost -P 3306 -u root -G -o /usr/local/src/sql/databases/centreon_storage -B centreon_storage diff --git a/.github/docker/centreon-web/alma9/Dockerfile.dependencies b/.github/docker/centreon-web/alma9/Dockerfile.dependencies index 3e703fb357..18c31fa54e 100644 --- a/.github/docker/centreon-web/alma9/Dockerfile.dependencies +++ b/.github/docker/centreon-web/alma9/Dockerfile.dependencies @@ -20,8 +20,8 @@ dnf config-manager --set-enabled crb dnf install -y epel-release if [[ ${RELEASE_CLOUD} -eq 1 ]]; then - dnf config-manager --add-repo https://$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_USERNAME):$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_PASSWORD)@packages.centreon.com/rpm-standard-internal/24.05/el9/centreon-24.05-internal.repo - sed -i "s#packages.centreon.com/rpm-standard-internal#$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_USERNAME):$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_PASSWORD)@packages.centreon.com/rpm-standard-internal#" /etc/yum.repos.d/centreon-24.05-internal.repo + dnf config-manager --add-repo https://$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_USERNAME):$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_PASSWORD)@packages.centreon.com/rpm-standard-internal/24.09/el9/centreon-24.09-internal.repo + sed -i "s#packages.centreon.com/rpm-standard-internal#$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_USERNAME):$(cat /run/secrets/ARTIFACTORY_INTERNAL_REPO_PASSWORD)@packages.centreon.com/rpm-standard-internal#" /etc/yum.repos.d/centreon-24.09-internal.repo else dnf config-manager --add-repo https://packages.centreon.com/rpm-standard/${VERSION}/el9/centreon-${VERSION}.repo fi @@ -115,8 +115,21 @@ dnf install -y \ # install and configure mariadb # ################################# -curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup \ - | bash -s -- --os-type=rhel --skip-check-installed --os-version=9 --mariadb-server-version="mariadb-10.5" +# curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup \ +# | bash -s -- --os-type=rhel --skip-check-installed --os-version=9 --mariadb-server-version="mariadb-10.11" + +cat <> /etc/yum.repos.d/mariadb.repo +[mariadb-main] +name = MariaDB Server +baseurl = https://dlm.mariadb.com/repo/mariadb-server/10.11/yum/rhel/9/x86_64 +gpgkey = file:///etc/pki/rpm-gpg/MariaDB-Server-GPG-KEY +gpgcheck = 1 +enabled = 1 +module_hotfixes = 1 +EOT + +rpm --import https://rpm.mariadb.org/RPM-GPG-KEY-MariaDB + dnf install -y mariadb-server mariadb echo "[server] diff --git a/.github/docker/centreon-web/alma9/slim-configuration/exec.txt b/.github/docker/centreon-web/alma9/slim-configuration/exec.txt index 1e5e107ed6..ee743c2bb7 100644 --- a/.github/docker/centreon-web/alma9/slim-configuration/exec.txt +++ b/.github/docker/centreon-web/alma9/slim-configuration/exec.txt @@ -21,4 +21,5 @@ systemctl stop cbd systemctl stop php-fpm systemctl stop httpd -rm -f /tmp/gorgone/*.ipc /var/log/centreon*/*.log /var/lib/centreon-gorgone/history.sdb +rm -f /tmp/gorgone/*.ipc /var/lib/centreon-gorgone/history.sdb +bash -c "find /var/log/centreon{,-engine,-broker,-gorgone} /var/lib/centreon-{engine,broker} /var/lib/centreon/{centcore,metrics,status} -type f -delete" diff --git a/.github/docker/centreon-web/bookworm/Dockerfile b/.github/docker/centreon-web/bookworm/Dockerfile index 06a7fa3892..be92871b8c 100644 --- a/.github/docker/centreon-web/bookworm/Dockerfile +++ b/.github/docker/centreon-web/bookworm/Dockerfile @@ -4,8 +4,9 @@ ARG VERSION FROM ${REGISTRY_URL}/centreon-web-dependencies-bookworm:${VERSION} ARG VERSION +ARG MYDUMPER_VERSION -ENV DEBIAN_FRONTEND noninteractive +ENV DEBIAN_FRONTEND=noninteractive COPY *.deb /tmp/debs-centreon/ @@ -55,7 +56,7 @@ sed -i 's#severity=error#severity=debug#' /etc/default/gorgoned sed -i "5s/.*/ id: 1/" /etc/centreon-gorgone/config.d/40-gorgoned.yaml sed -i 's#enable: true#enable: false#' /etc/centreon-gorgone/config.d/50-centreon-audit.yaml -wget -P /tmp/ https://github.com/mydumper/mydumper/releases/download/v0.15.2-7/mydumper_0.15.2-7.bookworm_amd64.deb +wget -P /tmp/ https://github.com/mydumper/mydumper/releases/download/v${MYDUMPER_VERSION}/mydumper_${MYDUMPER_VERSION}.bookworm_amd64.deb apt-get install -y /tmp/mydumper_*.deb zstd libpcre3 rm -f /tmp/mydumper_* mkdir -p /usr/local/src/sql/databases diff --git a/.github/docker/centreon-web/bookworm/slim-configuration/exec.txt b/.github/docker/centreon-web/bookworm/slim-configuration/exec.txt index 61777c6f37..7f926e6073 100644 --- a/.github/docker/centreon-web/bookworm/slim-configuration/exec.txt +++ b/.github/docker/centreon-web/bookworm/slim-configuration/exec.txt @@ -22,4 +22,5 @@ systemctl stop cbd systemctl stop php8.1-fpm systemctl stop apache2 -rm -f /tmp/gorgone/*.ipc /var/log/centreon*/*.log /var/lib/centreon-gorgone/history.sdb +rm -f /tmp/gorgone/*.ipc /var/lib/centreon-gorgone/history.sdb +bash -c "find /var/log/centreon{,-engine,-broker,-gorgone} /var/lib/centreon-{engine,broker} /var/lib/centreon/{centcore,metrics,status} -type f -delete" diff --git a/.github/docker/centreon-web/bullseye/Dockerfile b/.github/docker/centreon-web/bullseye/Dockerfile index 012ef92ab9..6b8bc89c5e 100644 --- a/.github/docker/centreon-web/bullseye/Dockerfile +++ b/.github/docker/centreon-web/bullseye/Dockerfile @@ -4,8 +4,9 @@ ARG VERSION FROM ${REGISTRY_URL}/centreon-web-dependencies-bullseye:${VERSION} ARG VERSION +ARG MYDUMPER_VERSION -ENV DEBIAN_FRONTEND noninteractive +ENV DEBIAN_FRONTEND=noninteractive COPY *.deb /tmp/debs-centreon/ @@ -55,7 +56,7 @@ sed -i 's#severity=error#severity=debug#' /etc/default/gorgoned sed -i "5s/.*/ id: 1/" /etc/centreon-gorgone/config.d/40-gorgoned.yaml sed -i 's#enable: true#enable: false#' /etc/centreon-gorgone/config.d/50-centreon-audit.yaml -wget -P /tmp/ https://github.com/mydumper/mydumper/releases/download/v0.15.2-7/mydumper_0.15.2-7.bullseye_amd64.deb +wget -P /tmp/ https://github.com/mydumper/mydumper/releases/download/v${MYDUMPER_VERSION}/mydumper_${MYDUMPER_VERSION}.bullseye_amd64.deb apt-get install -y /tmp/mydumper_*.deb zstd rm -f /tmp/mydumper_* mkdir -p /usr/local/src/sql/databases diff --git a/.github/docker/centreon-web/bullseye/Dockerfile.dependencies b/.github/docker/centreon-web/bullseye/Dockerfile.dependencies index d241fc3bf8..5a0a4814ca 100644 --- a/.github/docker/centreon-web/bullseye/Dockerfile.dependencies +++ b/.github/docker/centreon-web/bullseye/Dockerfile.dependencies @@ -99,7 +99,7 @@ apt-get install -y \ ################################# curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup \ - | sudo bash -s -- --os-type=debian --os-version=11 --mariadb-server-version="mariadb-10.5" + | sudo bash -s -- --os-type=debian --os-version=11 --mariadb-server-version="mariadb-10.11" apt-get update diff --git a/.github/docker/centreon-web/bullseye/slim-configuration/exec.txt b/.github/docker/centreon-web/bullseye/slim-configuration/exec.txt index 61777c6f37..7f926e6073 100644 --- a/.github/docker/centreon-web/bullseye/slim-configuration/exec.txt +++ b/.github/docker/centreon-web/bullseye/slim-configuration/exec.txt @@ -22,4 +22,5 @@ systemctl stop cbd systemctl stop php8.1-fpm systemctl stop apache2 -rm -f /tmp/gorgone/*.ipc /var/log/centreon*/*.log /var/lib/centreon-gorgone/history.sdb +rm -f /tmp/gorgone/*.ipc /var/lib/centreon-gorgone/history.sdb +bash -c "find /var/log/centreon{,-engine,-broker,-gorgone} /var/lib/centreon-{engine,broker} /var/lib/centreon/{centcore,metrics,status} -type f -delete" diff --git a/.github/docker/centreon-web/jammy/Dockerfile b/.github/docker/centreon-web/jammy/Dockerfile index 8d07678b49..e7516e3bbf 100644 --- a/.github/docker/centreon-web/jammy/Dockerfile +++ b/.github/docker/centreon-web/jammy/Dockerfile @@ -4,8 +4,9 @@ ARG VERSION FROM ${REGISTRY_URL}/centreon-web-dependencies-jammy:${VERSION} ARG VERSION +ARG MYDUMPER_VERSION -ENV DEBIAN_FRONTEND noninteractive +ENV DEBIAN_FRONTEND=noninteractive COPY *.deb /tmp/debs-centreon/ @@ -55,7 +56,7 @@ sed -i 's#severity=error#severity=debug#' /etc/default/gorgoned sed -i "5s/.*/ id: 1/" /etc/centreon-gorgone/config.d/40-gorgoned.yaml sed -i 's#enable: true#enable: false#' /etc/centreon-gorgone/config.d/50-centreon-audit.yaml -wget -P /tmp/ https://github.com/mydumper/mydumper/releases/download/v0.15.2-7/mydumper_0.15.2-7.jammy_amd64.deb +wget -P /tmp/ https://github.com/mydumper/mydumper/releases/download/v${MYDUMPER_VERSION}/mydumper_${MYDUMPER_VERSION}.jammy_amd64.deb apt-get install -y /tmp/mydumper_*.deb zstd rm -f /tmp/mydumper_* mkdir -p /usr/local/src/sql/databases diff --git a/.github/docker/centreon-web/jammy/slim-configuration/exec.txt b/.github/docker/centreon-web/jammy/slim-configuration/exec.txt index 61777c6f37..7f926e6073 100644 --- a/.github/docker/centreon-web/jammy/slim-configuration/exec.txt +++ b/.github/docker/centreon-web/jammy/slim-configuration/exec.txt @@ -22,4 +22,5 @@ systemctl stop cbd systemctl stop php8.1-fpm systemctl stop apache2 -rm -f /tmp/gorgone/*.ipc /var/log/centreon*/*.log /var/lib/centreon-gorgone/history.sdb +rm -f /tmp/gorgone/*.ipc /var/lib/centreon-gorgone/history.sdb +bash -c "find /var/log/centreon{,-engine,-broker,-gorgone} /var/lib/centreon-{engine,broker} /var/lib/centreon/{centcore,metrics,status} -type f -delete" diff --git a/.github/docker/docker-compose.yml b/.github/docker/docker-compose.yml index ee1a242b6f..0f8051f688 100644 --- a/.github/docker/docker-compose.yml +++ b/.github/docker/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3" services: web: env_file: @@ -12,7 +11,7 @@ services: healthcheck: test: bash -c "[ -f /tmp/docker.ready ]" && curl --fail http://localhost/centreon/api/latest/platform/versions || exit 1 interval: 1s - retries: 60 + retries: 120 timeout: 5s db: @@ -23,8 +22,8 @@ services: deploy: resources: limits: - cpus: '1' - memory: 300M + cpus: '2' + memory: 400M reservations: cpus: '0.25' memory: 100M diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml index 7b9e5d9b21..d4d1edf266 100644 --- a/.github/workflows/actionlint.yml +++ b/.github/workflows/actionlint.yml @@ -6,7 +6,7 @@ concurrency: on: workflow_dispatch: - pull_request: + pull_request_target: branches: - develop - dev-[2-9][0-9].[0-9][0-9].x @@ -20,35 +20,43 @@ on: jobs: action-lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download actionlint id: get_actionlint - run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) + run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/v1.7.1/scripts/download-actionlint.bash) shell: bash - name: Check workflow files + env: + SHELLCHECK_OPTS: "--severity=error" run: | ${{ steps.get_actionlint.outputs.executable }} \ - -ignore 'label "common" is unknown' \ - -ignore 'label "veracode" is unknown' \ - -ignore '"github.head_ref" is potentially untrusted' \ - -shellcheck= \ - -pyflakes= \ - -color + -ignore 'label "ubuntu-24.04" is unknown' \ + -ignore 'label "common" is unknown' \ + -ignore 'label "veracode" is unknown' \ + -ignore 'label "infra" is unknown' \ + -ignore 'property "author_association" is not defined in object type*' \ + -ignore '"github.head_ref" is potentially untrusted' \ + -pyflakes= \ + -color shell: bash yaml-lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 + with: + python-version: '3.12' - name: Install Yaml - run: pip install yamllint==1.32.0 + run: pip install yamllint==1.35.1 - name: Add Yaml Lint Rules run: | diff --git a/.github/workflows/awie.yml b/.github/workflows/awie.yml deleted file mode 100644 index 8ef948d760..0000000000 --- a/.github/workflows/awie.yml +++ /dev/null @@ -1,227 +0,0 @@ -name: awie - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - "centreon-awie/**" - - "!centreon-awie/veracode.json" - - "!centreon-awie/.veracode-exclusions" - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - - master - - "[2-9][0-9].[0-9][0-9].x" - paths: - - "centreon-awie/**" - - "!centreon-awie/veracode.json" - - "!centreon-awie/.veracode-exclusions" - -env: - module: awie - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon-awie/www/modules/centreon-awie/conf.php - - veracode-analysis: - needs: [get-version] - uses: ./.github/workflows/veracode-analysis.yml - with: - module_directory: centreon-awie - module_name: centreon-awie - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - secrets: - veracode_api_id: ${{ secrets.VERACODE_API_ID }} - veracode_api_key: ${{ secrets.VERACODE_API_KEY }} - veracode_srcclr_token: ${{ secrets.VERACODE_SRCCLR_TOKEN }} - jira_base_url: ${{ secrets.JIRA_BASE_URL }} - jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} - jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} - - backend-lint: - runs-on: ubuntu-22.04 - needs: [get-version] - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Setup PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 - with: - php-version: 8.1 - coverage: none - env: - runner: ubuntu-22.04 - - - name: Install Dependencies - run: composer install --optimize-autoloader - working-directory: centreon-awie - shell: bash - - - name: Run of phpstan on /www at level 6 - run: vendor/bin/phpstan analyse --no-progress --level=6 --configuration=phpstan.neon - working-directory: centreon-awie - - package: - needs: [get-version, backend-lint] - if: ${{ needs.get-version.outputs.stability != 'stable' }} - - strategy: - fail-fast: false - matrix: - distrib: [el8, el9, bullseye, bookworm] - include: - - package_extension: rpm - image: packaging-nfpm-alma8 - distrib: el8 - - package_extension: rpm - image: packaging-nfpm-alma9 - distrib: el9 - - package_extension: deb - image: packaging-nfpm-bullseye - distrib: bullseye - - package_extension: deb - image: packaging-nfpm-bookworm - distrib: bookworm - - runs-on: ubuntu-22.04 - - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} - credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - name: package ${{ matrix.distrib }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Package - uses: ./.github/actions/package-nfpm - with: - nfpm_file_pattern: "centreon-awie/packaging/*.yaml" - distrib: ${{ matrix.distrib }} - package_extension: ${{ matrix.package_extension }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - release: ${{ needs.get-version.outputs.release }} - arch: all - commit_hash: ${{ github.sha }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} - rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} - rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} - rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} - stability: ${{ needs.get-version.outputs.stability }} - - deliver-sources: - runs-on: [self-hosted, common] - needs: [get-version, package] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Deliver sources - uses: ./.github/actions/release-sources - with: - bucket_directory: centreon-awie - module_directory: centreon-awie - module_name: centreon-awie - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - token_download_centreon_com: ${{ secrets.TOKEN_DOWNLOAD_CENTREON_COM }} - - delivery-rpm: - needs: [get-version, package] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} - runs-on: [self-hosted, common] - environment: ${{ needs.get-version.outputs.environment }} - - strategy: - matrix: - distrib: [el8, el9] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/rpm-delivery - with: - module_name: awie - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - delivery-deb: - needs: [get-version, package] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} - runs-on: [self-hosted, common] - environment: ${{ needs.get-version.outputs.environment }} - - strategy: - matrix: - distrib: [bullseye, bookworm] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/deb-delivery - with: - module_name: awie - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - promote: - needs: [get-version] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - runs-on: [self-hosted, common] - strategy: - matrix: - distrib: [el8, el9, bullseye, bookworm] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Promote ${{ matrix.distrib }} to stable - uses: ./.github/actions/promote-to-stable - with: - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - module: awie - distrib: ${{ matrix.distrib }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - github_ref_name: ${{ github.ref_name }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} diff --git a/.github/workflows/behat-test.yml b/.github/workflows/behat-test.yml deleted file mode 100644 index abef4a578d..0000000000 --- a/.github/workflows/behat-test.yml +++ /dev/null @@ -1,193 +0,0 @@ -on: - workflow_call: - inputs: - name: - required: true - type: string - module_name: - required: true - type: string - database_image: - required: true - type: string - image_name: - required: true - type: string - os: - required: true - type: string - features_path: - required: true - type: string - config_file: - required: false - type: string - default: behat.yml - secrets: - registry_username: - required: true - registry_password: - required: true - composer_token: - required: true - -jobs: - behat-test-list: - runs-on: ubuntu-22.04 - outputs: - features: ${{ steps.list-features.outputs.features }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: List features - id: list-features - run: | - cd ${{ inputs.module_name }} - echo "features=$(find ${{ inputs.features_path }} -type f -name "*.feature" -printf "%P\n" | sort | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT - - behat-test-run: - needs: [behat-test-list] - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - feature: ${{ fromJson(needs.behat-test-list.outputs.features) }} - name: ${{ matrix.feature }} - - env: - IMAGE_TAG: ${{ github.head_ref || github.ref_name }} - SLIM_IMAGE_NAME: ${{ inputs.image_name }}-slim-${{ inputs.os }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.registry_username }} - password: ${{ secrets.registry_password }} - - - name: Setup PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 - with: - php-version: 8.1 - coverage: none - env: - COMPOSER_TOKEN: ${{ secrets.composer_token }} - runner: ubuntu-22.04 - - - name: Setup docker compose - run: | - sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - sudo chmod +x /usr/local/bin/docker-compose - - - if: ${{ contains(matrix.feature, 'RestApi') }} - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - with: - node-version: 20 - - - name: Install dependencies - run: composer install --optimize-autoloader - working-directory: ${{ inputs.module_name }} - - - name: Restore standard slim image from cache - id: cache-docker-slim - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - continue-on-error: true - timeout-minutes: 6 - with: - path: /tmp/cache/docker-image - key: docker-image-${{ env.SLIM_IMAGE_NAME }}-${{ env.IMAGE_TAG }} - env: - SEGMENT_DOWNLOAD_TIMEOUT_MINS: 5 - - - name: Load standard slim image - if: ${{ steps.cache-docker-slim.outputs.cache-hit == 'true' }} - run: | - docker load --input /tmp/cache/docker-image/${{ env.SLIM_IMAGE_NAME }}.tar - docker tag ${{ env.SLIM_IMAGE_NAME }}:${{ env.IMAGE_TAG }} ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.SLIM_IMAGE_NAME }}:${{ env.IMAGE_TAG }} - shell: bash - - - name: Behat acceptance testing - env: - PANTHER_CHROME_BINARY: /usr/bin/google-chrome - WEB_IMAGE: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.SLIM_IMAGE_NAME }}:${{ env.IMAGE_TAG }} - MYSQL_IMAGE: ${{ inputs.database_image }} - run: | - rm -rf acceptance-logs && mkdir acceptance-logs - rm -rf xunit-reports && mkdir xunit-reports - BASE_DIRECTORY=$(pwd) - cd ${{ inputs.module_name }} - ./vendor/bin/behat --config="${{ inputs.config_file }}" --colors --format=pretty --out=std --format=junit --out="$BASE_DIRECTORY/xunit-reports" "${{ inputs.features_path }}/${{ matrix.feature }}" - - - name: Clean empty reports - if: ${{ !cancelled() }} - run: find ./xunit-reports/* -type f | xargs grep -l -E "" | xargs -r rm - - - if: failure() - name: Display logs - run: find ./acceptance-logs -type f | grep '.txt' | xargs -r more | cat - shell: bash - - - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - if: failure() - name: Upload acceptance test logs - with: - name: ${{ inputs.name }}-${{ inputs.os }}-test-logs-${{ matrix.feature }} - path: acceptance-logs - retention-days: 1 - - - name: Upload Test Results - if: failure() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: ${{ inputs.name }}-${{ inputs.os }}-test-reports-${{ matrix.feature }} - path: xunit-reports - retention-days: 1 - - behat-test-report: - needs: [behat-test-run] - if: failure() - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Download Artifacts - uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 - with: - pattern: ${{ inputs.name }}-${{ inputs.os }}-test-reports-* - path: ${{ inputs.name }}-xunit-reports - merge-multiple: true - - - uses: ./.github/actions/publish-report - with: - check_name: ${{ inputs.name }}-tests-report - path: '${{ inputs.name }}-xunit-reports/**/*.xml' - - regroup-artifacts: - needs: [behat-test-run, behat-test-report] - if: always() - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - type_of_report: [test-logs, test-reports] - steps: - - name: Merge Artifacts - uses: actions/upload-artifact/merge@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 - if: ${{ contains(needs.behat-test-run.result, 'failure') }} - with: - name: ${{ inputs.name }}-${{ inputs.os }}-${{ matrix.type_of_report }} - pattern: ${{ inputs.name }}-${{ inputs.os }}-${{ matrix.type_of_report }}-* - retention-days: 1 - - - name: Delete merged artifacts - uses: geekyeggo/delete-artifact@24928e75e6e6590170563b8ddae9fac674508aa1 # v5.0.0 - with: - name: ${{ inputs.name }}-${{ inputs.os }}-${{ matrix.type_of_report }}-* - failOnError: false diff --git a/.github/workflows/check-status.yml b/.github/workflows/check-status.yml index 65b1caa536..da1b20ef31 100644 --- a/.github/workflows/check-status.yml +++ b/.github/workflows/check-status.yml @@ -16,59 +16,93 @@ on: jobs: check-status: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" - name: Check workflow statuses and display token usage + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - display_token_usage () { - echo "current token usage :" - curl -s -H "Accept: application/vnd.github+json" -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit | jq .rate - echo "" - } - - display_token_usage - sleep 30s - - ITERATIONS=1 - while [[ $ITERATIONS -le 60 ]]; do - CHECK_SUITES=$(gh api -H "Accept: application/vnd.github+json" /repos/centreon/centreon/commits/${{ github.event.pull_request.head.sha }}/check-suites | jq '. | .check_suites[] | select(.app.slug == "github-actions")' | jq -r '.conclusion // "pending"') || true - - if [ $(echo $CHECK_SUITES | grep -o -i 'pending' | wc -l) -eq 0 ]; then - echo "Cannot get pull request check status" - exit 1 - fi - - if [ $(echo $CHECK_SUITES | wc -w) -eq 1 ]; then - echo "this job is the only triggered one" - exit 0 - fi - - if [ $(echo $CHECK_SUITES | grep -o -i 'failure' | wc -l) -gt 0 ]; then - echo "some jobs have failed" - exit 1 - fi - - # only remaining pending job should be check-status itself - if [ $(echo $CHECK_SUITES | grep -o -i 'pending' | wc -l) -eq 1 ]; then - echo "all jobs have passed" - exit 0 - fi - - if [ $ITERATIONS -lt 60 ]; then - echo "some jobs are still in progress, next try in 60 seconds... (tries: $ITERATIONS/60)" - sleep 30s - display_token_usage - sleep 30s - display_token_usage - fi - - ITERATIONS=$((ITERATIONS+1)) - done - - echo "Timeout : some jobs are still in progress" - exit 1 - shell: bash + echo "current rest api rate usage:" + curl -s -H "Accept: application/vnd.github+json" -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit | jq .rate + echo "" + echo "" + echo "current graphql rate usage:" + curl -s -H "Accept: application/vnd.github+json" -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit | jq .resources.graphql + echo "" + echo "" + + - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 env: - GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.number }} + with: + script: | + await exec.exec("sleep 20s"); + + for (let i = 0; i < 120; i++) { + const failure = []; + const cancelled = []; + const pending = []; + + const result = await github.rest.checks.listSuitesForRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: "${{ github.event.pull_request.head.sha }}" + }); + result.data.check_suites.forEach(({ app: { slug }, conclusion, id}) => { + if (slug === 'github-actions') { + if (conclusion === 'failure' || conclusion === 'cancelled') { + failure.push(id); + } else if (conclusion === null) { + pending.push(id); + } + console.log(`check suite ${id} => ${conclusion === null ? 'pending' : conclusion}`); + } + }); + + if (pending.length === 0) { + core.setFailed("Cannot get pull request check status"); + return; + } + + if (failure.length > 0) { + let failureMessage = ''; + const failedCheckRuns = []; + for await (const suite_id of failure) { + const resultCheckRuns = await github.rest.checks.listForSuite({ + owner: context.repo.owner, + repo: context.repo.repo, + check_suite_id: suite_id + }); + + resultCheckRuns.data.check_runs.forEach(({ conclusion, name, html_url }) => { + if (conclusion === 'failure' || conclusion === 'cancelled') { + failedCheckRuns.push(`${name} (${conclusion})`); + } + }); + } + + core.summary.addRaw(`${failedCheckRuns.length} job(s) failed:`, true) + core.summary.addList(failedCheckRuns); + core.summary.write() + + core.setFailed(`${failure.length} workflow(s) failed`); + return; + } + + if (pending.length === 1) { + core.info("All workflows are ok"); + return; + } + + core.info(`${pending.length} workflows in progress`); + + await exec.exec("sleep 30s"); + } + + core.setFailed("Timeout: some jobs are still in progress"); diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml deleted file mode 100644 index b454bca3d5..0000000000 --- a/.github/workflows/chromatic.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: chromatic - -on: - workflow_dispatch: - push: - branches: - - 'develop' - - 'MON-**' - paths: - - "centreon/packages/ui/**" - -env: - directory: "centreon/packages/ui" - -jobs: - chromatic: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - uses: ./.github/actions/chromatic - with: - frontend_directory: ${{ env.directory }} - dependencies_lock_file: centreon/pnpm-lock.yaml - pat: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - project_token: ${{ secrets.CHROMATIC_TOKEN }} diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml deleted file mode 100644 index 1917bb2c02..0000000000 --- a/.github/workflows/clean-cache.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: clean-cache - -on: - pull_request: - types: - - closed - -jobs: - clean-cache: - runs-on: ubuntu-22.04 - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Install github cli - run: | - curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg - sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null - sudo apt update - sudo apt install -y gh - shell: bash - - - name: Clean cache - run: | - gh extension install actions/gh-actions-cache - - REPO=${{ github.repository }} - BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge" - - echo "Fetching list of cache key" - cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) - - ## Setting this to not fail the workflow while deleting cache keys. - set +e - echo "Deleting caches..." - for cacheKey in $cacheKeysForPR - do - gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm - done - echo "Done" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/create-repo-yum.yml b/.github/workflows/create-repo-yum.yml deleted file mode 100644 index 9f1b0bfe6e..0000000000 --- a/.github/workflows/create-repo-yum.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: create-repo-yum - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - paths: - - ".github/workflows/create-repo-yum.yml" - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - create-repo-file-and-deliver: - needs: [get-version] - runs-on: ubuntu-22.04 - strategy: - matrix: - distrib: [el8, el9] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Install jfrog cli - uses: jfrog/setup-jfrog-cli@d82fe26823e1f25529250895d5673f65b02af085 # v4.0.1 - env: - JF_URL: https://centreon.jfrog.io - JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - - - name: Create repository structure - run: | - for STABILITY in "unstable" "testing" "stable"; do - - for ARCH in "noarch" "x86_64"; do - curl -H "Authorization: Bearer ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }}" -X PUT "https://centreon.jfrog.io/artifactory/rpm-standard/${{ needs.get-version.outputs.major_version }}/${{ matrix.distrib }}/$STABILITY/$ARCH/" - curl -H "Authorization: Bearer ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }}" -X POST "https://centreon.jfrog.io/artifactory/api/yum/rpm-standard?path=/${{ needs.get-version.outputs.major_version }}/${{ matrix.distrib }}/$STABILITY/$ARCH&async=1" - - curl -H "Authorization: Bearer ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }}" -X PUT "https://centreon.jfrog.io/artifactory/rpm-plugins/${{ matrix.distrib }}/$STABILITY/$ARCH/" - curl -H "Authorization: Bearer ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }}" -X POST "https://centreon.jfrog.io/artifactory/api/yum/rpm-plugins?path=/${{ matrix.distrib }}/$STABILITY/$ARCH&async=1" - done - - done - shell: bash - - - name: Create repo file - run: | - sed \ - -e "s#@MAJOR_VERSION@#${{ needs.get-version.outputs.major_version }}#g" \ - -e "s#@DISTRIB@#${{ matrix.distrib }}#g" \ - ./.github/scripts/repo/centreon.repo.template > ./centreon-${{ needs.get-version.outputs.major_version }}.repo - shell: bash - - - name: Upload repo file in jfrog - run: | - jf rt upload "centreon-${{ needs.get-version.outputs.major_version }}.repo" "rpm-standard/${{ needs.get-version.outputs.major_version }}/${{ matrix.distrib }}/" - shell: bash diff --git a/.github/workflows/create-xray-test-plan-and-test-execution.yml b/.github/workflows/create-xray-test-plan-and-test-execution.yml deleted file mode 100644 index e9f0f93409..0000000000 --- a/.github/workflows/create-xray-test-plan-and-test-execution.yml +++ /dev/null @@ -1,294 +0,0 @@ -name: create-xray-test-plan-and-test-execution - -on: - workflow_call: - inputs: - major_version: - required: true - type: string - minor_version: - required: true - type: string - os: - required: true - type: string - outputs: - test_plan_key_alma8: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_plan_key_alma8 }} - test_plan_id_alma8: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_plan_id_alma8 }} - test_execution_key_alma8: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_execution_key_alma8 }} - test_execution_id_alma8: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_execution_id_alma8 }} - test_plan_key_alma9: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_plan_key_alma9 }} - test_plan_id_alma9: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_plan_id_alma9 }} - test_execution_key_alma9: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_execution_key_alma9 }} - test_execution_id_alma9: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_execution_id_alma9 }} - test_plan_key_bullseye: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_plan_key_bullseye }} - test_plan_id_bullseye: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_plan_id_bullseye }} - test_execution_key_bullseye: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_execution_key_bullseye }} - test_execution_id_bullseye: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_execution_id_bullseye }} - test_plan_key_bookworm: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_plan_key_bookworm }} - test_plan_id_bookworm: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_plan_id_bookworm }} - test_execution_key_bookworm: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_execution_key_bookworm }} - test_execution_id_bookworm: - value: ${{ jobs.create-xray-test-plan-and-test-execution.outputs.test_execution_id_bookworm }} - secrets: - xray_jira_user_email: - required: true - xray_jira_token: - required: true - xray_client_id: - required: true - xray_client_secret: - required: true - -# NIGHTLY (e.g., NIGHTLY OSS 23.10) -jobs: - create-xray-test-plan-and-test-execution: - runs-on: ubuntu-22.04 - outputs: - test_plan_key_alma8: ${{ steps.get_test_plan_key.outputs.test_plan_key_alma8 }} - test_plan_id_alma8: ${{ steps.get_test_plan_id.outputs.test_plan_id_alma8 }} - test_execution_key_alma8: ${{ steps.get_test_execution_key.outputs.test_execution_key_alma8 }} - test_execution_id_alma8: ${{ steps.get_test_execution_id.outputs.test_execution_id_alma8 }} - test_plan_key_alma9: ${{ steps.get_test_plan_key.outputs.test_plan_key_alma9 }} - test_plan_id_alma9: ${{ steps.get_test_plan_id.outputs.test_plan_id_alma9 }} - test_execution_key_alma9: ${{ steps.get_test_execution_key.outputs.test_execution_key_alma9 }} - test_execution_id_alma9: ${{ steps.get_test_execution_id.outputs.test_execution_id_alma9 }} - test_plan_key_bullseye: ${{ steps.get_test_plan_key.outputs.test_plan_key_bullseye }} - test_plan_id_bullseye: ${{ steps.get_test_plan_id.outputs.test_plan_id_bullseye }} - test_execution_key_bullseye: ${{ steps.get_test_execution_key.outputs.test_execution_key_bullseye }} - test_execution_id_bullseye: ${{ steps.get_test_execution_id.outputs.test_execution_id_bullseye }} - test_plan_key_bookworm: ${{ steps.get_test_plan_key.outputs.test_plan_key_bookworm }} - test_plan_id_bookworm: ${{ steps.get_test_plan_id.outputs.test_plan_id_bookworm }} - test_execution_key_bookworm: ${{ steps.get_test_execution_key.outputs.test_execution_key_bookworm }} - test_execution_id_bookworm: ${{ steps.get_test_execution_id.outputs.test_execution_id_bookworm }} - - steps: - - name: Generate Xray Token - id: generate_xray_token - run: | - token_response=$(curl -H "Content-Type: application/json" -X POST --data "{\"client_id\": \"${{ secrets.xray_client_id }}\", \"client_secret\": \"${{ secrets.xray_client_secret }}\"}" "https://xray.cloud.getxray.app/api/v1/authenticate") - xray_token=$(echo "$token_response" | sed -n 's/.*"\(.*\)".*/\1/p') - echo "xray_token=$xray_token" >> $GITHUB_OUTPUT - shell: bash - - - name: Create or Get the TestPlanKey - id: get_test_plan_key - run: | - # Initialize start value - start=0 - - # Loop to fetch all test plans - while true; do - # Execute the GraphQL query with the current start value - graphql_query='{ - "query":"query GetTestPlans($jql: String, $limit: Int!, $start: Int) { getTestPlans(jql: $jql, limit: $limit, start: $start) { total results { issueId jira(fields: [\"summary\", \"key\"]) } } }", - "variables":{"jql": "project = MON","limit": 100, "start": '"$start"'}}' - - response=$(curl -sS -H "Content-Type: application/json" -X POST -H "Authorization: Bearer ${{ steps.generate_xray_token.outputs.xray_token }}" --data "$graphql_query" "https://xray.cloud.getxray.app/api/v2/graphql") - - # Parse the response and extract test plans - test_plans=$(echo "$response" | jq -c '.data.getTestPlans.results[].jira') - - # Check if test_plans is empty - if [ -z "$test_plans" ]; then - echo "No more test plans found. Exiting loop." - break - fi - - echo "These are the existing TPs: $test_plans" - - # Determine the summary's prefix - summary_prefix='' - if [[ ${{ github.event_name }} == 'schedule' ]]; then - summary_prefix="NIGHTLY" - else - echo "The github_ref_name is: $GITHUB_REF_NAME" - case "$GITHUB_REF_NAME" in - hotfix*) - summary_prefix="HOTFIX" - ;; - release*) - summary_prefix="RLZ" - ;; - esac - fi - - input_summary="$summary_prefix OSS ${{ inputs.major_version }}" - echo "The summary to search is: $input_summary" - - # Extract the key of the existent test plan - while read row; do - summary=$(echo "$row" | jq -r '.summary') - if [[ "$summary" == "$input_summary" ]]; then - test_plan_key=$(echo "$row" | jq -r '.key') - echo "The test_plan_key is $test_plan_key and the summary is $summary" - break - fi - done <<< "$test_plans" - - echo "The test plan key for now is: $test_plan_key" - - # If no matching test plan was found, create one - if [[ -z "$test_plan_key" ]]; then - echo "TestPlan doesn't exist yet" - - # Create the test plan using a GraphQL mutation - create_test_plan_mutation="{ - \"query\": \"mutation CreateTestPlan(\$testIssueIds: [String], \$jira: JSON!) { createTestPlan(testIssueIds: \$testIssueIds, jira: \$jira) { testPlan { issueId jira(fields: [\\\"key\\\"]) }warnings } }\", - \"variables\": { - \"testIssueIds\": [], - \"jira\": { - \"fields\": { - \"summary\": \"$input_summary\", - \"project\": { \"key\": \"MON\" } - } - } - } - }" - create_result=$(curl -sS -H "Content-Type: application/json" -X POST -H "Authorization: Bearer ${{ steps.generate_xray_token.outputs.xray_token }}" -d "$create_test_plan_mutation" "https://xray.cloud.getxray.app/api/v2/graphql") - echo "API response: $create_result " - - # Extract the key of the created test plan - test_plan_key=$(echo "$create_result" | jq -r '.data.createTestPlan.testPlan.jira.key') - echo "New TP created with key: $test_plan_key" - fi - - # Update start value for the next iteration - start=$((start + 100)) - done - - # Set the testPlanKey as an output - echo "test_plan_key_${{ inputs.os }}=$test_plan_key" >> $GITHUB_OUTPUT - - shell: bash - - - name: Get TestPlanID - id: get_test_plan_id - run: | - test_plan_key=$(echo '${{ toJSON(steps.get_test_plan_key.outputs) }}' | jq -r '.test_plan_key_'${{ inputs.os }}) - echo "getting the testPlanId for the testPlanKey: $test_plan_key" - jira_url="https://centreon.atlassian.net/rest/api/2/issue/$test_plan_key" - - test_plan_id=$(curl -u "${{ secrets.xray_jira_user_email }}:${{ secrets.xray_jira_token }}" -X GET -s "$jira_url" | jq -r '.id') - echo "this is the testPlan ID : $test_plan_id" - echo "test_plan_id_${{ inputs.os }}=$test_plan_id" >> $GITHUB_OUTPUT - shell: bash - - - name: Create TestExecution and Get the TestExecutionID - id: get_test_execution_id - run: | - # Determine the summary's prefix - summary_prefix='' - if [[ ${{ github.event_name }} == 'schedule' ]]; then - summary_prefix="NIGHTLY" - else - echo "The github_ref_name is: $GITHUB_REF_NAME" - case "$GITHUB_REF_NAME" in - hotfix*) - summary_prefix="HOTFIX" - ;; - release*) - summary_prefix="RLZ" - ;; - esac - fi - - current_date=$(date +'%d/%m/%Y') - - workflow_run_url="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" - - input_summary="$summary_prefix WEB ${{ inputs.major_version }}.${{ inputs.minor_version }} $current_date" - echo "The summary of the TE is: $input_summary" - - linux_distribution='' - case "${{ inputs.os }}" in - alma8) - linux_distribution="ALMA8" - mariadb_version="MARIADB_10_5" - ;; - alma9) - linux_distribution="ALMA9" - mariadb_version="MARIADB_10_5" - ;; - bullseye) - linux_distribution="DEBIAN11" - mariadb_version="MARIADB_10_5" - ;; - bookworm) - linux_distribution="DEBIAN12" - mariadb_version="MARIADB_10_11" - ;; - esac - - xray_graphql_createTestExecution="{ - \"query\": \"mutation CreateTestExecution(\$testEnvironments: [String], \$jira: JSON!) { createTestExecution(testEnvironments: \$testEnvironments, jira: \$jira) { testExecution { issueId jira(fields: [\\\"key\\\"]) } warnings createdTestEnvironments } }\", - \"variables\": { - \"testEnvironments\": [\"$linux_distribution\",\"$mariadb_version\",\"CHROME\"], - \"jira\": { - \"fields\": { - \"summary\": \"$input_summary\", - \"description\": \"$workflow_run_url\", - \"project\": { \"key\": \"MON\" }, - \"components\": [{\"name\": \"centreon-web\"}], - \"priority\":{\"name\":\"Low\"} - } - } - } - }" - - echo "this is the graphql mutation : $xray_graphql_createTestExecution" - - response=$(curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{ steps.generate_xray_token.outputs.xray_token }}" --data "$xray_graphql_createTestExecution" "https://xray.cloud.getxray.app/api/v2/graphql") - - echo -e "Response from Create Test Execution:\n$response" - - # Extract the ID of the created TE - test_execution_id=$(echo "$response" | jq -r '.data.createTestExecution.testExecution.issueId') - echo "test_execution_id_${{ inputs.os }}=$test_execution_id" >> $GITHUB_OUTPUT - - echo "TestExecution created with ID: $test_execution_id" - shell: bash - - - name: Get TestExecutionKey - id: get_test_execution_key - run: | - test_execution_id=$(echo '${{ toJSON(steps.get_test_execution_id.outputs) }}' | jq -r '.test_execution_id_'${{ inputs.os }}) - jira_url="https://centreon.atlassian.net/rest/api/2/issue/$test_execution_id" - - test_execution_key=$(curl -u "${{ secrets.xray_jira_user_email }}:${{ secrets.xray_jira_token }}" -X GET -s "$jira_url" | jq -r '.key') - echo "this is the TestExecutionKey: $test_execution_key" - echo "test_execution_key_${{ inputs.os }}=$test_execution_key" >> $GITHUB_OUTPUT - shell: bash - - - name: Update the status of the TestExecution Issue - run: | - test_execution_key=$(echo '${{ toJSON(steps.get_test_execution_key.outputs) }}' | jq -r '.test_execution_key_'${{ inputs.os }}) - curl -D- -u "${{ secrets.xray_jira_user_email }}:${{ secrets.xray_jira_token }}" -X POST --data '{"transition":{"id":"5"}}' -H "Content-Type: application/json" https://centreon.atlassian.net/rest/api/2/issue/$test_execution_key/transitions?expand=transitions.fields - - - name: Add the TestExecution Issue to the TestPlan - run: | - test_plan_id=$(echo '${{ toJSON(steps.get_test_plan_id.outputs) }}' | jq -r '.test_plan_id_'${{ inputs.os }}) - test_execution_id=$(echo '${{ toJSON(steps.get_test_execution_id.outputs) }}' | jq -r '.test_execution_id_'${{ inputs.os }}) - xray_graphql_mutation="{ - \"query\": \"mutation AddTestExecution(\$issueId: String!, \$testExecIssueIds: [String]!) { addTestExecutionsToTestPlan(issueId: \$issueId, testExecIssueIds: \$testExecIssueIds) { addedTestExecutions warning } }\", - \"variables\": { - \"issueId\": \"$test_plan_id\", - \"testExecIssueIds\": [\"$test_execution_id\"] - } - }" - curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{ steps.generate_xray_token.outputs.xray_token }}" --data "${xray_graphql_mutation}" "https://xray.cloud.getxray.app/api/v2/graphql" diff --git a/.github/workflows/cypress-component-parallelization.yml b/.github/workflows/cypress-component-parallelization.yml deleted file mode 100644 index f00fd3286c..0000000000 --- a/.github/workflows/cypress-component-parallelization.yml +++ /dev/null @@ -1,191 +0,0 @@ -on: - workflow_call: - inputs: - name: - required: true - type: string - module_name: - required: true - type: string - specs_path: - required: true - type: string - dependencies_lock_file: - required: true - type: string - description: 'The frontend dependencies lock file path' - -jobs: - cypress-component-test-list: - runs-on: ubuntu-22.04 - outputs: - specs: ${{ steps.list-specs.outputs.specs }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: List of specs - id: list-specs - run: | - cd ${{ inputs.module_name }} - echo "specs=$(find ${{ inputs.specs_path }} -type f -name "*.cypress.spec.tsx" -exec basename {} \; | sort | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT - - cypress-component-test-run: - needs: [cypress-component-test-list] - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - spec: ${{ fromJson(needs.cypress-component-test-list.outputs.specs) }} - name: ${{ matrix.spec }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Cypress component testing - uses: ./.github/actions/web-frontend-component-test - with: - module: ${{ inputs.module_name }} - spec_file_path: ${{ inputs.specs_path }}/${{ matrix.spec }} - dependencies_lock_file: ${{ inputs.dependencies_lock_file }} - - - name: Upload components tests Results - if: failure() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: ${{ inputs.name }}-test-reports-${{ matrix.spec }} - path: centreon/cypress/results/*.json - retention-days: 1 - - - name: Change coverage report name - run: mv ${{ inputs.module_name }}/.nyc_output/out.json ${{ inputs.module_name }}/.nyc_output/${{ matrix.spec }}-out.json - shell: bash - - - name: Archive test coverage - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: ${{ inputs.name }}-test-coverage-${{ matrix.spec }} - path: ${{ inputs.module_name }}/.nyc_output/${{ matrix.spec }}-out.json - retention-days: 1 - - cypress-component-coverage-report: - needs: [cypress-component-test-run] - if: always() - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 8 - - - name: Download coverage reports - uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 - with: - pattern: ${{ inputs.name }}-test-coverage-* - path: .nyc_output/ - merge-multiple: true - - - name: Merge coverage reports - run: | - pnpx nyc merge .nyc_output - mv coverage.json .nyc_output/out.json - shell: bash - - - name: Generate lcov coverage report - run: pnpx nyc report --reporter=lcov --reporter html - shell: bash - - - name: Format title - id: title - run: | - MODULE_NAME=`echo "${{ inputs.module_name }}" | sed -e "s#/#-#g"` - echo "replaced=$MODULE_NAME" >> $GITHUB_OUTPUT - shell: bash - - - name: Install action dependencies - run: pnpm install --frozen-lockfile - working-directory: ./.github/actions/code-coverage-gate-keeper - shell: bash - - - name: Archive HTML code coverage - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: ${{ steps.title.outputs.replaced }}-${{ inputs.name }}-code-coverage - path: coverage/lcov-report - retention-days: 1 - - - name: Publish code coverage to PR - uses: romeovs/lcov-reporter-action@4cf015aa4afa87b78238301f1e3dc140ea0e1ec6 - if: ${{ github.event_name == 'pull_request' }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - title: Code coverage report for ${{ steps.title.outputs.replaced }} ${{ inputs.name }} 🚀 - delete-old-comments: true - filter-changed-files: true - - - name: Check Code coverage - uses: ./.github/actions/code-coverage-gate-keeper - if: ${{ github.event_name == 'pull_request' }} - with: - module_path: ${{ inputs.module_name }} - github_token: ${{ secrets.GITHUB_TOKEN }} - name: ${{ steps.title.outputs.replaced }} - - cypress-component-test-report: - needs: [cypress-component-test-run] - if: failure() - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 8 - - - name: Download Artifacts - uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 - with: - pattern: ${{ inputs.name }}-test-reports-* - path: ${{ inputs.name }}-json-reports - merge-multiple: true - - - name: Merge reports - run: | - pnpx mochawesome-merge "${{ inputs.name }}-json-reports/**/*.json" > mochawesome.json - shell: bash - - - name: Publish report - uses: ./.github/actions/publish-report - with: - check_name: ${{ inputs.name }}-report - path: mochawesome.json - format: cypress - urlFilePrefix: centreon - - regroup-artifacts: - needs: [cypress-component-coverage-report, cypress-component-test-report, cypress-component-test-run] - if: always() - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - type_of_report: [test-results, test-reports, test-coverage] - steps: - - name: Merge Artifacts - uses: actions/upload-artifact/merge@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 - if: ${{ ( contains(needs.cypress-component-test-run.result, 'failure') && ( matrix.type_of_report == 'test-reports' ) ) || matrix.type_of_report == 'test-coverage' }} - with: - name: ${{ inputs.name }}-${{ matrix.type_of_report }} - pattern: ${{ inputs.name }}-${{ matrix.type_of_report }}-* - delete-merged: false # cannot be set to true due to random fails: Failed to DeleteArtifact: Unable to make request: ECONNRESET - retention-days: 1 - - - name: Delete merged artifacts - uses: geekyeggo/delete-artifact@24928e75e6e6590170563b8ddae9fac674508aa1 # v5.0.0 - with: - name: ${{ inputs.name }}-${{ matrix.type_of_report }}-* - failOnError: false diff --git a/.github/workflows/cypress-e2e-parallelization.yml b/.github/workflows/cypress-e2e-parallelization.yml deleted file mode 100644 index be37304d0d..0000000000 --- a/.github/workflows/cypress-e2e-parallelization.yml +++ /dev/null @@ -1,277 +0,0 @@ -on: - workflow_call: - inputs: - name: - required: true - type: string - module_name: - required: true - type: string - database_image: - required: true - type: string - image_name: - required: true - type: string - os: - required: true - type: string - features_path: - required: true - type: string - major_version: - required: true - type: string - minor_version: - required: true - type: string - stability: - required: true - type: string - package_cache_key: - required: false - type: string - package_directory: - required: false - type: string - dependencies_lock_file: - required: true - type: string - description: "The frontend dependencies lock file path" - xray_keys_and_ids: - description: "The test execution and the test plan keys and ids" - required: true - type: string - secrets: - registry_username: - required: true - registry_password: - required: true - xray_client_id: - required: true - xray_client_secret: - required: true - -jobs: - cypress-e2e-test-list: - runs-on: ubuntu-22.04 - outputs: - features: ${{ steps.list-features.outputs.features }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: List features - id: list-features - run: | - cd ${{ inputs.module_name }} - echo "features=$(find ${{ inputs.features_path }} -type f -name "*.feature" -printf "%P\n" | sort | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT - - cypress-e2e-test-run: - needs: [cypress-e2e-test-list] - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - feature: ${{ fromJson(needs.cypress-e2e-test-list.outputs.features) }} - name: ${{ matrix.feature }} - - env: - IMAGE_TAG: ${{ github.head_ref || github.ref_name }} - SLIM_IMAGE_NAME: ${{ inputs.image_name }}-slim-${{ inputs.os }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Restore packages - if: "${{ inputs.package_cache_key != '' && inputs.package_directory != '' && contains(matrix.feature, 'platform-') }}" - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: ./*.${{ contains(inputs.os, 'alma') && 'rpm' || 'deb' }} - key: ${{ inputs.package_cache_key }} - fail-on-cache-miss: true - - - name: Move packages - if: "${{ inputs.package_cache_key != '' && inputs.package_directory != '' && contains(matrix.feature, 'platform-') }}" - run: | - mkdir -p ${{ inputs.package_directory }} - mv ./*.${{ contains(inputs.os, 'alma') && 'rpm' || 'deb' }} ${{ inputs.package_directory }} - shell: bash - - - name: Login to Registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.registry_username }} - password: ${{ secrets.registry_password }} - - - name: Restore standard slim image from cache - id: cache-docker-slim - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - continue-on-error: true - timeout-minutes: 6 - with: - path: /tmp/cache/docker-image - key: docker-image-${{ env.SLIM_IMAGE_NAME }}-${{ env.IMAGE_TAG }} - env: - SEGMENT_DOWNLOAD_TIMEOUT_MINS: 5 - - - name: Load standard slim image - if: ${{ steps.cache-docker-slim.outputs.cache-hit == 'true' }} - run: | - docker load --input /tmp/cache/docker-image/${{ env.SLIM_IMAGE_NAME }}.tar - docker tag ${{ env.SLIM_IMAGE_NAME }}:${{ env.IMAGE_TAG }} ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.SLIM_IMAGE_NAME }}:${{ env.IMAGE_TAG }} - shell: bash - - - name: Test Execution Key - id: get-test-execution-key - run: | - test_execution_key=$(echo '${{ inputs.xray_keys_and_ids }}' | jq -r '.test_execution_key_'${{ inputs.os }}) - echo "The Test Execution KEY : $test_execution_key" - echo "test_execution_key=$test_execution_key" >> $GITHUB_OUTPUT - shell: bash - - - name: Cypress e2e testing - uses: ./.github/actions/cypress-e2e-testing - with: - name: ${{ inputs.name }} - database_image: ${{ inputs.database_image }} - web_image_os: ${{ inputs.os }} - web_image_version: ${{ github.head_ref || github.ref_name }} - openid_image_version: ${{ inputs.major_version }} - saml_image_version: ${{ inputs.major_version }} - module: centreon - feature_file_path: ${{ matrix.feature }} - dependencies_lock_file: ${{ inputs.dependencies_lock_file }} - test_execution_key: ${{ steps.get-test-execution-key.outputs.test_execution_key }} - - - name: Replace / with - in the feature path - id: feature-path - if: always() - run: | - feature_name="${{ matrix.feature }}" - feature_name_with_dash="${feature_name//\//-}" - echo "Modified Feature Name: $feature_name_with_dash" - echo "feature_name_with_dash=$feature_name_with_dash" >> $GITHUB_OUTPUT - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: ${{ inputs.name }}-${{ inputs.os }}-test-results-${{ steps.feature-path.outputs.feature_name_with_dash }} - path: ${{ inputs.module_name }}/tests/e2e/results/ - retention-days: 1 - - - name: Upload test reports - if: failure() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: ${{ inputs.name }}-${{ inputs.os }}-test-reports-${{ steps.feature-path.outputs.feature_name_with_dash }} - path: ${{ inputs.module_name }}/tests/e2e/results/reports/*.json - retention-days: 1 - - - name: Upload xray reports - if: always() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: ${{ inputs.name }}-${{ inputs.os }}-xray-reports-${{ steps.feature-path.outputs.feature_name_with_dash }} - path: ${{ inputs.module_name }}/tests/e2e/results/cucumber-logs/*.json - retention-days: 1 - - # This action is only for NIGHTLY and testing branches - import-reports-to-xray: - needs: [cypress-e2e-test-run] - if: ${{ always() && (inputs.stability == 'testing' || github.event_name == 'schedule') }} - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 7 - - - name: Download Artifacts - uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 - with: - pattern: ${{ inputs.name }}-${{ inputs.os }}-xray-reports-* - path: ${{ inputs.name }}-json-xray-reports - merge-multiple: true - - - name: Generate Xray Token - id: generate-xray-token - run: | - token_response=$(curl -H "Content-Type: application/json" -X POST --data "{\"client_id\": \"${{ secrets.XRAY_CLIENT_ID }}\", \"client_secret\": \"${{ secrets.XRAY_CLIENT_SECRET }}\"}" "https://xray.cloud.getxray.app/api/v1/authenticate") - xray_token=$(echo "$token_response" | sed -n 's/.*"\(.*\)".*/\1/p') - echo "xray_token=$xray_token" >> $GITHUB_OUTPUT - shell: bash - - - name: Keys - run: | - test_execution_key=$(echo '${{ inputs.xray_keys_and_ids }}' | jq -r '.test_execution_key_'${{ inputs.os }}) - test_plan_key=$(echo '${{ inputs.xray_keys_and_ids }}' | jq -r '.test_plan_key_'${{ inputs.os }}) - echo "The Test Execution KEY : $test_execution_key" - echo "The Test Plan KEY: $test_plan_key" - - - name: Import results to xray - run: | - for file in "${{ inputs.name }}-json-xray-reports/"*.json - do - curl -H "Content-Type: application/json" -X POST -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token }}" --data @"$file" https://xray.cloud.getxray.app/api/v2/import/execution/cucumber - done - - cypress-e2e-test-report: - needs: [cypress-e2e-test-run] - if: failure() - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 8 - - - name: Download Artifacts - uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 - with: - pattern: ${{ inputs.name }}-${{ inputs.os }}-test-reports-* - path: ${{ inputs.name }}-json-reports - merge-multiple: true - - - name: Merge reports - run: pnpx mochawesome-merge "${{ inputs.name }}-json-reports/**/*.json" > mochawesome.json - shell: bash - - - name: Publish report - uses: ./.github/actions/publish-report - with: - check_name: ${{ inputs.name }}-report - path: mochawesome.json - format: cypress - urlFilePrefix: centreon - - regroup-artifacts: - needs: [cypress-e2e-test-run, import-reports-to-xray, cypress-e2e-test-report] - if: always() - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - type_of_report: [test-results, test-reports, xray-reports] - steps: - - name: Merge Artifacts - uses: actions/upload-artifact/merge@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 - if: ${{ ( contains(needs.cypress-e2e-test-run.result, 'failure') && ( matrix.type_of_report == 'test-results' || matrix.type_of_report == 'test-reports' ) ) || matrix.type_of_report == 'xray-reports' }} - with: - name: ${{ inputs.name }}-${{ inputs.os }}-${{ matrix.type_of_report }} - pattern: ${{ inputs.name }}-${{ inputs.os }}-${{ matrix.type_of_report }}-* - delete-merged: false # cannot be set to true due to random fails: Failed to DeleteArtifact: Unable to make request: ECONNRESET - retention-days: 1 - - - name: Delete merged artifacts - uses: geekyeggo/delete-artifact@24928e75e6e6590170563b8ddae9fac674508aa1 # v5.0.0 - with: - name: ${{ inputs.name }}-${{ inputs.os }}-${{ matrix.type_of_report }}-* - failOnError: false diff --git a/.github/workflows/docker-gorgone-testing.yml b/.github/workflows/docker-gorgone-testing.yml deleted file mode 100644 index 05bfeaf063..0000000000 --- a/.github/workflows/docker-gorgone-testing.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: docker-gorgone-testing - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - paths: - - ".github/docker/Dockerfile.gorgone-testing-*" - pull_request: - paths: - - ".github/docker/Dockerfile.gorgone-testing-*" - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - dockerize: - needs: [get-version] - runs-on: ubuntu-22.04 - - strategy: - matrix: - distrib: [alma8, bullseye] - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - - - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 - with: - file: .github/docker/Dockerfile.gorgone-testing-${{ matrix.distrib }} - context: . - pull: true - push: true - tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/gorgone-testing-${{ matrix.distrib }}:${{ needs.get-version.outputs.major_version }} diff --git a/.github/workflows/docker-keycloak.yml b/.github/workflows/docker-keycloak.yml deleted file mode 100644 index 8cfd9c4d60..0000000000 --- a/.github/workflows/docker-keycloak.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: docker-keycloak - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - paths: - - ".github/docker/keycloak/**" - push: - branches: - - develop - paths: - - ".github/docker/keycloak/**" - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - create-and-push-docker: - needs: [get-version] - runs-on: ubuntu-22.04 - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - - - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 - with: - file: .github/docker/keycloak/Dockerfile - context: . - pull: true - push: true - tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/keycloak:${{ needs.get-version.outputs.major_version }} diff --git a/.github/workflows/docker-packaging.yml b/.github/workflows/docker-packaging.yml deleted file mode 100644 index b1a3e348f1..0000000000 --- a/.github/workflows/docker-packaging.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: docker-packaging - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - paths: - - ".github/docker/Dockerfile.packaging-*" - pull_request: - paths: - - ".github/docker/Dockerfile.packaging-*" - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - dockerize: - needs: [get-version] - - strategy: - fail-fast: false - matrix: - include: - - runner: ubuntu-22.04 - dockerfile: packaging-alma8 - image: packaging-alma8 - - runner: ubuntu-22.04 - dockerfile: packaging-nfpm-alma8 - image: packaging-nfpm-alma8 - - runner: ubuntu-22.04 - dockerfile: packaging-alma9 - image: packaging-alma9 - - runner: ubuntu-22.04 - dockerfile: packaging-nfpm-alma9 - image: packaging-nfpm-alma9 - - runner: ubuntu-22.04 - dockerfile: packaging-bullseye - image: packaging-bullseye - - runner: ubuntu-22.04 - dockerfile: packaging-nfpm-bullseye - image: packaging-nfpm-bullseye - - runner: ubuntu-22.04 - dockerfile: packaging-bookworm - image: packaging-bookworm - - runner: ubuntu-22.04 - dockerfile: packaging-nfpm-bookworm - image: packaging-nfpm-bookworm - - runner: ubuntu-22.04 - dockerfile: packaging-nfpm-jammy - image: packaging-nfpm-jammy - - runner: ["self-hosted", "collect-arm64"] - dockerfile: packaging-bullseye - image: packaging-bullseye-arm64 - - runner: ["self-hosted", "collect-arm64"] - dockerfile: packaging-nfpm-bullseye - image: packaging-nfpm-bullseye-arm64 - - runs-on: ${{ matrix.runner }} - - name: build container ${{ matrix.image }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - - - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 - with: - file: .github/docker/Dockerfile.${{ matrix.dockerfile }} - context: . - pull: true - push: true - tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} diff --git a/.github/workflows/docker-translation.yml b/.github/workflows/docker-translation.yml deleted file mode 100644 index 77dae01ac0..0000000000 --- a/.github/workflows/docker-translation.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: docker-translation - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - paths: - - ".github/docker/Dockerfile.translation" - pull_request: - paths: - - ".github/docker/Dockerfile.translation" - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - dockerize: - needs: [get-version] - runs-on: ubuntu-22.04 - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - - - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 - with: - file: .github/docker/Dockerfile.translation - context: . - pull: true - push: true - tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/translation:${{ needs.get-version.outputs.major_version }} diff --git a/.github/workflows/docker-web-dependencies.yml b/.github/workflows/docker-web-dependencies.yml deleted file mode 100644 index 6e9c1fa53b..0000000000 --- a/.github/workflows/docker-web-dependencies.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: docker-web-dependencies - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - paths: - - '.github/docker/centreon-web/**/Dockerfile.dependencies' - schedule: - - cron: '0 2 * * *' - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - dockerize: - needs: [get-version] - runs-on: ubuntu-22.04 - - strategy: - fail-fast: false - matrix: - distrib: [alma8, alma9, bullseye, bookworm, jammy] - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - - - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 - with: - file: .github/docker/centreon-web/${{ matrix.distrib }}/Dockerfile.dependencies - context: . - build-args: | - "VERSION=${{ needs.get-version.outputs.major_version }}" - "RELEASE_CLOUD=${{ needs.get-version.outputs.release_cloud }}" - pull: true - push: true - tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/centreon-web-dependencies-${{ matrix.distrib }}:${{ needs.get-version.outputs.major_version }} - secrets: | - "ARTIFACTORY_INTERNAL_REPO_USERNAME=${{ secrets.ARTIFACTORY_INTERNAL_REPO_USERNAME }}" - "ARTIFACTORY_INTERNAL_REPO_PASSWORD=${{ secrets.ARTIFACTORY_INTERNAL_REPO_PASSWORD }}" diff --git a/.github/workflows/dsm.yml b/.github/workflows/dsm.yml index dc2437fba8..ee9713074b 100644 --- a/.github/workflows/dsm.yml +++ b/.github/workflows/dsm.yml @@ -6,7 +6,7 @@ concurrency: on: workflow_dispatch: - pull_request: + pull_request_target: types: - opened - synchronize @@ -31,10 +31,30 @@ env: module: dsm jobs: + validation: + runs-on: ubuntu-22.04 + steps: + - name: Validate potential external contributions + id: validate + run: | + ENVIRONMENT_PULL_REQUEST="external_contributor" + if [[ "${{ github.event_name }}" == 'pull_request_target' ]] && [[ + "${{ github.event.pull_request.author_association }}" == "MEMBER" || + "${{ github.event.pull_request.author_association }}" == "CONTRIBUTOR" || + "${{ github.event.pull_request.author_association }}" == "OWNER" ]]; then + ENVIRONMENT_PULL_REQUEST="internal_contributor" + fi + echo "environment_pull_request=$ENVIRONMENT_PULL_REQUEST" >> $GITHUB_OUTPUT + shell: bash + outputs: + environment_pull_request: ${{ steps.validate.outputs.environment_pull_request }} + get-version: uses: ./.github/workflows/get-version.yml + needs: [validation] with: version_file: centreon-dsm/www/modules/centreon-dsm/conf.php + environment_pull_request: ${{ needs.validation.outputs.environment_pull_request }} veracode-analysis: needs: [get-version] @@ -58,10 +78,10 @@ jobs: needs: [get-version] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 + uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 with: php-version: 8.1 coverage: none @@ -77,158 +97,158 @@ jobs: run: vendor/bin/phpstan analyse --no-progress --level=0 --configuration=phpstan.neon working-directory: centreon-dsm - package: - needs: [get-version, backend-lint] - if: ${{ needs.get-version.outputs.stability != 'stable' }} - - strategy: - fail-fast: true - matrix: - distrib: [el8, el9, bullseye, bookworm] - include: - - package_extension: rpm - image: packaging-nfpm-alma8 - distrib: el8 - - package_extension: rpm - image: packaging-nfpm-alma9 - distrib: el9 - - package_extension: deb - image: packaging-nfpm-bullseye - distrib: bullseye - - package_extension: deb - image: packaging-nfpm-bookworm - distrib: bookworm - - package_extension: deb - image: packaging-nfpm-jammy - distrib: jammy - - runs-on: ubuntu-22.04 - - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} - credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - name: package ${{ matrix.distrib }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Change macro - run: | - find ./centreon-dsm -type f | xargs sed -i -f ./centreon-dsm/packaging/src/centreon-macroreplacement.txt - shell: bash - - - name: Package - uses: ./.github/actions/package-nfpm - with: - nfpm_file_pattern: "centreon-dsm/packaging/*.yaml" - distrib: ${{ matrix.distrib }} - package_extension: ${{ matrix.package_extension }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - release: ${{ needs.get-version.outputs.release }} - arch: all - commit_hash: ${{ github.sha }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} - rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} - rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} - rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} - stability: ${{ needs.get-version.outputs.stability }} - - deliver-sources: - runs-on: [self-hosted, common] - needs: [get-version, package] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch'}} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Deliver sources - uses: ./.github/actions/release-sources - with: - bucket_directory: centreon-dsm - module_directory: centreon-dsm - module_name: centreon-dsm - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - token_download_centreon_com: ${{ secrets.TOKEN_DOWNLOAD_CENTREON_COM }} - - delivery-rpm: - needs: [get-version, package] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} - runs-on: [self-hosted, common] - environment: ${{ needs.get-version.outputs.environment }} - - strategy: - matrix: - distrib: [el8, el9] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/rpm-delivery - with: - module_name: dsm - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - delivery-deb: - needs: [get-version, package] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} - runs-on: [self-hosted, common] - environment: ${{ needs.get-version.outputs.environment }} - - strategy: - matrix: - distrib: [bullseye, bookworm, jammy] - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/deb-delivery - with: - module_name: dsm - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - promote: - needs: [get-version] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - runs-on: [self-hosted, common] - strategy: - matrix: - distrib: [el8, el9, bullseye, bookworm] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Promote ${{ matrix.distrib }} to stable - uses: ./.github/actions/promote-to-stable - with: - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - module: dsm - distrib: ${{ matrix.distrib }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - github_ref_name: ${{ github.ref_name }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} + # package: + # needs: [get-version, backend-lint] + # if: ${{ needs.get-version.outputs.stability != 'stable' }} + + # strategy: + # fail-fast: true + # matrix: + # distrib: [el8, el9, bullseye, bookworm] + # include: + # - package_extension: rpm + # image: packaging-nfpm-alma8 + # distrib: el8 + # - package_extension: rpm + # image: packaging-nfpm-alma9 + # distrib: el9 + # - package_extension: deb + # image: packaging-nfpm-bullseye + # distrib: bullseye + # - package_extension: deb + # image: packaging-nfpm-bookworm + # distrib: bookworm + # - package_extension: deb + # image: packaging-nfpm-jammy + # distrib: jammy + + # runs-on: ubuntu-22.04 + + # container: + # image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} + # credentials: + # username: ${{ secrets.DOCKER_REGISTRY_ID }} + # password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} + + # name: package ${{ matrix.distrib }} + + # steps: + # - name: Checkout sources + # uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # - name: Change macro + # run: | + # find ./centreon-dsm -type f | xargs sed -i -f ./centreon-dsm/packaging/src/centreon-macroreplacement.txt + # shell: bash + + # - name: Package + # uses: ./.github/actions/package-nfpm + # with: + # nfpm_file_pattern: "centreon-dsm/packaging/*.yaml" + # distrib: ${{ matrix.distrib }} + # package_extension: ${{ matrix.package_extension }} + # major_version: ${{ needs.get-version.outputs.major_version }} + # minor_version: ${{ needs.get-version.outputs.minor_version }} + # release: ${{ needs.get-version.outputs.release }} + # arch: all + # commit_hash: ${{ github.sha }} + # cache_key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} + # rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} + # rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} + # rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + # stability: ${{ needs.get-version.outputs.stability }} + + # deliver-sources: + # runs-on: [self-hosted, common] + # needs: [get-version, package] + # if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch'}} + + # steps: + # - name: Checkout sources + # uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # - name: Deliver sources + # uses: ./.github/actions/release-sources + # with: + # bucket_directory: centreon-dsm + # module_directory: centreon-dsm + # module_name: centreon-dsm + # major_version: ${{ needs.get-version.outputs.major_version }} + # minor_version: ${{ needs.get-version.outputs.minor_version }} + # token_download_centreon_com: ${{ secrets.TOKEN_DOWNLOAD_CENTREON_COM }} + + # delivery-rpm: + # needs: [get-version, package] + # if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} + # runs-on: [self-hosted, common] + # environment: ${{ needs.get-version.outputs.environment }} + + # strategy: + # matrix: + # distrib: [el8, el9] + + # steps: + # - name: Checkout sources + # uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # - name: Delivery + # uses: ./.github/actions/rpm-delivery + # with: + # module_name: dsm + # distrib: ${{ matrix.distrib }} + # version: ${{ needs.get-version.outputs.major_version }} + # artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} + # cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} + # stability: ${{ needs.get-version.outputs.stability }} + # release_type: ${{ needs.get-version.outputs.release_type }} + # release_cloud: ${{ needs.get-version.outputs.release_cloud }} + + # deliver-deb: + # needs: [get-version, package] + # if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} + # runs-on: [self-hosted, common] + # environment: ${{ needs.get-version.outputs.environment }} + + # strategy: + # matrix: + # distrib: [bullseye, bookworm, jammy] + # steps: + # - name: Checkout sources + # uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # - name: Delivery + # uses: ./.github/actions/deb-delivery + # with: + # module_name: dsm + # distrib: ${{ matrix.distrib }} + # version: ${{ needs.get-version.outputs.major_version }} + # artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} + # cache_key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} + # stability: ${{ needs.get-version.outputs.stability }} + # release_type: ${{ needs.get-version.outputs.release_type }} + # release_cloud: ${{ needs.get-version.outputs.release_cloud }} + + # promote: + # needs: [get-version] + # if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} + # runs-on: [self-hosted, common] + # strategy: + # matrix: + # distrib: [el8, el9, bullseye, bookworm] + + # steps: + # - name: Checkout sources + # uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # - name: Promote ${{ matrix.distrib }} to stable + # uses: ./.github/actions/promote-to-stable + # with: + # artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} + # module: dsm + # distrib: ${{ matrix.distrib }} + # major_version: ${{ needs.get-version.outputs.major_version }} + # minor_version: ${{ needs.get-version.outputs.minor_version }} + # stability: ${{ needs.get-version.outputs.stability }} + # github_ref_name: ${{ github.ref_name }} + # release_type: ${{ needs.get-version.outputs.release_type }} + # release_cloud: ${{ needs.get-version.outputs.release_cloud }} diff --git a/.github/workflows/get-version.yml b/.github/workflows/get-version.yml index a58d2755c9..4ac7adb3b7 100644 --- a/.github/workflows/get-version.yml +++ b/.github/workflows/get-version.yml @@ -4,6 +4,10 @@ on: version_file: required: true type: string + environment_pull_request: + description: "environment for pull request runs" + required: true + type: string outputs: major_version: description: "major version" @@ -20,9 +24,9 @@ on: environment: description: "environment deployed" value: ${{ jobs.get-version.outputs.environment }} - dockerize_matrix: - description: "matrix to use for dockerize job" - value: ${{ jobs.get-version.outputs.dockerize_matrix }} + os_and_database_matrix: + description: "matrix to use for dockerize and test jobs" + value: ${{ jobs.get-version.outputs.os_and_database_matrix }} release_type: description: "type of release (hotfix, release)" value: ${{ jobs.get-version.outputs.release_type }} @@ -30,23 +34,30 @@ on: description: "context of release (cloud or not cloud)" value: ${{ jobs.get-version.outputs.release_cloud }} + jobs: get-version: runs-on: ubuntu-22.04 + environment: ${{ inputs.environment_pull_request }} outputs: major_version: ${{ steps.get_version.outputs.major_version }} minor_version: ${{ steps.get_version.outputs.minor_version }} release: ${{ steps.get_version.outputs.release }} stability: ${{ steps.get_version.outputs.stability }} environment: ${{ steps.get_version.outputs.env }} - dockerize_matrix: ${{ steps.get_version.outputs.dockerize_matrix }} + os_and_database_matrix: ${{ steps.get_os_database_matrix.outputs.result }} release_type: ${{ steps.get_version.outputs.release_type }} - release_cloud: ${{ steps.get_version.outputs.release_cloud}} + release_cloud: ${{ steps.get_version.outputs.release_cloud }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 + - uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 if: ${{ endsWith(inputs.version_file, '.php') }} with: php-version: 8.1 @@ -113,6 +124,16 @@ jobs: echo "BRANCHNAME is: $BRANCHNAME" + # Check if pull_request is internal or contribution + IS_EXTERNAL_CONTRIBUTION="" + if [ "${{ github.repository }}" != "${{ github.event.pull_request.head.repo.full_name }}" ]; then + echo "Detected external contribution, setting IS_CONTRIBUTION value to yes." + IS_EXTERNAL_CONTRIBUTION="yes" + else + echo "Detected internal contribution, setting IS_CONTRIBUTION value to no." + IS_EXTERNAL_CONTRIBUTION="no" + fi + # Set default release values GITHUB_RELEASE_CLOUD=0 GITHUB_RELEASE_TYPE=$(echo $BRANCHNAME |cut -d '-' -f 1) @@ -133,6 +154,11 @@ jobs: echo "release_cloud=1" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT ;; + dev-[2-9][0-9].[0-9][0-9].x) + echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT + echo "release_cloud=0" >> $GITHUB_OUTPUT + echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT + ;; release* | hotfix*) # Handle workflow_dispatch run triggers and run a dispatch ONLY for cloud release GITHUB_RELEASE_BRANCH_BASE_REF_NAME="$(gh pr view $BRANCHNAME -q .baseRefName --json headRefName,baseRefName,state)" @@ -160,25 +186,50 @@ jobs: echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT fi ;; + prepare-release-cloud*) + # Set release cloud to 1 (0=not-cloud, 1=cloud) + GITHUB_RELEASE_CLOUD=1 + # Debug + echo "GITHUB_RELEASE_TYPE is: $GITHUB_RELEASE_TYPE" + echo "GITHUB_RELEASE_CLOUD is: $GITHUB_RELEASE_CLOUD" + # Github ouputs + echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT + echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT + echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT + ;; *) # Any branch name - GITHUB_BRANCH_BASE_REF_NAME="$(gh pr view $BRANCHNAME -q .baseRefName --json headRefName,baseRefName,state)" - GITHUB_BRANCH_PR_STATE="$(gh pr view $BRANCHNAME -q .state --json headRefName,baseRefName,state)" - echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT - - # Check if pull request branch targeting develop - if [[ "$GITHUB_BRANCH_BASE_REF_NAME" == "develop" ]] && [[ "$GITHUB_BRANCH_PR_STATE" == "OPEN" ]]; then + echo "Github repository context var: $GITHUB_REPOSITORY" + if [[ "$IS_EXTERNAL_CONTRIBUTION" == "no" ]]; then + echo "Internal contribution." echo "release_cloud=1" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT - else - echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT + # GITHUB_BRANCH_BASE_REF_NAME="$(gh pr view $BRANCHNAME -q .baseRefName --json headRefName,baseRefName,state)" + # GITHUB_BRANCH_PR_STATE="$(gh pr view $BRANCHNAME -q .state --json headRefName,baseRefName,state)" + elif [[ "$IS_EXTERNAL_CONTRIBUTION" == "yes" ]]; then + echo "External contribution." + echo "release_cloud=1" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT + # CONTRIB_PR_NUMBER=$(gh pr list --repo ${{ github.repository }} --head ${{ github.head_ref }} -q .[].number --json number) + # GITHUB_BRANCH_PR_STATE="$(gh pr view $CONTRIB_PR_NUMBER -q .state --json headRefName,baseRefName,state)" + else + echo "Invalid value for IS_EXTERNAL_CONTRIBUTION : $IS_EXTERNAL_CONTRIBUTION ." fi - ;; + echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT + + # Check if pull request branch targeting develop + # if [[ "$GITHUB_BRANCH_BASE_REF_NAME" == "develop" ]] && [[ "$GITHUB_BRANCH_PR_STATE" == "OPEN" ]]; then + # echo "release_cloud=1" >> $GITHUB_OUTPUT + # echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT + # else + # echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT + # echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT + # fi + # ;; esac case "$BRANCHNAME" in - develop | dev-[2-9][0-9].[0-9][0-9].x) + develop | dev-[2-9][0-9].[0-9][0-9].x |prepare-release-cloud*) STABILITY="unstable" ENV="development" ;; @@ -201,12 +252,49 @@ jobs: esac echo "stability=$STABILITY" >> $GITHUB_OUTPUT echo "env=$MAJOR-$ENV" >> $GITHUB_OUTPUT - - DOCKERIZE_MATRIX='["alma9"]' - if [ "${{ github.event_name }}" = "schedule" ]; then - DOCKERIZE_MATRIX='["alma8","alma9","bullseye"]' - fi - echo "dockerize_matrix=$DOCKERIZE_MATRIX" >> $GITHUB_OUTPUT shell: bash env: GH_TOKEN: ${{ github.token }} + + - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + id: get_os_database_matrix + with: + script: | + const alma9_mariadb = { + "operating_system": "alma9", + "database": "mariadb:10.11", + "test_tags": "not @ignore" + }; + const alma8_mariadb = { + "operating_system": "alma8", + "database": "mariadb:10.11", + "test_tags": "not @ignore and @system" + }; + const bookworm_mysql = { + "operating_system": "bookworm", + "database": "mysql:8.3", + "test_tags": "not @ignore" + }; + const bullseye_mysql = { + "operating_system": "bullseye", + "database": "mysql:8.3", + "test_tags": "not @ignore and @system" + }; + + let matrix = { + "main": [alma9_mariadb], + "operating_systems": [alma9_mariadb], + "databases": [alma9_mariadb], + }; + + if (context.eventName === 'schedule') { + matrix = { + "main": [alma9_mariadb], + "operating_systems": [alma9_mariadb, alma8_mariadb, bookworm_mysql, bullseye_mysql], + "databases": [alma9_mariadb, bookworm_mysql], + }; + } + + console.log(matrix); + + return matrix; diff --git a/.github/workflows/gorgone.yml b/.github/workflows/gorgone.yml deleted file mode 100644 index 9d90dc8566..0000000000 --- a/.github/workflows/gorgone.yml +++ /dev/null @@ -1,305 +0,0 @@ -name: gorgone - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - "centreon-gorgone/**" - - "!centreon-gorgone/veracode.json" - - "!centreon-gorgone/.veracode-exclusions" - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - - master - - "[2-9][0-9].[0-9][0-9].x" - paths: - - "centreon-gorgone/**" - - "!centreon-gorgone/veracode.json" - - "!centreon-gorgone/.veracode-exclusions" - -env: - base_directory: centreon-gorgone - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon-gorgone/.version - - veracode-analysis: - needs: [get-version] - uses: ./.github/workflows/veracode-analysis.yml - with: - module_directory: centreon-gorgone - module_name: centreon-gorgone - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - is_perl_project: true - secrets: - veracode_api_id: ${{ secrets.VERACODE_API_ID_GORG }} - veracode_api_key: ${{ secrets.VERACODE_API_KEY_GORG }} - veracode_srcclr_token: ${{ secrets.VERACODE_SRCCLR_TOKEN }} - jira_base_url: ${{ secrets.JIRA_BASE_URL }} - jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} - jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} - - package: - needs: [get-version] - if: ${{ needs.get-version.outputs.stability != 'stable' }} - - strategy: - fail-fast: false - matrix: - distrib: [el8, el9, bullseye, bookworm, jammy] - include: - - package_extension: rpm - image: packaging-nfpm-alma8 - distrib: el8 - - package_extension: rpm - image: packaging-nfpm-alma9 - distrib: el9 - - package_extension: deb - image: packaging-nfpm-bullseye - distrib: bullseye - - package_extension: deb - image: packaging-nfpm-bookworm - distrib: bookworm - - package_extension: deb - image: packaging-nfpm-jammy - distrib: jammy - - runs-on: ubuntu-22.04 - - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} - credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - name: package ${{ matrix.distrib }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Set package version and paths according to distrib - run: | - if [[ "${{ matrix.package_extension }}" == "deb" ]]; then - PERL_VENDORLIB="/usr/share/perl5" - else - PERL_VENDORLIB="/usr/share/perl5/vendor_perl" - fi - echo "PERL_VENDORLIB=$PERL_VENDORLIB" >> $GITHUB_ENV - shell: bash - - - name: Generate selinux binaries - if: ${{ matrix.package_extension == 'rpm' }} - run: | - cd centreon-gorgone/selinux - sed -i "s/@VERSION@/${{ needs.get-version.outputs.major_version }}.${{ needs.get-version.outputs.minor_version }}/g" centreon-gorgoned.te - make -f /usr/share/selinux/devel/Makefile - shell: bash - - - name: Remove selinux packaging files on debian - if: ${{ matrix.package_extension == 'deb' }} - run: rm -f centreon-gorgone/packaging/*-selinux.yaml - shell: bash - - - name: Package - uses: ./.github/actions/package-nfpm - with: - nfpm_file_pattern: "centreon-gorgone/packaging/*.yaml" - distrib: ${{ matrix.distrib }} - package_extension: ${{ matrix.package_extension }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - release: ${{ needs.get-version.outputs.release }} - arch: all - commit_hash: ${{ github.sha }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} - rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} - rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} - rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} - stability: ${{ needs.get-version.outputs.stability }} - - test-gorgone: - needs: [get-version, package] - - strategy: - fail-fast: false - matrix: - distrib: [el8, bullseye] - include: - - package_extension: rpm - image: gorgone-testing-alma8 - distrib: el8 - - package_extension: deb - image: gorgone-testing-bullseye - distrib: bullseye - runs-on: ubuntu-22.04 - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} - credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - services: - mariadb: - image: mariadb:latest - ports: - - 3306 - env: - MYSQL_USER: centreon - MYSQL_PASSWORD: password - MYSQL_ROOT_PASSWORD: password - - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: get cached gorgone package - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: ./*.${{ matrix.package_extension }} - key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} - fail-on-cache-miss: true - - - name: Install gorgogne from just built package - shell: bash - run: | - if [[ "${{ matrix.package_extension }}" == "deb" ]]; then - apt install -y ./centreon-gorgone*${{ matrix.distrib }}* - else - dnf install -y ./centreon-gorgone*${{ matrix.distrib }}* ./centreon-gorgone-centreon-config*${{ matrix.distrib }}* - # in el8 at least, there is a package for the configuration and a package for the actual code. - # this is not the case for debian, and for now I don't know why it was made any different between the 2 Os. - fi - - - name: Create databases - run: | - mysql -h mariadb -u root -ppassword -e "CREATE DATABASE \`centreon\`" - mysql -h mariadb -u root -ppassword -e "CREATE DATABASE \`centreon-storage\`" - mysql -h mariadb -u root -ppassword -e "GRANT ALL PRIVILEGES ON centreon.* TO 'centreon'@'%'" - mysql -h mariadb -u root -ppassword -e "GRANT ALL PRIVILEGES ON \`centreon-storage\`.* TO 'centreon'@'%'" - mysql -h mariadb -u root -ppassword 'centreon' < centreon/www/install/createTables.sql - mysql -h mariadb -u root -ppassword 'centreon-storage' < centreon/www/install/createTablesCentstorage.sql - - - name: Run tests - run: robot -v 'DBHOST:mariadb' -v 'DBNAME:centreon' -v 'DBUSER:centreon' centreon-gorgone/tests - - - - name: Upload gorgone and robot debug artifacts - if: failure() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: gorgone-debug-${{ matrix.distrib }} - path: | - log.html - /var/log/centreon-gorgone - /etc/centreon-gorgone - retention-days: 1 - - deliver-sources: - runs-on: [self-hosted, common] - needs: [get-version, package] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Deliver sources - uses: ./.github/actions/release-sources - with: - bucket_directory: centreon-gorgone - module_directory: centreon-gorgone - module_name: centreon-gorgone - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - token_download_centreon_com: ${{ secrets.TOKEN_DOWNLOAD_CENTREON_COM }} - - deliver-rpm: - runs-on: [self-hosted, common] - needs: [get-version, package] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} - - strategy: - matrix: - distrib: [el8, el9] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/rpm-delivery - with: - module_name: gorgone - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - deliver-deb: - runs-on: [self-hosted, common] - needs: [get-version, package] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} - - strategy: - matrix: - distrib: [bullseye, bookworm, jammy] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/deb-delivery - with: - module_name: gorgone - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - promote: - needs: [get-version] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - runs-on: [self-hosted, common] - strategy: - matrix: - distrib: [el8, el9, bullseye, bookworm] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Promote ${{ matrix.distrib }} to stable - uses: ./.github/actions/promote-to-stable - with: - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - module: gorgone - distrib: ${{ matrix.distrib }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - github_ref_name: ${{ github.ref_name }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} diff --git a/.github/workflows/ha.yml b/.github/workflows/ha.yml deleted file mode 100644 index 2075745c0d..0000000000 --- a/.github/workflows/ha.yml +++ /dev/null @@ -1,168 +0,0 @@ -name: ha - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - "centreon-ha/**" - - "!centreon-ha/veracode.json" - - "!centreon-ha/.veracode-exclusions" - push: - branches: - - dev-[2-9][0-9].[0-9][0-9].x - - "[2-9][0-9].[0-9][0-9].x" - paths: - - "centreon-ha/**" - - "!centreon-ha/veracode.json" - - "!centreon-ha/.veracode-exclusions" - -env: - module: ha - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon-ha/.env - -# package: -# needs: [get-version] -# if: ${{ needs.get-version.outputs.stability != 'stable' }} - -# strategy: -# fail-fast: true -# matrix: -# include: -# - package_extension: rpm -# image: packaging-alma8 -# distrib: el8 -# - package_extension: rpm -# image: packaging-alma9 -# distrib: el9 -# - package_extension: deb -# image: packaging-bullseye -# distrib: bullseye -# - package_extension: deb -# image: packaging-bookworm -# distrib: bookworm - -# uses: ./.github/workflows/package.yml -# with: -# base_directory: centreon-ha -# spec_file: centreon-ha/packaging/centreon-ha.spectemplate -# package_extension: ${{ matrix.package_extension }} -# image_name: ${{ matrix.image }} -# module_name: ha -# major_version: ${{ needs.get-version.outputs.major_version }} -# minor_version: ${{ needs.get-version.outputs.minor_version }} -# release: ${{ needs.get-version.outputs.release }} -# commit_hash: ${{ github.sha }} -# cache_key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} -# distrib: ${{ matrix.distrib }} -# secrets: -# registry_username: ${{ secrets.DOCKER_REGISTRY_ID }} -# registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - -# deliver-sources: -# runs-on: [self-hosted, common] -# needs: [get-version, package] -# if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - -# steps: -# - name: Checkout sources -# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - -# - name: Deliver sources -# uses: ./.github/actions/release-sources -# with: -# bucket_directory: centreon-ha -# module_directory: centreon-ha -# module_name: centreon-ha -# major_version: ${{ needs.get-version.outputs.major_version }} -# minor_version: ${{ needs.get-version.outputs.minor_version }} -# token_download_centreon_com: ${{ secrets.TOKEN_DOWNLOAD_CENTREON_COM }} - -# delivery-rpm: -# needs: [get-version, package] -# if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} -# runs-on: [self-hosted, common] -# environment: ${{ needs.get-version.outputs.environment }} - -# strategy: -# matrix: -# distrib: [el8, el9] - -# steps: -# - name: Checkout sources -# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - -# - name: Delivery -# uses: ./.github/actions/rpm-delivery -# with: -# module_name: ha -# distrib: ${{ matrix.distrib }} -# version: ${{ needs.get-version.outputs.major_version }} -# artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} -# cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} -# stability: ${{ needs.get-version.outputs.stability }} -# release_type: ${{ needs.get-version.outputs.release_type }} -# release_cloud: ${{ needs.get-version.outputs.release_cloud }} - -# delivery-deb: -# needs: [get-version, package] -# if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} -# runs-on: [self-hosted, common] -# environment: ${{ needs.get-version.outputs.environment }} - -# strategy: -# matrix: -# distrib: [bullseye, bookworm] -# steps: -# - name: Checkout sources -# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - -# - name: Delivery -# uses: ./.github/actions/deb-delivery -# with: -# module_name: ha -# distrib: ${{ matrix.distrib }} -# version: ${{ needs.get-version.outputs.major_version }} -# artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} -# cache_key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} -# stability: ${{ needs.get-version.outputs.stability }} -# release_type: ${{ needs.get-version.outputs.release_type }} -# release_cloud: ${{ needs.get-version.outputs.release_cloud }} - -# promote: -# needs: [get-version] -# if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} -# runs-on: [self-hosted, common] -# strategy: -# matrix: -# distrib: [el8, el9, bullseye, bookworm] - -# steps: -# - name: Checkout sources -# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - -# - name: Promote ${{ matrix.distrib }} to stable -# uses: ./.github/actions/promote-to-stable -# with: -# artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} -# module: ha -# distrib: ${{ matrix.distrib }} -# major_version: ${{ needs.get-version.outputs.major_version }} -# minor_version: ${{ needs.get-version.outputs.minor_version }} -# stability: ${{ needs.get-version.outputs.stability }} -# github_ref_name: ${{ github.ref_name }} -# release_type: ${{ needs.get-version.outputs.release_type }} -# release_cloud: ${{ needs.get-version.outputs.release_cloud }} diff --git a/.github/workflows/js-config-beta.yml b/.github/workflows/js-config-beta.yml deleted file mode 100644 index 7f621ed165..0000000000 --- a/.github/workflows/js-config-beta.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: centreon-js-config-beta - -on: - workflow_dispatch: - pull_request: - paths: - - 'centreon/packages/js-config/**' - - '.github/workflows/js-config-beta.yml' - -env: - directory: "centreon/packages/js-config" - package: 'js-config' - base_branch: develop - -jobs: - publish-new-npm-beta-version: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.head_ref }} - - - uses: ./.github/actions/npm-publish-package-beta - with: - directory: ${{ env.directory }} - pat: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - npm_token: ${{ secrets.NPM_TOKEN }} - release_branch: ${{ env.base_branch }} - package: ${{ env.package }} diff --git a/.github/workflows/js-config-stable.yml b/.github/workflows/js-config-stable.yml deleted file mode 100644 index 54877570a8..0000000000 --- a/.github/workflows/js-config-stable.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: centreon-js-config-stable - -on: - workflow_dispatch: - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - paths: - - "centreon/packages/js-config/**" - - ".github/actions/npm-publish-package-stable/**" - - '.github/workflows/js-config-stable.yml' - - "!centreon/packages/js-config/package.json" - -env: - directory: "centreon/packages/js-config" - package: "js-config" - base_branch: develop - -jobs: - publish-new-npm-version: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/npm-publish-package-stable - with: - directory: ${{ env.directory }} - pat: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - npm_token: ${{ secrets.NPM_TOKEN }} - release_branch: ${{ env.base_branch }} - package: ${{ env.package }} diff --git a/.github/workflows/newman.yml b/.github/workflows/newman.yml deleted file mode 100644 index e4d29a60ab..0000000000 --- a/.github/workflows/newman.yml +++ /dev/null @@ -1,727 +0,0 @@ -on: - workflow_call: - inputs: - collection_path: - required: true - type: string - image_name: - required: true - type: string - os: - required: true - type: string - container_name: - required: true - type: string - centreon_url: - required: true - type: string - centreon_image: - required: true - type: string - database_image: - required: true - type: string - dependencies_lock_file: - required: true - type: string - major_version: - required: true - type: string - stability: - required: true - type: string - xray_keys_and_ids: - description: "The test execution and the test plan keys and ids" - required: true - type: string - secrets: - registry_username: - required: true - registry_password: - required: true - client_id: - required: true - client_secret: - required: true - jira_user: - required: true - jira_token_test: - required: true - -jobs: - newman-test-list: - runs-on: ubuntu-22.04 - - outputs: - collections: ${{ steps.set_collections.outputs.collections }} - steps: - - name: Checkout Repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: List Postman Collections and Environments - id: set_collections - run: | - collection_path="${{ inputs.collection_path }}" - collections=$(find "$collection_path" -type f -name "*.postman_collection.json" -printf "%P\n" | sort | jq -R -s -c 'split("\n")[:-1]') - echo "collections=$collections" >> $GITHUB_OUTPUT - echo "GITHUB_OUTPUT contents:" - cat $GITHUB_OUTPUT - - associate-test-cases: - runs-on: ubuntu-22.04 - if: ${{ inputs.os == 'alma9' && contains(fromJson('["testing", "unstable"]'), inputs.stability) && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_nightly == 'true')) }} - outputs: - test_execution_id: ${{ steps.get-test-ids.outputs.test_execution_id }} - test_plan_id: ${{ steps.get-test-ids.outputs.test_plan_id }} - issue_list_ids: ${{ steps.xray-newman.outputs.issue_list_ids }} - defaults: - run: - shell: bash - working-directory: centreon/tests/rest_api - - steps: - - name: Checkout Repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Test Execution and test plan Keys - id: get-test-ids - run: | - test_execution_id=$(echo '${{ inputs.xray_keys_and_ids }}' | jq -r '.test_execution_id_'${{ inputs.os }}) - test_plan_id=$(echo '${{ inputs.xray_keys_and_ids }}' | jq -r '.test_plan_id_'${{ inputs.os }}) - echo "The Test Execution ID : $test_execution_id" - echo "The Test Plan ID : $test_plan_id" - echo "test_plan_id=$test_plan_id" >> $GITHUB_OUTPUT - echo "test_execution_id=$test_execution_id" >> $GITHUB_OUTPUT - shell: bash - - - name: Generate Xray Token - id: generate-xray-token - run: | - token_response=$(curl -H "Content-Type: application/json" -X POST --data "{\"client_id\": \"${{ secrets.client_id }}\", \"client_secret\": \"${{ secrets.client_secret }}\"}" "https://xray.cloud.getxray.app/api/v1/authenticate") - xray_token=$(echo "$token_response" | sed -n 's/.*"\(.*\)".*/\1/p') - echo "xray_token=$xray_token" >> $GITHUB_OUTPUT - shell: bash - - - name: Associate Test Cases with Test plan - id: xray-newman - run: | - get_test_ids() { - start=0 - test_issue_ids=() - - while true; do - xray_graphql_getTests='{ - "query": "query getTests($jql: String, $limit: Int!, $start: Int) { getTests(jql: $jql, limit: $limit, start: $start) { total results { issueId } } }", - "variables": { - "jql": "reporter = \"712020:093f82f0-b0f1-4498-8369-fbe72fb50bcb\" AND project = MON AND type = \"Test\" AND testType = \"API\"", - "limit": 100, - "start": '$start' - } - }' - - response=$(curl -X POST \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token }}" \ - --data "$xray_graphql_getTests" \ - "https://xray.cloud.getxray.app/api/v2/graphql") - - echo "Response from getTests:" - echo "$response" - - # Parsing and processing test IDs - current_test_issue_ids=($(echo "$response" | jq -r '.data.getTests.results[].issueId')) - - echo "Current Test Issue IDs: ${current_test_issue_ids[@]}" - - # Check if there are no more test issues - if [ ${#current_test_issue_ids[@]} -eq 0 ]; then - echo "No more test issues. Exiting loop." - break - fi - - # Concatenate the current batch of results to the overall test_issue_ids array - test_issue_ids+=("${current_test_issue_ids[@]}") - - # Increment the start value for the next iteration - start=$((start + 100)) - done - - # Display all retrieved test issue IDs - echo "All Test Issue IDs: ${test_issue_ids[@]}" - } - - get_test_ids - - formatted_getTest_issue_ids_str="[" - for issue_id in "${test_issue_ids[@]}"; do - formatted_getTest_issue_ids_str+="\"$issue_id\"," - done - formatted_getTest_issue_ids_str="${formatted_getTest_issue_ids_str%,}" - formatted_getTest_issue_ids_str+="]" - echo "$formatted_getTest_issue_ids_str" - - # Display the retrieved test issue IDs - echo "Test Issue IDs: ${test_issue_ids[@]}" - - # Mutation to add tests to the test plan - xray_graphql_addTestsToTestPlan='{ - "query": "mutation AddTestsToTestPlan($issueId: String!, $testIssueIds: [String]!) { addTestsToTestPlan(issueId: $issueId, testIssueIds: $testIssueIds) { addedTests warning } }", - "variables": { - "issueId": "'${{ steps.get-test-ids.outputs.test_plan_id }}'", - "testIssueIds": '"$formatted_getTest_issue_ids_str"' - } - }' - - # Execute the mutation to add tests to the test plan - response_addTestsToTestPlan=$(curl -X POST \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token }}" \ - --data "$xray_graphql_addTestsToTestPlan" \ - "https://xray.cloud.getxray.app/api/v2/graphql") - - echo "Response from Add Tests to Test Plan:" - echo "$response_addTestsToTestPlan" - - get_test_plan_issue_ids() { - start=0 - issue=() - api_issue_ids=() - - while true; do - xray_graphql_getTestPlan='{ - "query": "query GetTestPlan($issueId: String, $start: Int) { getTestPlan(issueId: $issueId) { issueId tests(limit: 100, start: $start) { results { issueId testType { name } } } } }", - "variables": { - "issueId": "'${{ steps.get-test-ids.outputs.test_plan_id }}'", - "start": '$start' - } - }' - - response=$(curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token }}" --data "${xray_graphql_getTestPlan}" "https://xray.cloud.getxray.app/api/v2/graphql") - - echo "Response from Get Test Plan:" - echo "$response" - - # Parsing and processing test IDs - current_issue_ids=($(echo "$response" | jq -r '.data.getTestPlan.tests.results[] | .issueId')) - echo "Current Issue IDs: ${current_issue_ids[@]}" - - # Concatenate the current batch of results to the overall issue_ids array - issue=("${issue[@]}" "${current_issue_ids[@]}") - - # Parsing and processing test IDs for API tests and adding them to api_issue_ids - current_api_issue_ids=($(echo "$response" | jq -r '.data.getTestPlan.tests.results[] | select(.testType.name == "API") | .issueId')) - api_issue_ids=("${api_issue_ids[@]}" "${current_api_issue_ids[@]}") - - # Increment the start value for the next iteration - start=$((start + 100)) - - # Check if there are more results - if [ -z "$response" ] || [ ${#current_issue_ids[@]} -eq 0 ]; then - echo "No more results. Exiting loop." - break - fi - done - - # Display results - echo "API Issue IDs: ${api_issue_ids[@]}" - } - - get_test_plan_issue_ids - issue_ids=("${api_issue_ids[@]}") - - summaries=() - - for issue_id in "${issue_ids[@]}"; do - echo "Processing issue ID: $issue_id" - jira_issue_url="https://centreon.atlassian.net/rest/api/2/issue/$issue_id" - - response=$(curl --request GET \ - --url "$jira_issue_url" \ - --user "${{ secrets.jira_user }}:${{ secrets.jira_token_test }}" \ - --header 'Accept: application/json') - - summary=$(echo "$response" | jq -r '.fields.summary') - - if [ "$response_code" -eq 404 ]; then - echo "The issue with ID $issue_id does not exist or you do not have permission to see it." - break - else - echo "The issue with ID $issue_id exists." - summaries+=("$summary") - fi - done - - collections=($(find ./collections -type f -name "*.postman_collection.json")) - test_case_ids=() - - xray_graphql_AddingTestsToTestPlan='{ - "query": "mutation AddTestsToTestPlan($issueId: String!, $testIssueIds: [String]!) { addTestsToTestPlan(issueId: $issueId, testIssueIds: $testIssueIds) { addedTests warning } }", - "variables": { - "issueId":"${{ steps.get-test-ids.outputs.test_plan_id }}", - "testIssueIds": [] - } - }' - - existing_test_case_ids=("${issue_ids[@]}") - - for collection_file in "${collections[@]}"; do - collection_name=$(basename "$collection_file" .postman_collection.json) - collection_name_sanitized="${collection_name//[^a-zA-Z0-9]/_}" - - if [[ " ${summaries[@]} " =~ " ${collection_name_sanitized} " ]]; then - echo "The test case for $collection_name_sanitized already exists in the test plan." - else - # Adding a new test case - response=$(curl --request POST \ - --url 'https://centreon.atlassian.net/rest/api/2/issue' \ - --user '${{ secrets.jira_user }}:${{ secrets.jira_token_test }}' \ - --header 'Accept: application/json' \ - --header 'Content-Type: application/json' \ - --data '{ - "fields": { - "project": { - "key": "MON" - }, - "summary": "'"$collection_name_sanitized"'", - "components": [{"name": "centreon-web"}], - "priority":{"name":"Low"}, - "description": "Test case for '"$collection_name_sanitized"'", - "issuetype": { - "name": "Test" - } - } - }' \ - --max-time 20) - - if [ -z "$response" ]; then - echo "Failed to create the test case within the specified time." - else - test_case_id=$(echo "$response" | jq -r '.id') - - # Checking if the test case is a new one - if [[ ! " ${existing_test_case_ids[@]} " =~ " ${test_case_id} " ]]; then - echo "New Test Case with ID: $test_case_id" - summaries+=("$collection_name_sanitized") - - # Update GraphQL query to add this test to the test plan - xray_graphql_AddingTestsToTestPlan_variables=$(echo "$xray_graphql_AddingTestsToTestPlan" | jq --arg test_case_id "$test_case_id" '.variables.testIssueIds += [$test_case_id]') - - # Execute the GraphQL mutation to update the testType only for new test cases - testType_mutation_response=$(curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token }}" --data '{"query": "mutation { updateTestType(issueId: \"'$test_case_id'\", testType: {name: \"API\"} ) { issueId testType { name kind } } }"}' "https://xray.cloud.getxray.app/api/v2/graphql") - - # Checking if the mutation was successful - if [ "$(echo "$testType_mutation_response" | jq -r '.data.updateTestType')" != "null" ]; then - echo "Successfully updated testType to API for Test Case with ID: $test_case_id" - else - echo "Failed to update testType for Test Case with ID: $test_case_id" - fi - - # Execute the GraphQL mutation to add tests to the test plan - response=$(curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token}}" --data "$xray_graphql_AddingTestsToTestPlan_variables" "https://xray.cloud.getxray.app/api/v2/graphql") - else - echo "Test Case with ID $test_case_id already exists in the test plan." - fi - fi - fi - done - - get_test_plan_issue_ids - issue_list_ids=("${issue[@]}") - echo "issue_list_ids=("${issue[@]}")" >> $GITHUB_OUTPUT - - test_issue_ids=("${issue_list_ids[@]}") - formatted_test_issue_ids_str="[" - for issue_id in "${issue_list_ids[@]}"; do - formatted_test_issue_ids_str+="\"$issue_id\"," - done - formatted_test_issue_ids_str="${formatted_test_issue_ids_str%,}" - formatted_test_issue_ids_str+="]" - echo "$formatted_test_issue_ids_str" - - xray_graphql_addTestsToTestExecution='{ - "query": "mutation AddTestsToTestExecution($issueId: String!, $testIssueIds: [String]) { addTestsToTestExecution(issueId: $issueId, testIssueIds: $testIssueIds) { addedTests warning } }", - "variables": { - "issueId": "${{ steps.get-test-ids.outputs.test_execution_id }}", - "testIssueIds": '$formatted_test_issue_ids_str' - } - }' - - response_addTestsToTestExecution=$(curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token }}" --data "${xray_graphql_addTestsToTestExecution}" "https://xray.cloud.getxray.app/api/v2/graphql") - - echo "Response from Add Tests to Test Execution:" - echo "$response_addTestsToTestExecution" - - newman-test-run: - needs: [newman-test-list, associate-test-cases] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - feature: ${{ fromJson(needs.newman-test-list.outputs.collections) }} - - name: ${{ matrix.feature }} - - defaults: - run: - shell: bash - working-directory: centreon/tests/rest_api - env: - IMAGE_TAG: ${{ github.head_ref || github.ref_name }} - SLIM_IMAGE_NAME: ${{ inputs.image_name }}-slim-${{ inputs.os }} - CONTAINER_NAME: ${{ inputs.container_name }} - CENTREON_URL: ${{ inputs.centreon_url }} - WEB_IMAGE: ${{ inputs.centreon_image }} - DATABASE_IMAGE: ${{ inputs.database_image }} - steps: - - name: Checkout Repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 8 - run_install: false - - - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - with: - node-version: 20 - cache: pnpm - cache-dependency-path: ${{ inputs.dependencies_lock_file }} - - - name: Install Dependencies for tests/rest_api - run: pnpm install --frozen-lockfile - shell: bash - env: - CYPRESS_INSTALL_BINARY: "0" - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" - PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true" - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.registry_username }} - password: ${{ secrets.registry_password }} - - - name: Restore standard slim image from cache - id: cache-docker-slim - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - continue-on-error: true - timeout-minutes: 6 - with: - path: /tmp/cache/docker-image - key: docker-image-${{ env.SLIM_IMAGE_NAME }}-${{ env.IMAGE_TAG }} - env: - SEGMENT_DOWNLOAD_TIMEOUT_MINS: 5 - - - name: Load standard slim image - if: ${{ steps.cache-docker-slim.outputs.cache-hit == 'true' }} - run: | - docker load --input /tmp/cache/docker-image/${{ env.SLIM_IMAGE_NAME }}.tar - docker tag ${{ env.SLIM_IMAGE_NAME }}:${{ env.IMAGE_TAG }} ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.SLIM_IMAGE_NAME }}:${{ env.IMAGE_TAG }} - shell: bash - - - name: Start Centreon Web and database containers - env: - MYSQL_IMAGE: ${{ env.DATABASE_IMAGE }} - run: | - COLLECTION_DIRECTORY=$(dirname "collections/${{ matrix.feature }}") - - if [[ -f "${COLLECTION_DIRECTORY}/.env" ]]; then - echo "Using environment file ${COLLECTION_DIRECTORY}/.env" - cat ${COLLECTION_DIRECTORY}/.env >> ../../../.github/docker/.env - fi - - docker compose --profile web -f ../../../.github/docker/docker-compose.yml up -d --wait - - if [[ -f "${COLLECTION_DIRECTORY}/setup.sh" ]]; then - echo "Running script ${COLLECTION_DIRECTORY}/setup.sh ..." - bash -ex "${COLLECTION_DIRECTORY}/setup.sh" - fi - - if [[ -f "${COLLECTION_DIRECTORY}/setup-web.sh" ]]; then - echo "Running script ${COLLECTION_DIRECTORY}/setup-web.sh ..." - docker compose -f ../../../.github/docker/docker-compose.yml cp ${COLLECTION_DIRECTORY}/setup-web.sh web:/tmp/setup-web.sh - docker compose -f ../../../.github/docker/docker-compose.yml exec web bash -ex "/tmp/setup-web.sh" - fi - shell: bash - - - name: Run Postman Tests and Generate HTML Report - run: | - collection_file="collections/${{ matrix.feature }}" - collection_name=$(basename "$collection_file" .postman_collection.json) - collection_directory="$(dirname "$collection_file")" - environment_file=$(find "$collection_directory" -maxdepth 1 -type f -name "*.postman_environment.json") - if [ -f "$environment_file" ]; then - echo "Environment: $environment_file" - pnpm newman run "$collection_file" -e "$environment_file" --working-dir "$collection_directory" --reporters cli,htmlextra,json-summary --reporter-htmlextra-title "$collection_name" --reporter-htmlextra-title "${collection_name// /_}" --reporter-htmlextra-export "newman/${collection_name}.html" --reporter-summary-json-export "postman_summaries/${collection_name}-summary.json" - else - echo "The file Environment-Collection.json was not found in the same directory as $collection_file" - exit 1 - fi - shell: bash - - - name: Display container logs - if: failure() - run: docker compose -f ../../../.github/docker/docker-compose.yml logs - - - name: Replace / with - in the feature path - id: feature-path - if: always() - run: | - feature_name="${{ matrix.feature }}" - feature_name_with_dash="${feature_name//\//-}" - echo "Modified Feature Name: $feature_name_with_dash" - echo "feature_name_with_dash=$feature_name_with_dash" >> $GITHUB_OUTPUT - - - name: Upload HTML Reports - if: failure() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: postman-html-reports-${{ steps.feature-path.outputs.feature_name_with_dash }} - path: centreon/tests/rest_api/newman/ - - - name: Upload test reports - if: always() - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: newman-${{ inputs.os }}-test-reports-${{ steps.feature-path.outputs.feature_name_with_dash }} - path: centreon/tests/rest_api/postman_summaries/*.json - retention-days: 1 - - synchronize-with-xray: - needs: [newman-test-run, associate-test-cases] - if: always() - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Generate Xray Token - id: generate-xray-token - run: | - token_response=$(curl -H "Content-Type: application/json" -X POST --data "{\"client_id\": \"${{ secrets.client_id }}\", \"client_secret\": \"${{ secrets.client_secret }}\"}" "https://xray.cloud.getxray.app/api/v1/authenticate") - xray_token=$(echo "$token_response" | sed -n 's/.*"\(.*\)".*/\1/p') - echo "xray_token=$xray_token" >> $GITHUB_OUTPUT - shell: bash - - - name: Download Artifacts - uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 - with: - pattern: newman-${{ inputs.os }}-test-reports-* - path: newman-json-test-reports - merge-multiple: true - - - name: Delete Artifacts - run: | - artifact_pattern="newman-${{ inputs.os }}-test-reports-" - TOKEN="${{ secrets.GITHUB_TOKEN }}" - artifact_exists=true - while [ "$artifact_exists" = true ]; do - artifact_exists=false - artifacts_response=$(curl -L \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $TOKEN" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/${{ github.repository }}/actions/artifacts?per_page=100") - artifacts=$(echo $artifacts_response | jq -c '.artifacts[]') - echo "Those are the artifacts : $artifacts" - while read row; do - artifact_name=$(echo "$row" | jq -r '.name') - if [[ "$artifact_name" =~ ^.*"$artifact_pattern".* ]]; then - artifact_exists=true - echo "Deleting : $artifact_name" - artifact_id=$(echo "$row" | jq -r '.id') - curl -L \ - -X DELETE \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $TOKEN" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/${{ github.repository }}/actions/artifacts/${artifact_id}" - fi - done <<< "$artifacts" - done - echo "End of Deleting" - shell: bash - - - name: Extract and Store Summaries - run: | - declare -A json_info - for summary_file in newman-json-test-reports/*.json; do - summary_content=$(cat "$summary_file" | jq -c '{Name: .Collection.Info.Name, Stats: .Run.Stats, Failures: .Run.Failures}') - filename=$(basename "$summary_file" .json) - clean_filename="${filename// /_}" - clean_filename="${clean_filename//-/_}" - json_info["$clean_filename"]=$summary_content - done - for key in "${!json_info[@]}"; do - echo "Summary info for $key:" - echo "${json_info[$key]}" - done - - - name: Change test execution status - if: ${{ inputs.os == 'alma9' && contains(fromJson('["testing", "unstable"]'), inputs.stability) && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_nightly == 'true')) }} - run: | - for summary_file in newman-json-test-reports/*.json; do - test_execution_id=${{ needs.associate-test-cases.outputs.test_execution_id }} - test_plan_id=${{ needs.associate-test-cases.outputs.test_plan_id }} - issue_ids=${{ needs.associate-test-cases.outputs.issue_list_ids }} - echo "issue_ids content: $issue_ids" - - filename=$(basename "$summary_file") - collection_name="${filename%-summary.json}" - collection_name="${collection_name//-/_}" - echo "Contenu de collection_name : $collection_name" - - failed_requests=$(jq -r '.Run.Stats.Requests.failed' "$summary_file") - failed_assertions=$(jq -r '.Run.Stats.Assertions.failed' "$summary_file") - failures=$(jq -r '.Run.Failures' "$summary_file") - - summaries=() - for issue_id in "${issue_ids[@]}"; do - echo "Processing issue ID: $issue_id" - jira_issue_url="https://centreon.atlassian.net/rest/api/2/issue/$issue_id" - - response=$(curl --request GET --url "$jira_issue_url" --user "${{ secrets.jira_user }}:${{ secrets.jira_token_test }}" --header 'Accept: application/json') - - if [ "$response_code" -eq 404 ]; then - echo "The issue with ID $issue_id does not exist or you do not have permission to see it." - else - echo "The issue with ID $issue_id exists." - summary=$(echo "$response" | jq -r '.fields.summary') - echo "Summary: $summary" - echo "Collection Name: $collection_name" - if [ "$summary" == "$collection_name" ]; then - echo "Matching issue ID: $issue_id with Collection Name: $collection_name" - if [ "$failed_requests" -gt 0 ] || [ "$failed_assertions" -gt 0 ]; then - newStatus="FAILED" - else - newStatus="PASSED" - fi - xray_graphql_getTestRunIDs='{ - "query": "query GetTestRuns($testIssueIds: [String], $testExecIssueIds: [String], $limit: Int!) { getTestRuns(testIssueIds: $testIssueIds, testExecIssueIds: $testExecIssueIds, limit: $limit) { total limit start results { id status { name color description } gherkin examples { id status { name color description } } test { issueId } testExecution { issueId } } } }", - "variables": { - "testIssueIds": ["'"$issue_id"'"], - "testExecIssueIds": ["'"$test_execution_id"'"], - "limit": 100 - } - }' - echo "$xray_graphql_getTestRunIDs" - response_getTestRun=$(curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token}}" --data "$xray_graphql_getTestRunIDs" -v "https://xray.cloud.getxray.app/api/v2/graphql") - echo "$response_getTestRun" - - # Analyze the JSON response to extract the test run ID corresponding to the issue ID - test_run_id=$(echo "$response_getTestRun" | jq -r ".data.getTestRuns.results[] | select(.test.issueId == \"$issue_id\") | .id") - - # Check if a corresponding testRunId was found - if [ -n "$test_run_id" ]; then - echo "Found Test Run ID $test_run_id for Issue ID $issue_id and Collection Name $collection_name" - - # Use the test_run_id to execute the mutation - graphqlMutation="{\"query\": \"mutation { updateTestRunStatus(id: \\\"$test_run_id\\\", status: \\\"$newStatus\\\") }\"}" - echo "$graphqlMutation" - curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{ steps.generate-xray-token.outputs.xray_token}}" --data "$graphqlMutation" -v "https://xray.cloud.getxray.app/api/v2/graphql" - - # You can add checks to handle the response as needed. - else - echo "Test Run ID not found for Issue ID $issue_id and Collection Name $collection_name." - fi - fi - fi - done - done - - - name: Perform Jira Transitions - if: ${{ inputs.os == 'alma9' && contains(fromJson('["testing", "unstable"]'), inputs.stability) && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_nightly == 'true')) }} - run: | - issue_ids=${{ needs.associate-test-cases.outputs.issue_list_ids }} - transition_ids=("61" "81" "21" "31") - - # Display the final set of issue IDs - echo "All Issue IDs: ${issue_ids[@]}" - - for test_issue_id in "${issue_ids[@]}"; do - # Make a GET request to get information about available transitions - get_response=$(curl --request GET \ - --url "https://centreon.atlassian.net/rest/api/2/issue/${test_issue_id}/transitions?expand=transitions.fields" \ - --user "${{ secrets.jira_user }}:${{ secrets.jira_token_test }}" \ - --header 'Accept: application/json') - - # Extract the transition ID from the response - current_transition_id=$(echo "$get_response" | jq -r '.transitions[0].id') - # Check if the current transition ID is 41 - if [ "$current_transition_id" -eq 41 ]; then - echo "Skipping Jira transition for issue ID $test_issue_id as current transition ID is 41." - else - # Perform the POST request for transitions other than 41 - for transition_id in "${transition_ids[@]}"; do - curl --request POST \ - --url "https://centreon.atlassian.net/rest/api/2/issue/${test_issue_id}/transitions?expand=transitions.fields" \ - --user "${{ secrets.jira_user }}:${{ secrets.jira_token_test }}" \ - --header 'Accept: application/json' \ - --header 'Content-Type: application/json' \ - --data '{ - "transition": { - "id": "'"$transition_id"'" - } - }' - echo "Processing issue ID: $test_issue_id" - echo "Performing Jira transition with transition ID: $transition_id..." - done - fi - done - - - name: Generate and Display Summaries - if: ${{ contains(needs.newman-test-run.result, 'failure') }} - run: | - summaries="" - has_failures=false - for summary_file in newman-json-test-reports/*.json; do - collection_name=$(jq -r '.Collection.Info.Name' "$summary_file") - total_requests=$(jq -r '.Run.Stats.Requests.total' "$summary_file") - pending_requests=$(jq -r '.Run.Stats.Requests.pending' "$summary_file") - failed_requests=$(jq -r '.Run.Stats.Requests.failed' "$summary_file") - failed_assertions=$(jq -r '.Run.Stats.Assertions.failed' "$summary_file") - failures=$(jq -r '.Run.Failures' "$summary_file") - echo "$failures" - if [ "$failed_requests" -gt 0 ] || [ "$failed_assertions" -gt 0 ]; then - has_failures=true # Set has_failures to true if there are failures - summaries+="" - summaries+="" - summaries+="" - summaries+="
Collection NameTotal Requests⏭️ Skipped requests❌ Failed Requests❌ Failed Assertions
$collection_name$total_requests$pending_requests$failed_requests$failed_assertions
" - filtered_failures=$(echo "$failures" | jq -c '.[] | select(.Parent.Name // "" != "" and .Source.Name // "" != "" and .Error.Message // "" != "")') - while IFS= read -r row; do - parent_name=$(echo "$row" | jq -r '.Parent.Name') - source_name=$(echo "$row" | jq -r '.Source.Name') - error_message=$(echo "$row" | jq -r '.Error.Message') - - summaries+="

📁 Collection name: $parent_name
📬 Request name: $source_name
❌ Error message: $error_message

" - done <<< "$(echo "$filtered_failures")" - fi - echo "Processing summary file: $summary_file" - done - - if [ -n "$summaries" ]; then - echo -e "$summaries" >> $GITHUB_STEP_SUMMARY - fi - - regroup-artifacts: - needs: [newman-test-run] - if: always() - runs-on: ubuntu-22.04 - - steps: - - name: Merge Artifacts - uses: actions/upload-artifact/merge@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 - if: ${{ contains(needs.newman-test-run.result, 'failure') }} - with: - name: postman-html-reports - pattern: postman-html-reports-* - retention-days: 1 - - - name: Delete merged artifacts - uses: geekyeggo/delete-artifact@24928e75e6e6590170563b8ddae9fac674508aa1 # v5.0.0 - with: - name: postman-html-reports-* - failOnError: false diff --git a/.github/workflows/open-tickets.yml b/.github/workflows/open-tickets.yml deleted file mode 100644 index 5a0e4bbcd4..0000000000 --- a/.github/workflows/open-tickets.yml +++ /dev/null @@ -1,229 +0,0 @@ -name: open-tickets - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - "centreon-open-tickets/**" - - "!centreon-open-tickets/veracode.json" - - "!centreon-open-tickets/.veracode-exclusions" - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - - master - - "[2-9][0-9].[0-9][0-9].x" - paths: - - "centreon-open-tickets/**" - - "!centreon-open-tickets/veracode.json" - - "!centreon-open-tickets/.veracode-exclusions" - -env: - module: open-tickets - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon-open-tickets/www/modules/centreon-open-tickets/conf.php - - veracode-analysis: - needs: [get-version] - uses: ./.github/workflows/veracode-analysis.yml - with: - module_directory: centreon-open-tickets - module_name: centreon-open-tickets - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - secrets: - veracode_api_id: ${{ secrets.VERACODE_API_ID }} - veracode_api_key: ${{ secrets.VERACODE_API_KEY }} - veracode_srcclr_token: ${{ secrets.VERACODE_SRCCLR_TOKEN }} - jira_base_url: ${{ secrets.JIRA_BASE_URL }} - jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} - jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} - - backend-lint: - runs-on: ubuntu-22.04 - needs: [get-version] - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Setup PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 - with: - php-version: 8.1 - coverage: none - env: - runner: ubuntu-22.04 - - - name: Install Dependencies - run: composer install --optimize-autoloader - working-directory: centreon-open-tickets - shell: bash - - - name: Run of phpstan on /www at level 2 - run: vendor/bin/phpstan analyse --no-progress --level=2 --configuration=phpstan.neon - working-directory: centreon-open-tickets - - package: - needs: [get-version, backend-lint] - if: ${{ needs.get-version.outputs.stability != 'stable' }} - - strategy: - fail-fast: false - matrix: - distrib: [el8, el9, bullseye, bookworm, jammy] - include: - - package_extension: rpm - image: packaging-nfpm-alma8 - distrib: el8 - - package_extension: rpm - image: packaging-nfpm-alma9 - distrib: el9 - - package_extension: deb - image: packaging-nfpm-bullseye - distrib: bullseye - - package_extension: deb - image: packaging-nfpm-bookworm - distrib: bookworm - - package_extension: deb - image: packaging-nfpm-jammy - distrib: jammy - - runs-on: ubuntu-22.04 - - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} - credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - name: package ${{ matrix.distrib }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Package - uses: ./.github/actions/package-nfpm - with: - nfpm_file_pattern: "centreon-open-tickets/packaging/*.yaml" - distrib: ${{ matrix.distrib }} - package_extension: ${{ matrix.package_extension }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - release: ${{ needs.get-version.outputs.release }} - arch: all - commit_hash: ${{ github.sha }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} - rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} - rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} - rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} - stability: ${{ needs.get-version.outputs.stability }} - - deliver-sources: - runs-on: [self-hosted, common] - needs: [get-version, package] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Deliver sources - uses: ./.github/actions/release-sources - with: - bucket_directory: centreon-open-tickets - module_directory: centreon-open-tickets - module_name: centreon-open-tickets - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - token_download_centreon_com: ${{ secrets.TOKEN_DOWNLOAD_CENTREON_COM }} - - delivery-rpm: - needs: [get-version, package] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} - runs-on: [self-hosted, common] - environment: ${{ needs.get-version.outputs.environment }} - - strategy: - matrix: - distrib: [el8, el9] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/rpm-delivery - with: - module_name: open-tickets - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - delivery-deb: - needs: [get-version, package] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-version.outputs.stability) }} - runs-on: [self-hosted, common] - environment: ${{ needs.get-version.outputs.environment }} - - strategy: - matrix: - distrib: [bullseye, bookworm, jammy] - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/deb-delivery - with: - module_name: open-tickets - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - promote: - needs: [get-version] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - runs-on: [self-hosted, common] - strategy: - matrix: - distrib: [el8, el9, bullseye, bookworm] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Promote ${{ matrix.distrib }} to stable - uses: ./.github/actions/promote-to-stable - with: - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - module: open-tickets - distrib: ${{ matrix.distrib }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - github_ref_name: ${{ github.ref_name }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml deleted file mode 100644 index 3d1894e6ce..0000000000 --- a/.github/workflows/package.yml +++ /dev/null @@ -1,163 +0,0 @@ -on: - workflow_call: - inputs: - base_directory: - type: string - description: The module directory - required: true - spec_file: - type: string - description: The spec file path to build rpm - required: true - package_extension: - type: string - description: The package extension (deb or rpm) - required: true - distrib: - type: string - description: The package distribution - required: true - frontend_index_cache_key: - type: string - description: The index.html cache key - frontend_index_file: - type: string - description: The index.html file path - frontend_static_cache_key: - type: string - description: The static directory cache key - frontend_static_directory: - type: string - description: The static directory - frontend_widgets_cache_key: - type: string - description: The widgets build cache key - frontend_widgets_directory: - type: string - description: The widgets directory - widgets_directory: - type: string - description: The widgets directory - backend_vendor_cache_key: - type: string - description: The vendor directory cache key - backend_vendor_directory: - type: string - description: The vendor directory - translation_cache_key: - type: string - description: The translation directory cache key - translation_directory: - type: string - description: The translation directory - image_name: - type: string - description: The image name - required: true - module_name: - type: string - description: The module name - required: true - major_version: - type: string - description: The major version - required: true - minor_version: - type: string - description: The minor version - required: true - release: - type: string - description: The release number - required: true - commit_hash: - type: string - description: The hash of the commit - required: true - cache_key: - type: string - description: The package files cache key - required: true - secrets: - registry_username: - required: true - registry_password: - required: true - -jobs: - package: - name: Package ${{ inputs.package_extension }} - runs-on: ubuntu-22.04 - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ inputs.image_name }}:${{ inputs.major_version }} - credentials: - username: ${{ secrets.registry_username }} - password: ${{ secrets.registry_password }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/package - with: - base_directory: ${{ inputs.base_directory }} - spec_file: ${{ inputs.spec_file }} - package_extension: ${{ inputs.package_extension }} - distrib: ${{ inputs.distrib }} - frontend_index_cache_key: ${{ inputs.frontend_index_cache_key }} - frontend_index_file: ${{ inputs.frontend_index_file }} - frontend_static_cache_key: ${{ inputs.frontend_static_cache_key }} - frontend_static_directory: ${{ inputs.frontend_static_directory }} - frontend_widgets_cache_key: ${{ inputs.frontend_widgets_cache_key }} - frontend_widgets_directory: ${{ inputs.frontend_widgets_directory }} - widgets_directory: ${{ inputs.widgets_directory }} - backend_vendor_cache_key: ${{ inputs.backend_vendor_cache_key }} - backend_vendor_directory: ${{ inputs.backend_vendor_directory }} - translation_cache_key: ${{ inputs.translation_cache_key }} - translation_directory: ${{ inputs.translation_directory }} - module_name: ${{ inputs.module_name }} - major_version: ${{ inputs.major_version }} - minor_version: ${{ inputs.minor_version }} - release: ${{ inputs.release }} - commit_hash: ${{ inputs.commit_hash }} - cache_key: unsigned-${{ inputs.cache_key }} - - - if: ${{ inputs.package_extension == 'deb' }} - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: ./*.${{ inputs.package_extension }} - key: ${{ inputs.cache_key }} - - sign: - if: ${{ inputs.package_extension == 'rpm' }} - needs: [package] - runs-on: ubuntu-22.04 - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/rpm-signing:ubuntu - options: -t - credentials: - username: ${{ secrets.registry_username }} - password: ${{ secrets.registry_password }} - - steps: - - run: | - apt-get update - apt-get install -y zstd - shell: bash - - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: ./*.${{ inputs.package_extension }} - key: unsigned-${{ inputs.cache_key }} - - - run: echo "HOME=/root" >> $GITHUB_ENV - shell: bash - - - run: rpmsign --addsign ./*.${{ inputs.package_extension }} - shell: bash - - - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: ./*.${{ inputs.package_extension }} - key: ${{ inputs.cache_key }} diff --git a/.github/workflows/release-trigger-builds.yml b/.github/workflows/release-trigger-builds.yml deleted file mode 100644 index a7237c112b..0000000000 --- a/.github/workflows/release-trigger-builds.yml +++ /dev/null @@ -1,77 +0,0 @@ ---- -name: release-trigger-builds - -on: - workflow_dispatch: - inputs: - dispatch_target_release_branch: - description: "Cloud release branch to trigger" - required: true - dispatch_content: - description: "Regular (only centreon named components) or Full (every component, including php and extra libs)" - required: true - type: choice - options: - - REGULAR - - FULL - -jobs: - release-trigger-builds: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Install Github CLI - run: | - set -eux - - if ! command -v gh &> /dev/null; then - echo "Installing GH CLI." - type -p curl >/dev/null || (sudo apt-get update && sudo apt-get install curl -y) - curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg - sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null - sudo apt-get update - sudo apt-get install gh -y - else - echo "GH CLI is already installed." - fi - shell: bash - - - name: Trigger selected branches - run: | - set -eux - - # VARS - # names defined in workflow files per components - COMPONENTS_OSS=("awie" "dsm" "gorgone" "ha" "open-tickets" "web") - COMPONENTS_OSS_FULL=("awie" "dsm" "gorgone" "ha" "open-tickets" "web") - #COMPONENTS_MODULES=("anomaly-detection" "autodiscovery" "bam" "cloud-business-extensions" "cloud-extensions" "it-edition-extensions" "lm" "map" "mbi" "ppm") - #COMPONENTS_MODULES_FULL=("anomaly-detection" "autodiscovery" "bam" "cloud-business-extensions" "cloud-extensions" "it-edition-extensions" "lm" "map" "mbi" "ppm" "php-pecl-gnupg" "sourceguardian-loader") - #COMPONENTS_COLLECT=("Centreon collect") - RUNS_URL="" - - if [[ ${{ inputs.dispatch_target_release_branch }} =~ ^release-2[0-9]\.[0-9]+-next$ ]];then - echo "Using ${{ inputs.dispatch_target_release_branch }} as release branch to build testing packages." - RUNS_URL="https://github.com/centreon/centreon/actions?query=branch%3A${{ inputs.dispatch_target_release_branch }}" - else - echo "::error::Invalid release branch name, please check the release branch name." - exit 1 - fi - - if [[ "${{ inputs.dispatch_content }}" == "FULL" ]]; then - echo "Requested ${{ inputs.dispatch_content }} content, triggering all component workflows." - for COMPONENT in ${COMPONENTS_OSS_FULL[@]}; do - gh workflow run $COMPONENT -r ${{ inputs.dispatch_target_release_branch }} - done - else - echo "Requested ${{ inputs.dispatch_content }} content, triggering centreon named components only." - for COMPONENT in ${COMPONENTS_OSS[@]}; do - gh workflow run $COMPONENT -r ${{ inputs.dispatch_target_release_branch }} - done - fi - - echo "Dispatch was successfully triggered. Runs can be found at ${RUNS_URL}" - shell: bash - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index f9838757dd..0000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: Release - -on: - pull_request: - types: - - closed - branches: - - master - - "[2-9][0-9].[0-9][0-9].x" - paths: - - "centreon-awie/**" - - "centreon-dsm/**" - - "centreon-gorgone/**" - - "centreon-ha/**" - - "centreon-open-tickets/**" - - "centreon/**" - workflow_dispatch: - -jobs: - release: - if: ${{ github.event.pull_request.merged == true }} - runs-on: ubuntu-22.04 - steps: - - name: Check base_ref - run: | - set -eu - - # Check if github.base_ref is either master or any of the supported version ones - # This must never run on any other than master and supported version base_ref - if [[ "${{ github.base_ref }}" == 'master' || "${{ github.base_ref }}" =~ ^[2-9][0-9].[0-9][0-9].x ]];then - echo "[DEBUG] base_ref is valid: ${{ github.base_ref }}" - else - echo "::error::base_ref is not valid (${{ github.base_ref }}), exiting." - exit 1 - fi - shell: bash - - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - name: Release - id: release - uses: ./.github/actions/release - with: - github_ref_name: ${{ github.base_ref }} - jira_project_id: ${{ secrets.JIRA_PROJECT_ID }} - jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} - jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} - jira_base_url: ${{ secrets.JIRA_BASE_URL }} - jira_webhook_url: ${{ secrets.JIRA_RELEASE_WEBHOOK }} diff --git a/.github/workflows/synchronize-branches.yml b/.github/workflows/synchronize-branches.yml deleted file mode 100644 index 4be9a45361..0000000000 --- a/.github/workflows/synchronize-branches.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Sync stable and dev version branches - -on: - pull_request_target: - types: - - closed - branches: - - "[2-9][0-9].[0-9][0-9].x" - workflow_dispatch: - -jobs: - main: - name: Sync Stable Branches - runs-on: ubuntu-22.04 - if: github.event.pull_request.merged == true - steps: - - name: git checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - token: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - - - name: Sync Branches - id: release - uses: ./.github/actions/sync-branches - with: - src_branch: ${{ github.ref_name }} - dest_branch: dev-${{ github.ref_name }} diff --git a/.github/workflows/synchronize-jira-xray.yml b/.github/workflows/synchronize-jira-xray.yml deleted file mode 100644 index eb328c409a..0000000000 --- a/.github/workflows/synchronize-jira-xray.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Integrate e2e tests to Xray - -on: - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - synchronize-jira-xray: - needs: [get-version] - runs-on: ubuntu-22.04 - - steps: - - name: Checkout Code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 7 - run_install: false - - - name: Set up Node.js - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - with: - node-version: 20 - - - name: Install Dependencies - run: | - pnpm install axios@1.5.1 - pnpm install form-data@4.0.0 - pnpm install @actions/core - - - name: Get the latest commit hash - run: | - latest_commit=$(git log -1 --format="%H") - echo "LATEST_COMMIT=$latest_commit" >> $GITHUB_ENV - - - name: Find Changed Feature Files - id: find_changed_files - run: | - mapfile -t CHANGED_FILES <<< "$(git show --name-only $LATEST_COMMIT | grep '\.feature$')" - echo "CHANGED_FILES=${CHANGED_FILES[@]}" >> $GITHUB_ENV - echo "Changed .feature files: ${CHANGED_FILES[@]}" - - - name: Run Script on Changed Feature Files - if: env.CHANGED_FILES != '' - run: | - echo "The target version for this script is : ${{ needs.get-version.outputs.major_version }}" - for file in $CHANGED_FILES; do - echo "Running script for $file on branch ${{ github.ref_name }}" - node .github/scripts/synchronize_jira_xray.js "$file" ${{ github.ref_name }} ${{ needs.get-version.outputs.major_version }} - done - env: - XRAY_JIRA_USER_EMAIL: ${{ secrets.XRAY_JIRA_USER_EMAIL }} - XRAY_JIRA_TOKEN: ${{ secrets.XRAY_JIRA_TOKEN }} - XRAY_CLIENT_ID: ${{ secrets.XRAY_CLIENT_ID }} - XRAY_CLIENT_SECRET: ${{ secrets.XRAY_CLIENT_SECRET }} diff --git a/.github/workflows/synchronize-next-major-branches.yml b/.github/workflows/synchronize-next-major-branches.yml deleted file mode 100644 index 5a320205af..0000000000 --- a/.github/workflows/synchronize-next-major-branches.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Sync stable and dev version branches - -on: - pull_request_target: - types: - - closed - branches: - - "master" - workflow_dispatch: - -jobs: - main: - name: Sync Stable Branches - runs-on: ubuntu-22.04 - if: github.event.pull_request.merged == true - steps: - - name: git checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - token: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - - - name: Sync Branches - id: release - uses: ./.github/actions/sync-branches - with: - src_branch: master - dest_branch: develop diff --git a/.github/workflows/ui-beta.yml b/.github/workflows/ui-beta.yml deleted file mode 100644 index 05cf8fbc21..0000000000 --- a/.github/workflows/ui-beta.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: centreon-ui-beta - -on: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - "centreon/packages/ui/**" - - '.github/workflows/ui-beta.yml' - -env: - directory: "centreon/packages/ui" - package: "ui" - base_branch: develop - -jobs: - lint: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/frontend-lint - with: - frontend_directory: ${{ env.directory }} - module_name: centreon-ui - dependencies_lock_file: centreon/pnpm-lock.yaml - - cypress-component-testing: - uses: ./.github/workflows/cypress-component-parallelization.yml - with: - name: component - module_name: centreon/packages/ui - specs_path: src/** - dependencies_lock_file: centreon/pnpm-lock.yaml - - unit-test: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 8 - - - name: Install Centreon dependencies - run: pnpm install --frozen-lockfile - working-directory: centreon - - - name: Unit test - run: pnpm t - working-directory: ${{ env.directory }} - - publish-new-npm-beta-version: - runs-on: ubuntu-22.04 - needs: [lint, unit-test, cypress-component-testing] - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.head_ref }} - - - uses: ./.github/actions/npm-publish-package-beta - with: - directory: ${{ env.directory }} - pat: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - npm_token: ${{ secrets.NPM_TOKEN }} - release_branch: ${{ env.base_branch }} - package: ${{ env.package }} diff --git a/.github/workflows/ui-context-beta.yml b/.github/workflows/ui-context-beta.yml deleted file mode 100644 index 586cc6b2ef..0000000000 --- a/.github/workflows/ui-context-beta.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: centreon-ui-context-beta - -on: - workflow_dispatch: - pull_request: - paths: - - "centreon/packages/ui-context/**" - - '.github/workflows/ui-context.yml' - branches: - - develop - -env: - directory: "centreon/packages/ui-context" - package: 'ui-context' - base_branch: develop - -jobs: - lint: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/frontend-lint - with: - frontend_directory: ${{ env.directory }} - module_name: centreon-ui-context - dependencies_lock_file: centreon/pnpm-lock.yaml - - - publish-new-npm-beta-version: - runs-on: ubuntu-22.04 - needs: lint - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.head_ref }} - - - uses: ./.github/actions/npm-publish-package-beta - with: - directory: ${{ env.directory }} - pat: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - npm_token: ${{ secrets.NPM_TOKEN }} - package: ${{ env.package }} - release_branch: ${{ env.base_branch }} diff --git a/.github/workflows/ui-context-stable.yml b/.github/workflows/ui-context-stable.yml deleted file mode 100644 index edede4abb5..0000000000 --- a/.github/workflows/ui-context-stable.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: centreon-ui-context-stable - -on: - workflow_dispatch: - pull_request: - types: - - closed - paths: - - "centreon/packages/ui-context/**" - - ".github/actions/npm-publish-package-stable/**" - -env: - directory: "centreon/packages/ui-context" - package: "ui-context" - base_branch: develop - -jobs: - publish-new-npm-version: - runs-on: ubuntu-22.04 - if: ${{ github.event.pull_request.merged == true }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/npm-publish-package-stable - with: - directory: ${{ env.directory }} - pat: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - npm_token: ${{ secrets.NPM_TOKEN }} - release_branch: ${{ env.base_branch }} - package: ${{ env.package }} diff --git a/.github/workflows/ui-stable.yml b/.github/workflows/ui-stable.yml deleted file mode 100644 index 83af4a501f..0000000000 --- a/.github/workflows/ui-stable.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: centreon-ui-stable - -on: - workflow_dispatch: - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - paths: - - "centreon/packages/ui/**" - - ".github/actions/npm-publish-package-stable/**" - - '.github/workflows/ui-stable.yml' - - "!centreon/packages/ui/package.json" - -env: - directory: "centreon/packages/ui" - package: "ui" - base_branch: develop - AWS_ACCESS_KEY_ID: ${{ secrets.LIGHTHOUSE_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.LIGHTHOUSE_SECRET }} - AWS_DEFAULT_REGION: eu-west-1 - -jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - publish-new-npm-version: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/npm-publish-package-stable - with: - directory: ${{ env.directory }} - pat: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - npm_token: ${{ secrets.NPM_TOKEN }} - release_branch: ${{ env.base_branch }} - package: ${{ env.package }} diff --git a/.github/workflows/veracode-analysis.yml b/.github/workflows/veracode-analysis.yml index f131636a3f..0eb6e38500 100644 --- a/.github/workflows/veracode-analysis.yml +++ b/.github/workflows/veracode-analysis.yml @@ -79,7 +79,7 @@ jobs: # skip analysis of draft PR and analysis on development branches using workflow dispatch SKIP_ANALYSIS="true" - if [[ "${{ github.event_name }}" == "pull_request" && -n "${{ github.event.pull_request.number }}" && -n "${{ github.event.pull_request.draft }}" && "${{ github.event.pull_request.draft }}" == "false" ]] || [[ "$DEVELOPMENT_STAGE" != "Development" ]]; then + if [[ ("${{ github.event_name }}" == "pull_request" || "${{ github.event_name }}" == "pull_request_target") && -n "${{ github.event.pull_request.number }}" && -n "${{ github.event.pull_request.draft }}" && "${{ github.event.pull_request.draft }}" == "false" ]] || [[ "$DEVELOPMENT_STAGE" != "Development" ]]; then SKIP_ANALYSIS="false" fi @@ -90,7 +90,7 @@ jobs: echo "skip_analysis=$SKIP_ANALYSIS" >> $GITHUB_OUTPUT cat $GITHUB_OUTPUT - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 if: steps.routing-mode.outputs.skip_analysis == 'false' - name: Generate binary file @@ -107,7 +107,7 @@ jobs: runs-on: [self-hosted, common] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Get build binary uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 @@ -134,7 +134,7 @@ jobs: TARGETS=( "${{ github.base_ref || github.ref_name }}" "dev-${{ inputs.major_version }}.x" develop ) fi - for TARGET in ${TARGETS[@]}; do + for TARGET in "${TARGETS[@]}"; do RESULT=0 echo "[INFO] - Searching baseline file for $TARGET's" aws s3 ls "$BUCKET/$TARGET/results.json" || RESULT=$( echo $? ) @@ -159,7 +159,7 @@ jobs: java-version: 8 - name: Pipeline scan - uses: veracode/Veracode-pipeline-scan-action@e4326eb9e6735637c250e725c67d1b5f56d1a97c # v1.0.15 + uses: veracode/Veracode-pipeline-scan-action@fe0924c134a03ab5a74fcb9722ed8456efa48e17 # v1.0.16 continue-on-error: ${{ vars.VERACODE_CONTINUE_ON_ERROR == 'true' }} with: vid: "vera01ei-${{ secrets.veracode_api_id }}" @@ -173,7 +173,6 @@ jobs: development_stage: '${{ needs.build.outputs.development_stage }}' summary_display: '${{ needs.build.outputs.display_summary }}' issue_details: '${{ needs.build.outputs.display_summary }}' - use_upgraded_version: 'true' - name: Backup analysis reports # debug step used to investigate support case @@ -233,7 +232,7 @@ jobs: - name: Create jira ticket # In case of QG failure, a ticket must be created - if: needs.build.outputs.enable_qg == 'false' || failure() + if: needs.build.outputs.enable_qg == 'false' || ( needs.build.outputs.development_stage == 'Development' && failure() ) uses: ./.github/actions/veracode-create-jira-ticket with: jira_base_url: ${{ secrets.jira_base_url }} @@ -286,7 +285,7 @@ jobs: continue-on-error: ${{ vars.VERACODE_CONTINUE_ON_ERROR == 'true' }} with: appname: "${{ inputs.module_name }}" - version: "${{ inputs.major_version }}.${{ inputs.minor_version }}_runId-${{ github.run_id }}" + version: "${{ inputs.major_version }}.${{ inputs.minor_version }}_runId-${{ github.run_id }}_attempt-${{ github.run_attempt }}" filepath: "${{ inputs.module_directory }}/${{ inputs.module_name }}-${{ github.sha }}-${{ github.run_id }}-veracode-binary.zip" vid: "vera01ei-${{ secrets.veracode_api_id }}" vkey: "vera01es-${{ secrets.veracode_api_key }}" @@ -324,7 +323,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Removing pnpm dependencies run: | @@ -334,7 +333,7 @@ jobs: RESULT=`find ./ -type f -name "composer.lock" -o -name "composer.json"` if [[ -n ${RESULT[0]} ]]; then - echo "trigger_sca_scan=true" >> $GITHUB_ENV + echo "trigger_sca_scan=true" >> $GITHUB_ENV fi - name: SCA scan diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml deleted file mode 100644 index 294b44dc88..0000000000 --- a/.github/workflows/web.yml +++ /dev/null @@ -1,968 +0,0 @@ -name: web -run-name: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.is_nightly == 'true')) && format('web nightly {0}', github.ref_name) || '' }} - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -on: - workflow_dispatch: - inputs: - is_nightly: - description: 'Set to true for nightly run' - required: true - default: false - type: boolean - schedule: - - cron: "0 3 * * *" - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - paths: - - "centreon/**" - - "!centreon/.veracode-exclusions" - - "!centreon/veracode.json" - - "!centreon/packages/**" - push: - branches: - - develop - - dev-[2-9][0-9].[0-9][0-9].x - - master - - "[2-9][0-9].[0-9][0-9].x" - paths: - - "centreon/**" - - "!centreon/.veracode-exclusions" - - "!centreon/veracode.json" - - "!centreon/packages/**" - -env: - base_directory: centreon - widgets_directory: centreon/www/widgets - -jobs: - changes: - runs-on: ubuntu-22.04 - outputs: - has_frontend_changes: ${{ steps.filter.outputs.has_frontend_changes }} - has_backend_changes: ${{ steps.filter.outputs.has_backend_changes }} - has_features_changes: ${{ steps.filter.outputs.has_features_changes }} - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 - id: filter - with: - filters: | - has_frontend_changes: - - '**/*.[jt]sx?' - - '**/www/front_src/**' - - '**/tests/e2e/**' - - '**/package*' - - '**/lighthouse/**' - - '**/tsconfig.json' - - '**/cypress/**|**/pnpm-*' - has_backend_changes: - - '**/*.php' - - '**/phpstan*.neon' - - 'centreon/codingstyle.xml' - - 'centreon/config/**/*.xml' - - 'centreon/phpunit.xml' - - 'centreon/ruleset.xml' - - 'centreon/www/**/*.xml' - - '**/bin/**' - - '**/tmpl/**' - - '**/features/**' - - '/centreon/src/**' - - '**/config/**' - - '**/composer.*' - - '**/tests/api/**' - - '**/tests/rest_api/collections/**' - - '**/tests/php/**' - - '**/tests/clapi_export/**' - - '**/www/!(front_src)/**' - - '**/doc/API/**' - has_features_changes: - - '**/tests/e2e/**/*.feature' - token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - - gherkin-lint: - runs-on: ubuntu-22.04 - needs: [changes] - if: ${{ needs.changes.outputs.has_features_changes == 'true' }} - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/gherkin-lint - with: - features_path: centreon/tests/e2e/features - - dispatch-to-maintained-branches: - if: ${{ github.event_name == 'schedule' && github.ref_name == 'develop' }} - runs-on: ubuntu-22.04 - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - run: | - NIGHTLY_TARGETS=("dev-22.10.x" "dev-23.04.x" "dev-23.10.x" "dev-24.04.x") - for target in ${NIGHTLY_TARGETS[@]}; do - echo "[INFO] - Dispatching nightly run to $target branch." - gh workflow run web.yml -r "$target" -f is_nightly=true - done - shell: bash - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - get-version: - uses: ./.github/workflows/get-version.yml - with: - version_file: centreon/www/install/insertBaseConf.sql - - veracode-analysis: - needs: [get-version] - uses: ./.github/workflows/veracode-analysis.yml - with: - module_directory: centreon - module_name: centreon-web - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - secrets: - veracode_api_id: ${{ secrets.VERACODE_API_ID_WEB }} - veracode_api_key: ${{ secrets.VERACODE_API_KEY_WEB_2 }} - veracode_srcclr_token: ${{ secrets.VERACODE_SRCCLR_TOKEN }} - jira_base_url: ${{ secrets.JIRA_BASE_URL }} - jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} - jira_api_token: ${{ secrets.XRAY_JIRA_TOKEN }} - - frontend-web-build: - needs: [get-version] - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/frontend-build - with: - base_directory: ${{ env.base_directory }} - dependencies_lock_file: ${{ env.base_directory }}/pnpm-lock.yaml - index_file: ${{ env.base_directory }}/www/index.html - static_directory: ${{ env.base_directory }}/www/static - index_cache_key: ${{ github.sha }}-${{ github.run_id }}-index - static_cache_key: ${{ github.sha }}-${{ github.run_id }}-static - build_command: pnpm centreon:build - - frontend-widgets-build: - needs: [get-version] - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/frontend-build - with: - base_directory: ${{ env.widgets_directory }} - dependencies_lock_file: ${{ env.base_directory }}/pnpm-lock.yaml - static_directory: ${{ env.widgets_directory }}/src - static_cache_key: ${{ github.sha }}-${{ github.run_id }}-widgets-static - - backend-dependencies: - needs: [get-version] - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/backend-dependencies - with: - base_directory: ${{ env.base_directory }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-vendor - - translation-build: - needs: [get-version] - - runs-on: ubuntu-22.04 - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/translation:${{ needs.get-version.outputs.major_version }} - credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - run: | - cd centreon - mkdir -p www/locale/en_US.UTF-8/LC_MESSAGES - php bin/centreon-translations.php en lang/fr_FR.UTF-8/LC_MESSAGES/messages.po www/locale/en_US.UTF-8/LC_MESSAGES/messages.ser - for i in lang/* ; do - localefull=`basename $i` - langcode=`echo $localefull | cut -d _ -f 1` - mkdir -p "www/locale/$localefull/LC_MESSAGES" - msgfmt "lang/$localefull/LC_MESSAGES/messages.po" -o "www/locale/$localefull/LC_MESSAGES/messages.mo" || exit 1 - msgfmt "lang/$localefull/LC_MESSAGES/help.po" -o "www/locale/$localefull/LC_MESSAGES/help.mo" || exit 1 - php bin/centreon-translations.php "$langcode" "lang/$localefull/LC_MESSAGES/messages.po" "www/locale/$localefull/LC_MESSAGES/messages.ser" - done - shell: bash - - - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: ${{ env.base_directory }}/www/locale - key: ${{ github.sha }}-${{ github.run_id }}-translation - - frontend-web-lint: - runs-on: ubuntu-22.04 - needs: [changes, get-version] - if: ${{ needs.changes.outputs.has_frontend_changes == 'true' && needs.get-version.outputs.stability != 'stable' }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: ./.github/actions/frontend-lint - with: - frontend_directory: ${{ env.base_directory }} - module_name: centreon - dependencies_lock_file: ${{ env.base_directory }}/pnpm-lock.yaml - - frontend-widgets-lint: - runs-on: ubuntu-22.04 - needs: [changes, get-version] - if: ${{ needs.changes.outputs.has_frontend_changes == 'true' && needs.get-version.outputs.stability != 'stable' }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: ./.github/actions/frontend-lint - with: - frontend_directory: ${{ env.widgets_directory }} - module_name: centreon-widgets - dependencies_lock_file: ${{ env.base_directory }}/pnpm-lock.yaml - - frontend-unit-test: - runs-on: ubuntu-22.04 - needs: [changes, get-version] - if: ${{ needs.changes.outputs.has_frontend_changes == 'true' && needs.get-version.outputs.stability != 'stable' }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 - with: - version: 8 - run_install: false - - - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 - with: - node-version: 20 - cache: pnpm - cache-dependency-path: ${{ env.base_directory }}/pnpm-lock.yaml - - - name: Install dependencies - run: pnpm install --frozen-lockfile - working-directory: centreon - env: - CYPRESS_INSTALL_BINARY: "0" - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" - PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true" - - - name: Unit test - run: pnpm t --silent --reporter=jest-junit - working-directory: centreon - - - if: failure() - uses: ./.github/actions/publish-report - with: - path: "centreon/junit.xml" - - frontend-component-test: - needs: [changes, get-version] - if: ${{ needs.changes.outputs.has_frontend_changes == 'true' && needs.get-version.outputs.stability != 'stable' }} - uses: ./.github/workflows/cypress-component-parallelization.yml - with: - name: component - module_name: centreon - specs_path: www/** - dependencies_lock_file: centreon/pnpm-lock.yaml - - backend-unit-test: - runs-on: ubuntu-22.04 - needs: [changes, get-version] - if: ${{ needs.changes.outputs.has_backend_changes == 'true' && needs.get-version.outputs.stability != 'stable' }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Setup PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 - with: - php-version: 8.1 - coverage: none - env: - runner: ubuntu-22.04 - - - name: Install dependencies - uses: ramsey/composer-install@57532f8be5bda426838819c5ee9afb8af389d51a # v3.0.0 - with: - working-directory: centreon - composer-options: "--optimize-autoloader" - - - name: Unit test - run: XDEBUG_MODE=coverage composer run-script test:ci - working-directory: centreon - - - if: failure() - uses: ./.github/actions/publish-report - with: - path: "centreon/build/phpunit.xml" - format: "php-junit" - - backend-lint: - runs-on: ubuntu-22.04 - needs: [changes, get-version] - if: ${{ needs.changes.outputs.has_backend_changes == 'true' && needs.get-version.outputs.stability != 'stable' }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Setup PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 - with: - php-version: 8.1 - coverage: none - env: - runner: ubuntu-22.04 - - - name: Install Dependencies - run: composer install --optimize-autoloader - working-directory: centreon - shell: bash - - - name: Run of php-cs-fixer with strict_type - run: vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --verbose --dry-run --diff - working-directory: centreon - - - name: Run of php-cs-fixer without strict_type - run: vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.unstrict.php --verbose --dry-run --diff - working-directory: centreon - - - name: Run of phpstan on /src at level 4 - run: vendor/bin/phpstan analyse --no-progress --level=4 --configuration=phpstan.neon - working-directory: centreon - - - name: Run of phpstan on /src/Core at level 8 + Centreon Custom Rules - run: vendor/bin/phpstan analyse --no-progress --level=8 --configuration=phpstan.core.neon - working-directory: centreon - - - name: Run of phpstan on /tests at level 2 - run: vendor/bin/phpstan analyse --no-progress --level=2 --configuration=phpstan.test.neon - working-directory: centreon - - package: - needs: - [ - gherkin-lint, - get-version, - translation-build, - backend-dependencies, - backend-lint, - backend-unit-test, - frontend-web-build, - frontend-web-lint, - frontend-widgets-build, - frontend-widgets-lint, - frontend-unit-test, - frontend-component-test, - ] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && needs.get-version.outputs.stability != 'stable' }} - - strategy: - fail-fast: false - matrix: - include: - - package_extension: rpm - image: packaging-nfpm-alma8 - distrib: el8 - - package_extension: rpm - image: packaging-nfpm-alma9 - distrib: el9 - - package_extension: deb - image: packaging-nfpm-bullseye - distrib: bullseye - - package_extension: deb - image: packaging-nfpm-bookworm - distrib: bookworm - - package_extension: deb - image: packaging-nfpm-jammy - distrib: jammy - - runs-on: ubuntu-22.04 - - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} - credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - name: package ${{ matrix.distrib }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Restore translation from cache - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: centreon/www/locale - key: ${{ github.sha }}-${{ github.run_id }}-translation - fail-on-cache-miss: true - - - name: Restore web index.html from cache - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: centreon/www/index.html - key: ${{ github.sha }}-${{ github.run_id }}-index - fail-on-cache-miss: true - - - name: Restore web frontend from cache - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: centreon/www/static - key: ${{ github.sha }}-${{ github.run_id }}-static - fail-on-cache-miss: true - - - name: Restore widget frontend from cache - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: centreon/www/widgets/src - key: ${{ github.sha }}-${{ github.run_id }}-widgets-static - fail-on-cache-miss: true - - - name: Move widgets directory - run: mv centreon/www/widgets/src/* centreon/www/widgets/ - shell: bash - - - name: Restore vendor directory from cache - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: centreon/vendor - key: ${{ github.sha }}-${{ github.run_id }}-vendor - fail-on-cache-miss: true - - - name: Set perl vendor lib path according to distrib - run: | - if [[ "${{ matrix.package_extension }}" == "deb" ]]; then - PERL_VENDORLIB="/usr/share/perl5" - else - PERL_VENDORLIB="/usr/share/perl5/vendor_perl" - fi - echo "PERL_VENDORLIB=$PERL_VENDORLIB" >> $GITHUB_ENV - shell: bash - - - name: Create centreon web configuration file - run: mv centreon/config/centreon.config.php.template centreon/config/centreon.config.php - shell: bash - - - name: Remove compilation related files - run: | - rm -rf centreon/www/front_src - rm -rf centreon/www/widgets/src - find centreon/www/widgets/ -maxdepth 1 -type f ! -name "*.php" ! -name "*.ts" -delete - shell: bash - - - name: Replace macros in source code - run: | - MACRO_REPLACEMENT_FILE="centreon/packaging/src/centreon-macroreplacement.txt" - if [[ "${{ matrix.package_extension }}" == "rpm" ]]; then - APACHE_USER="apache" - else - APACHE_USER="www-data" - fi - echo "s#@WEB_USER@#$APACHE_USER#g" >> $MACRO_REPLACEMENT_FILE - - find ./centreon -type f -not -path "./vendor/*" | grep -v $MACRO_REPLACEMENT_FILE | xargs --delimiter='\n' sed -i -f $MACRO_REPLACEMENT_FILE - shell: bash - - - name: Generate selinux binaries - if: ${{ matrix.package_extension == 'rpm' }} - run: | - cd centreon/selinux - sed -i "s/@VERSION@/${{ needs.get-version.outputs.major_version }}.${{ needs.get-version.outputs.minor_version }}/g" *.te - make -f /usr/share/selinux/devel/Makefile - shell: bash - - - name: Remove selinux packaging files on debian - if: ${{ matrix.package_extension == 'deb' }} - run: rm -f centreon/packaging/*-selinux.yaml - shell: bash - - - name: Package Centreon - uses: ./.github/actions/package-nfpm - with: - nfpm_file_pattern: "centreon/packaging/*.yaml" - distrib: ${{ matrix.distrib }} - package_extension: ${{ matrix.package_extension }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - release: ${{ needs.get-version.outputs.release }} - arch: all - commit_hash: ${{ github.sha }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} - rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} - rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} - rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} - stability: ${{ needs.get-version.outputs.stability }} - - dockerize: - runs-on: ubuntu-22.04 - needs: [get-version, package] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && needs.get-version.outputs.stability != 'stable' }} - - env: - project: centreon-web - strategy: - fail-fast: false - matrix: - os: ${{ fromJson(needs.get-version.outputs.dockerize_matrix) }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Generate information according to matrix os - id: matrix_include - run: | - if [ "${{ matrix.os }}" = "alma8" ]; then - DISTRIB=el8 - PACKAGE_EXTENSION=rpm - elif [ "${{ matrix.os }}" = "alma9" ]; then - DISTRIB=el9 - PACKAGE_EXTENSION=rpm - elif [ "${{ matrix.os }}" = "bullseye" ]; then - DISTRIB=bullseye - PACKAGE_EXTENSION=deb - elif [ "${{ matrix.os }}" = "bookworm" ]; then - DISTRIB=bookworm - PACKAGE_EXTENSION=deb - elif [ "${{ matrix.os }}" = "jammy" ]; then - DISTRIB=jammy - PACKAGE_EXTENSION=deb - else - echo "::error::${{ matrix.os }} is not managed" - exit 1 - fi - - echo "distrib=$DISTRIB" >> $GITHUB_OUTPUT - echo "package_extension=$PACKAGE_EXTENSION" >> $GITHUB_OUTPUT - shell: bash - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - - name: Restore ${{ steps.matrix_include.outputs.package_extension }} files - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: ./*.${{ steps.matrix_include.outputs.package_extension }} - key: ${{ github.sha }}-${{ github.run_id }}-${{ steps.matrix_include.outputs.package_extension }}-${{ steps.matrix_include.outputs.distrib }} - fail-on-cache-miss: true - - - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - - - name: Build web image - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 - with: - file: .github/docker/${{ env.project }}/${{ matrix.os }}/Dockerfile - context: . - build-args: | - "REGISTRY_URL=${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}" - "VERSION=${{ needs.get-version.outputs.major_version }}" - pull: true - load: true - tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.project }}-${{ matrix.os }}:${{ github.head_ref || github.ref_name }} - - - name: Push web image - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 - with: - file: .github/docker/${{ env.project }}/${{ matrix.os }}/Dockerfile - context: . - build-args: | - "REGISTRY_URL=${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}" - "VERSION=${{ needs.get-version.outputs.major_version }}" - pull: false - push: true - tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.project }}-${{ matrix.os }}:${{ github.head_ref || github.ref_name }} - - - name: Setup docker slim - run: curl -sL https://raw.githubusercontent.com/slimtoolkit/slim/master/scripts/install-slim.sh | sudo -E bash -s -- 1.40.11 - shell: bash - - - name: Build slim image - run: | - export WEB_IMAGE="${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.project }}-${{ matrix.os }}:${{ github.head_ref || github.ref_name }}" - sed -i '/openid:/,$d' .github/docker/docker-compose.yml # remove all services after openid - docker compose -f .github/docker/docker-compose.yml pull db - slim build \ - --compose-file .github/docker/docker-compose.yml \ - --compose-env-file .github/docker/.env \ - --target-compose-svc web \ - --show-clogs \ - --show-blogs \ - --include-shell \ - --include-new=false \ - --http-probe-off \ - --exec-file .github/docker/centreon-web/${{ matrix.os }}/slim-configuration/exec.txt \ - --include-path-file .github/docker/centreon-web/${{ matrix.os }}/slim-configuration/include-path.txt \ - --include-bin-file .github/docker/centreon-web/${{ matrix.os }}/slim-configuration/include-bin.txt \ - --path-perms-file .github/docker/centreon-web/${{ matrix.os }}/slim-configuration/path-perms.txt \ - --tag ${{ env.project }}-slim-${{ matrix.os }}:${{ github.head_ref || github.ref_name }} - docker tag ${{ env.project }}-slim-${{ matrix.os }}:${{ github.head_ref || github.ref_name }} ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.project }}-slim-${{ matrix.os }}:${{ github.head_ref || github.ref_name }} - shell: bash - - - name: Push slim image - run: docker push ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ env.project }}-slim-${{ matrix.os }}:${{ github.head_ref || github.ref_name }} - shell: bash - - - name: Store slim image in local archive - run: | - mkdir -p /tmp/cache/docker-image - docker save --output /tmp/cache/docker-image/${{ env.project }}-slim-${{ matrix.os }}.tar ${{ env.project }}-slim-${{ matrix.os }}:${{ github.head_ref || github.ref_name }} - shell: bash - - - name: Clear previous docker image from cache - run: | - curl \ - -X DELETE \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - https://api.github.com/repos/centreon/centreon/actions/caches?key=docker-image-${{ env.project }}-slim-${{ matrix.os }}-${{ github.head_ref || github.ref_name }} - shell: bash - - - name: Store slim image in cache - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: /tmp/cache/docker-image - key: docker-image-${{ env.project }}-slim-${{ matrix.os }}-${{ github.head_ref || github.ref_name }} - - newman-test: - needs: [get-version, changes, create-xray-test-plan-and-test-execution, dockerize] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && needs.changes.outputs.has_backend_changes == 'true' }} - strategy: - fail-fast: false - matrix: - os: ${{ fromJson(needs.get-version.outputs.dockerize_matrix) }} - - uses: ./.github/workflows/newman.yml - with: - collection_path: centreon/tests/rest_api/collections - image_name: centreon-web - os: ${{ matrix.os }} - container_name: my_centreon_container - centreon_url: http://localhost - centreon_image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/centreon-web-slim-${{ matrix.os }}:${{ github.head_ref || github.ref_name }} - database_image: bitnami/mariadb:10.11 - dependencies_lock_file: centreon/pnpm-lock.yaml - major_version: ${{ needs.get-version.outputs.major_version }} - stability: ${{ needs.get-version.outputs.stability }} - xray_keys_and_ids: ${{ toJson(needs.create-xray-test-plan-and-test-execution.outputs) }} - - secrets: - registry_username: ${{ secrets.DOCKER_REGISTRY_ID }} - registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - client_id: ${{ secrets.XRAY_CLIENT_ID }} - client_secret: ${{ secrets.XRAY_CLIENT_SECRET }} - jira_user: ${{ secrets.XRAY_JIRA_USER_EMAIL }} - jira_token_test: ${{ secrets.XRAY_JIRA_TOKEN }} - - api-integration-test: - needs: [get-version, changes, dockerize] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && needs.changes.outputs.has_backend_changes == 'true' && needs.get-version.outputs.stability != 'stable'}} - strategy: - fail-fast: false - matrix: - os: ${{ fromJson(needs.get-version.outputs.dockerize_matrix) }} - - uses: ./.github/workflows/behat-test.yml - with: - name: api - module_name: centreon - database_image: bitnami/mariadb:10.11 - image_name: centreon-web - os: ${{ matrix.os }} - features_path: tests/api/features - config_file: tests/api/behat.yml - secrets: - registry_username: ${{ secrets.DOCKER_REGISTRY_ID }} - registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - composer_token: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - - legacy-e2e-test: - needs: [get-version, changes, dockerize] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && needs.changes.outputs.has_backend_changes == 'true' && needs.get-version.outputs.stability != 'stable' }} - strategy: - fail-fast: false - matrix: - os: ${{ fromJson(needs.get-version.outputs.dockerize_matrix) }} - - uses: ./.github/workflows/behat-test.yml - with: - name: legacy-e2e - module_name: centreon - database_image: bitnami/mariadb:10.11 - image_name: centreon-web - os: ${{ matrix.os }} - features_path: features - secrets: - registry_username: ${{ secrets.DOCKER_REGISTRY_ID }} - registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - composer_token: ${{ secrets.CENTREON_TECHNIQUE_PAT }} - - create-xray-test-plan-and-test-execution: - needs: [get-version, dockerize] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && ( needs.get-version.outputs.stability == 'testing' || github.event_name == 'schedule' ) }} - strategy: - fail-fast: false - matrix: - os: ${{ fromJson(needs.get-version.outputs.dockerize_matrix) }} - - uses: ./.github/workflows/create-xray-test-plan-and-test-execution.yml - with: - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - os: ${{ matrix.os }} - secrets: - xray_client_id: ${{ secrets.XRAY_CLIENT_ID }} - xray_client_secret: ${{ secrets.XRAY_CLIENT_SECRET }} - xray_jira_user_email: ${{ secrets.XRAY_JIRA_USER_EMAIL }} - xray_jira_token: ${{ secrets.XRAY_JIRA_TOKEN }} - - e2e-test: - needs: [get-version, dockerize, create-xray-test-plan-and-test-execution] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && needs.get-version.outputs.stability != 'stable' }} - strategy: - fail-fast: false - matrix: - os: ${{ fromJson(needs.get-version.outputs.dockerize_matrix) }} - - uses: ./.github/workflows/cypress-e2e-parallelization.yml - with: - name: e2e - module_name: centreon - image_name: centreon-web - database_image: bitnami/mariadb:10.11 - os: ${{ matrix.os }} - features_path: tests/e2e/features - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - package_cache_key: ${{ format('{0}-{1}-{2}', github.sha, github.run_id, matrix.os == 'alma8' && 'rpm-el8' || matrix.os == 'alma9' && 'rpm-el9' || matrix.os == 'bullseye' && 'deb-bullseye' || 'deb-bookworm' ) }} - package_directory: centreon/tests/e2e/fixtures/packages - dependencies_lock_file: centreon/pnpm-lock.yaml - xray_keys_and_ids: ${{ toJson(needs.create-xray-test-plan-and-test-execution.outputs) }} - secrets: - registry_username: ${{ secrets.DOCKER_REGISTRY_ID }} - registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - xray_client_id: ${{ secrets.XRAY_CLIENT_ID }} - xray_client_secret: ${{ secrets.XRAY_CLIENT_SECRET }} - - performances-test: - runs-on: ubuntu-22.04 - needs: [get-version, dockerize] - if: ${{ !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && needs.get-version.outputs.stability != 'stable' }} - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Login to registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 - with: - registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - - name: Run Lighthouse - uses: ./.github/actions/lighthouse-performance-testing - with: - path: "centreon/lighthouse" - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/centreon-web-slim-alma9 - image_version: ${{ github.head_ref || github.ref_name }} - database_image: bitnami/mariadb:10.11 - image_lighthouse_version: ${{ needs.get-version.outputs.major_version }} - module: centreon - dependencies_lock_file: centreon/pnpm-lock.yaml - - - name: Publish report to S3 - if: ${{ github.event_name == 'push' }} - uses: ./.github/actions/lighthouse-to-s3 - with: - report_path: centreon/lighthouse/report/lighthouseci-index.html - report_target: s3://centreon-lighthouse-report/ - access_key_id: ${{ secrets.LIGHTHOUSE_ID }} - secret_access_key: ${{ secrets.LIGHTHOUSE_SECRET }} - - - name: Publish report - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 - with: - name: lighthouse-report - path: centreon/lighthouse/report/lighthouseci-index.html - retention-days: 1 - - deliver-sources: - runs-on: [self-hosted, common] - needs: - [ - get-version, - api-integration-test, - e2e-test, - performances-test, - legacy-e2e-test, - ] - if: ${{ !cancelled() && contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && github.event_name != 'workflow_dispatch' }} - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Deliver sources - uses: ./.github/actions/release-sources - with: - bucket_directory: centreon - module_directory: centreon - module_name: centreon-web - frontend_index_cache_key: ${{ github.sha }}-${{ github.run_id }}-index - frontend_index_file: centreon/www/index.html - frontend_static_cache_key: ${{ github.sha }}-${{ github.run_id }}-static - frontend_static_directory: centreon/www/static - backend_vendor_cache_key: ${{ github.sha }}-${{ github.run_id }}-vendor - backend_vendor_directory: centreon/vendor - translation_cache_key: ${{ github.sha }}-${{ github.run_id }}-translation - translation_directory: centreon/www/locale - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - token_download_centreon_com: ${{ secrets.TOKEN_DOWNLOAD_CENTREON_COM }} - - deliver-rpm: - runs-on: [self-hosted, common] - needs: - [ - get-version, - api-integration-test, - e2e-test, - performances-test, - legacy-e2e-test, - ] - if: ${{ !cancelled() && contains(fromJson('["testing", "unstable", "pkgtest"]'), needs.get-version.outputs.stability) && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} - - environment: ${{ needs.get-version.outputs.environment }} - - strategy: - matrix: - distrib: [el8, el9] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/rpm-delivery - with: - module_name: web - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - deliver-deb: - runs-on: [self-hosted, common] - needs: - [ - get-version, - api-integration-test, - e2e-test, - performances-test, - legacy-e2e-test, - ] - if: ${{ !cancelled() && contains(fromJson('["testing", "unstable", "pkgtest"]'), needs.get-version.outputs.stability) && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} - - environment: ${{ needs.get-version.outputs.environment }} - - strategy: - matrix: - distrib: [bullseye, bookworm, jammy] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/deb-delivery - with: - module_name: web - distrib: ${{ matrix.distrib }} - version: ${{ needs.get-version.outputs.major_version }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} - stability: ${{ needs.get-version.outputs.stability }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - promote: - needs: [get-version] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} - runs-on: [self-hosted, common] - strategy: - matrix: - distrib: [el8, el9, bullseye, bookworm] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Promote ${{ matrix.distrib }} to stable - uses: ./.github/actions/promote-to-stable - with: - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - module: web - distrib: ${{ matrix.distrib }} - major_version: ${{ needs.get-version.outputs.major_version }} - minor_version: ${{ needs.get-version.outputs.minor_version }} - stability: ${{ needs.get-version.outputs.stability }} - github_ref_name: ${{ github.ref_name }} - release_type: ${{ needs.get-version.outputs.release_type }} - release_cloud: ${{ needs.get-version.outputs.release_cloud }} - - deploy-platform-nightly: - needs: - [ - get-version, - api-integration-test, - e2e-test, - performances-test, - legacy-e2e-test, - deliver-rpm - ] - if: ${{ github.event_name == 'schedule' && contains(fromJson('["unstable"]'), needs.get-version.outputs.stability) }} - runs-on: [self-hosted, common] - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Trigger platform deployment - uses: ./.github/actions/nightly-platform-deploy - with: - ref: main - bu: RD - poller_number: 1 - instance_features: "Alma9 - MariaDB" - centreon_branch: develop - configured_resources: false - install_business_modules: false - instance_password: ${{ secrets.COD_NIGHTLY_INSTANCE_ADMIN_PWD }} - cod_service_token: ${{ secrets.CENTREON_TECHNIQUE_PAT }} diff --git a/.version b/.version index 271de4a125..9319064af6 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -MAJOR=24.05 +MAJOR=24.09 diff --git a/centreon-awie/www/modules/centreon-awie/conf.php b/centreon-awie/www/modules/centreon-awie/conf.php index f6f993c96f..7900601e62 100644 --- a/centreon-awie/www/modules/centreon-awie/conf.php +++ b/centreon-awie/www/modules/centreon-awie/conf.php @@ -18,7 +18,7 @@ $module_conf['centreon-awie']['rname'] = 'Centreon Api Web Import Export'; $module_conf['centreon-awie']['name'] = 'centreon-awie'; -$module_conf['centreon-awie']["mod_release"] = "24.05.0"; +$module_conf['centreon-awie']["mod_release"] = "24.09.0"; $module_conf['centreon-awie']["infos"] = "The Centreon AWIE (Application Web Import Export) module has been " . "designed to help users configure several Centreon Web platforms in a faster and easier way, thanks to its " . "import/export mechanism. @@ -32,7 +32,7 @@ $module_conf['centreon-awie']["is_removeable"] = "1"; $module_conf['centreon-awie']["author"] = "Centreon"; $module_conf['centreon-awie']["stability"] = "stable"; -$module_conf['centreon-awie']["last_update"] = "2024-04-12"; +$module_conf['centreon-awie']["last_update"] = "2024-08-27"; $module_conf['centreon-awie']["release_note"] = "https://docs.centreon.com/23.10/en/releases/centreon-os-extensions.html"; $module_conf['centreon-awie']["images"] = [ diff --git a/centreon-dsm/.version b/centreon-dsm/.version index be51a9cda2..272d3f3216 100644 --- a/centreon-dsm/.version +++ b/centreon-dsm/.version @@ -1 +1 @@ -MINOR=0 +MINOR=555 diff --git a/centreon-dsm/bin/dsmclient.pl b/centreon-dsm/bin/dsmclient.pl index 8381789056..b293d61bdd 100755 --- a/centreon-dsm/bin/dsmclient.pl +++ b/centreon-dsm/bin/dsmclient.pl @@ -15,6 +15,7 @@ package centreon::script::dsmclient; use vars qw(%dsmclient_config); + sub new { my $class = shift; my $self = $class->SUPER::new("dsmclient", diff --git a/centreon-dsm/www/modules/centreon-dsm/conf.php b/centreon-dsm/www/modules/centreon-dsm/conf.php index 9ad9837ce1..a610db8259 100644 --- a/centreon-dsm/www/modules/centreon-dsm/conf.php +++ b/centreon-dsm/www/modules/centreon-dsm/conf.php @@ -37,7 +37,7 @@ // Be Careful with internal_name, it's case sensitive (with directory module name) $module_conf['centreon-dsm']["name"] = "centreon-dsm"; $module_conf['centreon-dsm']["rname"] = "Dynamic Services Management"; -$module_conf['centreon-dsm']["mod_release"] = "24.05.0"; +$module_conf['centreon-dsm']["mod_release"] = "24.09.0"; $module_conf['centreon-dsm']["infos"] = "Centreon Dynamic Service Management (Centreon-DSM) is a module to manage " . "alarms with an event logs system. With DSM, Centreon can receive events such as SNMP traps resulting from the " . "detection of a problem and assign events dynamically to a slot defined in Centreon, like a tray events. @@ -52,7 +52,7 @@ $module_conf['centreon-dsm']["is_removeable"] = "1"; $module_conf['centreon-dsm']["author"] = "Centreon"; $module_conf['centreon-dsm']["stability"] = "stable"; -$module_conf['centreon-dsm']["last_update"] = "2024-04-12"; +$module_conf['centreon-dsm']["last_update"] = "2024-08-27"; $module_conf['centreon-dsm']["release_note"] = "https://docs.centreon.com/23.10/en/releases/centreon-os-extensions.html"; $module_conf['centreon-dsm']["images"] = [ diff --git a/centreon-gorgone/.gitignore b/centreon-gorgone/.gitignore deleted file mode 100644 index 33e72b73fd..0000000000 --- a/centreon-gorgone/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -## source script - -# temporary folder -log - diff --git a/centreon-gorgone/.version b/centreon-gorgone/.version deleted file mode 100644 index be51a9cda2..0000000000 --- a/centreon-gorgone/.version +++ /dev/null @@ -1 +0,0 @@ -MINOR=0 diff --git a/centreon-gorgone/LICENSE.txt b/centreon-gorgone/LICENSE.txt deleted file mode 100644 index dfbec9227f..0000000000 --- a/centreon-gorgone/LICENSE.txt +++ /dev/null @@ -1,190 +0,0 @@ - Copyright 2020 - Centreon - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/centreon-gorgone/README.md b/centreon-gorgone/README.md deleted file mode 100644 index 28fbfbfea1..0000000000 --- a/centreon-gorgone/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Centreon Gorgone - -Centreon Gorgone and his "gorgoned" daemon is a lightweight, distributed, modular tasks handler. - -It provides a set of actions like: - -* Execute commands -* Send files/directories, -* Schedule cron-like tasks, -* Push or execute tasks through SSH. - -The daemon can be installed on Centreon environments like Centreon Central, Remote and Poller servers. - -It uses ZeroMQ library. - -To install it follow the [Getting started](docs/getting_started.md) documentation. - -To understand the main principles of Gorgone protocol, follow the [guide](docs/guide.md). - -## Modules - -The Centreon Gorgone project encloses several built-in modules. - -See the full list [here](docs/modules.md). - -## API - -The HTTP server module exposes a RestAPI. - -See how to use it [here](docs/api.md). diff --git a/centreon-gorgone/TODO b/centreon-gorgone/TODO deleted file mode 100644 index da16b751a1..0000000000 --- a/centreon-gorgone/TODO +++ /dev/null @@ -1,2 +0,0 @@ -- gorgone-newtest: don't use centcore.cmd. use ssh system. -- Add redis backend to store logs (we could disable synclog in redis mode) diff --git a/centreon-gorgone/config/gorgoned-central-ssh.yml b/centreon-gorgone/config/gorgoned-central-ssh.yml deleted file mode 100644 index 144c3f4756..0000000000 --- a/centreon-gorgone/config/gorgoned-central-ssh.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: gorgoned-central-ssh -description: Configuration example in a SSH environment for Central server -configuration: - centreon: - database: - db_configuration: - dsn: "mysql:host=localhost;dbname=centreon" - username: centreon - password: centreon - db_realtime: - dsn: "mysql:host=localhost;dbname=centreon_storage" - username: centreon - password: centreon - gorgone: - gorgonecore: - timeout: 50 - modules: - - name: httpserver - package: gorgone::modules::core::httpserver::hooks - enable: true - address: 0.0.0.0 - port: 8443 - ssl: true - ssl_cert_file: /etc/pki/tls/certs/server-cert.pem - ssl_key_file: /etc/pki/tls/server-key.pem - auth: - enabled: true - user: admin - password: password - - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: proxy - package: gorgone::modules::core::proxy::hooks - enable: true - - - name: nodes - package: gorgone::modules::centreon::nodes::hooks - enable: true - - - name: legacycmd - package: gorgone::modules::centreon::legacycmd::hooks - enable: true - cmd_file: "/var/lib/centreon/centcore.cmd" - cache_dir: "/var/cache/centreon/" - cache_dir_trap: "/etc/snmp/centreon_traps/" - remote_dir: "/var/cache/centreon/config/remote-data/" - - - name: engine - package: gorgone::modules::centreon::engine::hooks - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" diff --git a/centreon-gorgone/config/gorgoned-central-zmq.yml b/centreon-gorgone/config/gorgoned-central-zmq.yml deleted file mode 100644 index a7a0c1d12e..0000000000 --- a/centreon-gorgone/config/gorgoned-central-zmq.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: gorgoned-central-zmq -description: Configuration example in a full ZMQ environment for Central server -configuration: - centreon: - database: - db_configuration: - dsn: "mysql:host=localhost;dbname=centreon" - username: centreon - password: centreon - db_realtime: - dsn: "mysql:host=localhost;dbname=centreon_storage" - username: centreon - password: centreon - gorgone: - gorgonecore: - id: 1 - privkey: keys/central/privkey.pem - # can be: always, first (default), strict - fingerprint_mode: first - fingerprint_mgr: - package: gorgone::class::fingerprint::backend::sql - # if unset, it uses global configuration - #gorgone_db_type: - #gorgone_db_name: - modules: - - name: httpserver - package: gorgone::modules::core::httpserver::hooks - enable: true - address: 0.0.0.0 - port: 8443 - ssl: true - ssl_cert_file: /etc/pki/tls/certs/server-cert.pem - ssl_key_file: /etc/pki/tls/server-key.pem - auth: - enabled: true - user: admin - password: password - allowed_hosts: - enabled: true - subnets: - - 127.0.0.1/32 - - 10.30.2.0/16 - - - name: cron - package: gorgone::modules::core::cron::hooks - enable: true - cron: - - id: echo_date - timespec: "* * * * *" - action: COMMAND - parameters: - command: "date >> /tmp/date.log" - timeout: 10 - - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: proxy - package: gorgone::modules::core::proxy::hooks - enable: true - - - name: register - package: gorgone::modules::core::register::hooks - enable: true - config_file: config/registernodes-central.yml - - - name: legacycmd - package: gorgone::modules::centreon::legacycmd::hooks - enable: true - cmd_file: "/var/lib/centreon/centcore.cmd" - cache_dir: "/var/cache/centreon/" - cache_dir_trap: "/etc/snmp/centreon_traps/" - remote_dir: "/var/cache/centreon/config/remote-data/" - - - name: engine - package: gorgone::modules::centreon::engine::hooks - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" diff --git a/centreon-gorgone/config/gorgoned-poller.yml b/centreon-gorgone/config/gorgoned-poller.yml deleted file mode 100644 index 735e864311..0000000000 --- a/centreon-gorgone/config/gorgoned-poller.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: gorgoned-poller -description: Configuration example in a full ZMQ environment for Poller server -configuration: - gorgone: - gorgonecore: - id: 2 - external_com_type: tcp - external_com_path: "*:5556" - privkey: keys/poller/privkey.pem - authorized_clients: - - key: pnI6EWkiTbazjikJXRkLmjml5wvVECYtQduJUjS4QK4 - modules: - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: engine - package: gorgone::modules::centreon::engine::hooks - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" diff --git a/centreon-gorgone/config/gorgoned-remote-ssh.yml b/centreon-gorgone/config/gorgoned-remote-ssh.yml deleted file mode 100644 index fea645f45a..0000000000 --- a/centreon-gorgone/config/gorgoned-remote-ssh.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: gorgoned-remote-ssh -description: Configuration example in a SSH environment for Remote server -configuration: - centreon: - database: - db_configuration: - dsn: "mysql:host=localhost;dbname=centreon" - username: centreon - password: centreon - db_realtime: - dsn: "mysql:host=localhost;dbname=centreon_storage" - username: centreon - password: centreon - gorgone: - gorgonecore: - timeout: 50 - modules: - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: proxy - package: gorgone::modules::core::proxy::hooks - enable: true - - - name: nodes - package: gorgone::modules::centreon::nodes::hooks - enable: true - - - name: legacycmd - package: gorgone::modules::centreon::legacycmd::hooks - enable: true - cmd_file: "/var/lib/centreon/centcore.cmd" - cache_dir: "/var/cache/centreon/" - cache_dir_trap: "/etc/snmp/centreon_traps/" - remote_dir: "/var/cache/centreon/config/remote-data/" - - - name: engine - package: gorgone::modules::centreon::engine::hooks - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" diff --git a/centreon-gorgone/config/gorgoned-remote-zmq.yml b/centreon-gorgone/config/gorgoned-remote-zmq.yml deleted file mode 100644 index 2eb9872d8f..0000000000 --- a/centreon-gorgone/config/gorgoned-remote-zmq.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: gorgoned-remote-zmq -description: Configuration example in a full ZMQ environment for Remote server -configuration: - centreon: - database: - db_configuration: - dsn: "mysql:host=localhost;dbname=centreon" - username: centreon - password: centreon - db_realtime: - dsn: "mysql:host=localhost;dbname=centreon_storage" - username: centreon - password: centreon - gorgone: - gorgonecore: - id: 4 - external_com_type: tcp - external_com_path: "*:5556" - privkey: keys/central/privkey.pem - authorized_clients: - - key: pnI6EWkiTbazjikJXRkLmjml5wvVECYtQduJUjS4QK4 - modules: - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: proxy - package: gorgone::modules::core::proxy::hooks - enable: true - - - name: register - package: gorgone::modules::core::register::hooks - enable: true - config_file: config/registernodes-remote.yml - - - name: legacycmd - package: gorgone::modules::centreon::legacycmd::hooks - enable: true - cmd_file: "/var/lib/centreon/centcore.cmd" - cache_dir: "/var/cache/centreon/" - cache_dir_trap: "/etc/snmp/centreon_traps/" - remote_dir: "/var/cache/centreon/config/remote-data/" - - - name: engine - package: gorgone::modules::centreon::engine::hooks - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" diff --git a/centreon-gorgone/config/logrotate/gorgoned b/centreon-gorgone/config/logrotate/gorgoned deleted file mode 100644 index e6f56b7475..0000000000 --- a/centreon-gorgone/config/logrotate/gorgoned +++ /dev/null @@ -1,10 +0,0 @@ -/var/log/centreon-gorgone/gorgoned.log { - copytruncate - weekly - rotate 52 - compress - delaycompress - notifempty - missingok - su root root -} diff --git a/centreon-gorgone/config/registernodes-central.yml b/centreon-gorgone/config/registernodes-central.yml deleted file mode 100644 index 5c40cd531b..0000000000 --- a/centreon-gorgone/config/registernodes-central.yml +++ /dev/null @@ -1,9 +0,0 @@ -nodes: - - id: 4 - type: push_zmq - address: 10.30.2.135 - port: 5556 - prevail: 1 - nodes: - - id: 2 - pathscore: 1 diff --git a/centreon-gorgone/config/registernodes-remote.yml b/centreon-gorgone/config/registernodes-remote.yml deleted file mode 100644 index 41a0e67203..0000000000 --- a/centreon-gorgone/config/registernodes-remote.yml +++ /dev/null @@ -1,5 +0,0 @@ -nodes: - - id: 2 - type: push_zmq - address: 10.30.2.90 - port: 5556 diff --git a/centreon-gorgone/config/systemd/gorgoned-sysconfig b/centreon-gorgone/config/systemd/gorgoned-sysconfig deleted file mode 100644 index 3ee7e99a48..0000000000 --- a/centreon-gorgone/config/systemd/gorgoned-sysconfig +++ /dev/null @@ -1,4 +0,0 @@ -# Configuration file for Centreon Gorgone. - -# OPTIONS for the daemon launch -OPTIONS="--config=/etc/centreon-gorgone/config.yaml --logfile=/var/log/centreon-gorgone/gorgoned.log --severity=error" diff --git a/centreon-gorgone/config/systemd/gorgoned.deb.service b/centreon-gorgone/config/systemd/gorgoned.deb.service deleted file mode 100644 index 46aef41c17..0000000000 --- a/centreon-gorgone/config/systemd/gorgoned.deb.service +++ /dev/null @@ -1,33 +0,0 @@ -## -## Copyright 2019-2020 Centreon -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## -## For more information : contact@centreon.com -## - -[Unit] -Description=Centreon Gorgone -PartOf=centreon.service -After=centreon.service -ReloadPropagatedFrom=centreon.service - -[Service] -EnvironmentFile=/etc/default/gorgoned -ExecStart=/usr/bin/perl /usr/bin/gorgoned $OPTIONS -Type=simple -User=centreon-gorgone - -[Install] -WantedBy=multi-user.target -WantedBy=centreon.service diff --git a/centreon-gorgone/config/systemd/gorgoned.rpm.service b/centreon-gorgone/config/systemd/gorgoned.rpm.service deleted file mode 100644 index aec4c1efed..0000000000 --- a/centreon-gorgone/config/systemd/gorgoned.rpm.service +++ /dev/null @@ -1,33 +0,0 @@ -## -## Copyright 2019-2020 Centreon -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## -## For more information : contact@centreon.com -## - -[Unit] -Description=Centreon Gorgone -PartOf=centreon.service -After=centreon.service -ReloadPropagatedFrom=centreon.service - -[Service] -EnvironmentFile=/etc/sysconfig/gorgoned -ExecStart=/usr/bin/perl /usr/bin/gorgoned $OPTIONS -Type=simple -User=centreon-gorgone - -[Install] -WantedBy=multi-user.target -WantedBy=centreon.service diff --git a/centreon-gorgone/contrib/gorgone_audit.pl b/centreon-gorgone/contrib/gorgone_audit.pl deleted file mode 100644 index f6d86fa3fb..0000000000 --- a/centreon-gorgone/contrib/gorgone_audit.pl +++ /dev/null @@ -1,636 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use FindBin; -use lib "$FindBin::Bin"; -# to be launched from contrib directory -use lib "$FindBin::Bin/../"; - -gorgone::script::gorgone_audit->new()->run(); - -package gorgone::script::gorgone_audit; - -use strict; -use warnings; -use Data::Dumper; -use gorgone::standard::misc; -use gorgone::class::http::http; -use JSON::XS; - -use base qw(gorgone::class::script); - -sub new { - my $class = shift; - my $self = $class->SUPER::new('gorgone_audit', - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 0 - ); - - bless $self, $class; - $self->add_options( - 'url:s' => \$self->{url}, - 'markdown:s' => \$self->{markdown} - ); - return $self; -} - -sub init { - my $self = shift; - $self->SUPER::init(); - - $self->{url} = 'http://127.0.0.1:8085' if (!defined($self->{url}) || $self->{url} eq ''); - $self->{markdown} = 'audit.md' if (defined($self->{markdown}) && $self->{markdown} eq ''); - $self->{http} = gorgone::class::http::http->new(logger => $self->{logger}); -} - -sub json_decode { - my ($self, %options) = @_; - - my $decoded; - eval { - $decoded = JSON::XS->new->decode($options{content}); - }; - if ($@) { - $self->{logger}->writeLogError("cannot decode json response: $@"); - exit(1); - } - - return $decoded; -} - -sub schedule_audit { - my ($self) = @_; - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'POST', - hostname => '', - full_url => $self->{url} . '/api/centreon/audit/schedule', - query_form_post => '{}', - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($code) { - $self->{logger}->writeLogError("http request error"); - exit(1); - } - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{token})) { - $self->{logger}->writeLogError('cannot get token'); - exit(1); - } - - $self->{token} = $decoded->{token}; -} - -sub get_audit_log { - my ($self) = @_; - - my $progress = 0; - while (1) { - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'GET', - hostname => '', - full_url => $self->{url} . '/api/log/' . $self->{token}, - header => [ - 'Accept-Type: application/json; charset=utf-8' - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($code) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{data})) { - $self->{logger}->writeLogError("Cannot get log information"); - exit(1); - } - - my $stop = 0; - foreach (@{$decoded->{data}}) { - my $data = $self->json_decode(content => $_->{data}); - if ($_->{code} == 500 && $progress < $data->{complete}) { - $self->{logger}->writeLogInfo("audit completed: $data->{complete}\%"); - $progress = $data->{complete}; - } elsif ($_->{code} == 1) { - $self->{logger}->writeLogError("audit execution: $data->{message}"); - $stop = 1; - } elsif ($_->{code} == 2) { - $self->{audit} = $data->{audit}; - $stop = 1; - } - } - - last if ($stop == 1); - sleep(10); - } - - if (defined($self->{audit})) { - $self->{logger}->writeLogInfo("audit result: " . JSON::XS->new->encode($self->{audit})); - if (defined($self->{markdown})) { - $self->md_output(); - } - } -} - -sub md_node_system_cpu { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $cpu = <<"END_CPU"; - - Cpu - -END_CPU - - if ($options{entry}->{status_code} != 0) { - my $message = '_**Error:** cannot get informations ' . $options{entry}->{status_message}; - $cpu .= <<"END_CPU"; - - $message - -END_CPU - return $cpu; - } - - my $used = sprintf( - '%s/%s/%s/%s (1m/5m/15m/60m)', - defined($options{entry}->{avg_used_1min}) && $options{entry}->{avg_used_1min} =~ /\d/ ? $options{entry}->{avg_used_1min} . '%' : '-', - defined($options{entry}->{avg_used_5min}) && $options{entry}->{avg_used_5min} =~ /\d/ ? $options{entry}->{avg_used_5min} . '%' : '-', - defined($options{entry}->{avg_used_15min}) && $options{entry}->{avg_used_15min} =~ /\d/ ? $options{entry}->{avg_used_15min} . '%' : '-', - defined($options{entry}->{avg_used_60min}) && $options{entry}->{avg_used_60min} =~ /\d/ ? $options{entry}->{avg_used_60min} . '%' : '-' - ); - my $iowait = sprintf( - '%s/%s/%s/%s (1m/5m/15m/60m)', - defined($options{entry}->{avg_iowait_1min}) && $options{entry}->{avg_iowait_1min} =~ /\d/ ? $options{entry}->{avg_iowait_1min} . '%' : '-', - defined($options{entry}->{avg_iowait_5min}) && $options{entry}->{avg_iowait_5min} =~ /\d/ ? $options{entry}->{avg_iowait_5min} . '%' : '-', - defined($options{entry}->{avg_iowait_15min}) && $options{entry}->{avg_iowait_15min} =~ /\d/ ? $options{entry}->{avg_iowait_15min} . '%' : '-', - defined($options{entry}->{avg_iowait_60min}) && $options{entry}->{avg_iowait_60min} =~ /\d/ ? $options{entry}->{avg_iowait_60min} . '%' : '-' - ); - $cpu .= <<"END_CPU"; - - number of cores - $options{entry}->{num_cpu} - - - used - $used - - - iowait - $iowait - -END_CPU - - return $cpu; -} - -sub md_node_system_load { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $load = <<"END_LOAD"; - - Load - -END_LOAD - - if ($options{entry}->{status_code} != 0) { - my $message = '_**Error:** cannot get informations ' . $options{entry}->{status_message}; - $load .= <<"END_LOAD"; - - $message - -END_LOAD - return $load; - } - - $load .= <<"END_LOAD"; - - load average - $options{entry}->{load1m}/$options{entry}->{load5m}/$options{entry}->{load15m} (1m/5m/15m) - -END_LOAD - return $load; -} - -sub md_node_system_memory { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $memory = <<"END_MEMORY"; - - Memory - -END_MEMORY - - if ($options{entry}->{status_code} != 0) { - my $message = '_**Error:** cannot get informations ' . $options{entry}->{status_message}; - $memory .= <<"END_MEMORY"; - - $message - -END_MEMORY - return $memory; - } - - $memory .= <<"END_MEMORY"; - - memory total - $options{entry}->{ram_total_human} - - - memory available - $options{entry}->{ram_available_human} - - - swap total - $options{entry}->{swap_total_human} - - - swap free - $options{entry}->{swap_free_human} - -END_MEMORY - return $memory; -} - -sub md_node_system_disk { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $disk = "#### Filesystems\n\n"; - if ($options{entry}->{status_code} != 0) { - $disk .= '_**Error:** cannot get informations ' . $options{entry}->{status_message} . "\n\n"; - return $disk; - } - - $disk .= <<"END_DISK"; -| Filesystem | Type | Size | Used | Avail | Inodes | Mounted | -| :---------- | :---- | :----- | :--- | :----- | :------ | :------ | -END_DISK - - foreach my $mount (sort keys %{$options{entry}->{partitions}}) { - my $values = $options{entry}->{partitions}->{$mount}; - $disk .= <<"END_DISK"; -| $values->{filesystem} | $values->{type} | $values->{space_size_human} | $values->{space_used_human} | $values->{space_free_human} | $values->{inodes_used_percent} | $values->{mount} | -END_DISK - } - - $disk .= "\n"; - return $disk; -} - -sub md_node_system_diskio { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $diskio = "#### Disks I/O\n\n"; - if ($options{entry}->{status_code} != 0) { - $diskio .= '_**Error:** cannot get informations ' . $options{entry}->{status_message} . "\n\n"; - return $diskio; - } - - $diskio .= <<"END_DISKIO"; -| Device | Read IOPs | Write IOPs | Read Time | Write Time | -| :---------- | :--------- | :----------- | :-------- | :---------- | -END_DISKIO - - foreach my $dev (sort keys %{$options{entry}->{partitions}}) { - my $values = $options{entry}->{partitions}->{$dev}; - $diskio .= "| $dev | " . - sprintf( - '%s/%s/%s/%s', - defined($values->{read_iops_1min_human}) && $values->{read_iops_1min_human} =~ /\d/ ? $values->{read_iops_1min_human} : '-', - defined($values->{read_iops_5min_human}) && $values->{read_iops_5min_human} =~ /\d/ ? $values->{read_iops_5min_human} : '-', - defined($values->{read_iops_15min_human}) && $values->{read_iops_15min_human} =~ /\d/ ? $values->{read_iops_15min_human} : '-', - defined($values->{read_iops_60min_human}) && $values->{read_iops_60min_human} =~ /\d/ ? $values->{read_iops_60min_human} : '-', - ) . '| ' . - sprintf( - '%s/%s/%s/%s', - defined($values->{write_iops_1min_human}) && $values->{write_iops_1min_human} =~ /\d/ ? $values->{write_iops_1min_human} : '-', - defined($values->{write_iops_5min_human}) && $values->{write_iops_5min_human} =~ /\d/ ? $values->{write_iops_5min_human} : '-', - defined($values->{write_iops_15min_human}) && $values->{write_iops_15min_human} =~ /\d/ ? $values->{write_iops_15min_human} : '-', - defined($values->{write_iops_60min_human}) && $values->{write_iops_60min_human} =~ /\d/ ? $values->{write_iops_60min_human} : '-', - ) . '| ' . - sprintf( - '%s/%s/%s/%s', - defined($values->{read_time_1min_ms}) && $values->{read_time_1min_ms} =~ /\d/ ? $values->{read_time_1min_ms} . 'ms' : '-', - defined($values->{read_time_5min_ms}) && $values->{read_time_5min_ms} =~ /\d/ ? $values->{read_time_5min_ms} . 'ms' : '-', - defined($values->{read_time_15min_ms}) && $values->{read_time_15min_ms} =~ /\d/ ? $values->{read_time_15min_ms} . 'ms' : '-', - defined($values->{read_time_60min_ms}) && $values->{read_time_60min_ms} =~ /\d/ ? $values->{read_time_60min_ms} . 'ms' : '-' - ) . '| ' . - sprintf( - '%s/%s/%s/%s', - defined($values->{write_time_1min_ms}) && $values->{write_time_1min_ms} =~ /\d/ ? $values->{write_time_1min_ms} . 'ms' : '-', - defined($values->{write_time_5min_ms}) && $values->{write_time_5min_ms} =~ /\d/ ? $values->{write_time_5min_ms} . 'ms' : '-', - defined($values->{write_time_15min_ms}) && $values->{write_time_15min_ms} =~ /\d/ ? $values->{write_time_15min_ms} . 'ms' : '-', - defined($values->{write_time_60min_ms}) && $values->{write_time_60min_ms} =~ /\d/ ? $values->{write_time_60min_ms} . 'ms' : '-' - ) . "|\n"; - } - - $diskio .= "\n"; - return $diskio; -} - -sub md_node_centreon_packages { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $packages = "#### Packages\n\n"; - if ($options{entry}->{status_code} != 0) { - $packages .= '_**Error:** cannot get informations ' . $options{entry}->{status_message} . "\n\n"; - return $packages; - } - - $packages .= <<"END_PACKAGES"; -| Name | Version | -| :---- | :---- | -END_PACKAGES - - foreach my $entry (sort { $a->[0] cmp $b->[0] } @{$options{entry}->{list}}) { - $packages .= <<"END_PACKAGES"; -| $entry->[0] | $entry->[1] | -END_PACKAGES - } - - $packages .= "\n"; - return $packages; -} - -sub md_node_centreon_realtime { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $realtime = "#### Realtime\n\n"; - if ($options{entry}->{status_code} != 0) { - $realtime .= '_**Error:** cannot get informations ' . $options{entry}->{status_message} . "\n\n"; - return $realtime; - } - - $realtime .= <<"END_REALTIME"; -number of hosts: $options{entry}->{hosts_count} \\ -number of services: $options{entry}->{services_count} \\ -number of hostgroups: $options{entry}->{hostgroups_count} \\ -number of servicegroups: $options{entry}->{servicegroups_count} \\ -number of acl: $options{entry}->{acl_count} - -END_REALTIME - - return $realtime; -} - -sub md_node_centreon_rrd { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $rrd = "#### Rrd\n\n"; - if ($options{entry}->{status_code} != 0) { - $rrd .= '_**Error:** cannot get informations ' . $options{entry}->{status_message} . "\n\n"; - return $rrd; - } - - $rrd .= <<"END_RRD"; -number of metrics rrd: $options{entry}->{rrd_metrics_count} \\ -number of metrics rrd outdated: $options{entry}->{rrd_metrics_outdated} \\ -size of metrics rrd: $options{entry}->{rrd_metrics_human} \\ -number of status rrd: $options{entry}->{rrd_status_count} \\ -number of status rrd outdated: $options{entry}->{rrd_status_outdated} \\ -size of metrics rrd: $options{entry}->{rrd_status_human} - -END_RRD - - return $rrd; -} - -sub md_node_centreon_database { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $db = "#### Database\n\n"; - if ($options{entry}->{status_code} != 0) { - $db .= '_**Error:** cannot get informations ' . $options{entry}->{status_message} . "\n\n"; - return $db; - } - - $db .= <<"END_DATABASE"; -Total databases space used: $options{entry}->{space_used_human} \\ -Total databases space free: $options{entry}->{space_free_human} - -END_DATABASE - - $db .= <<"END_DATABASE"; -| Database | Used | Free | -| :-------- | :--- | :--- | -END_DATABASE - - foreach my $dbname (sort keys %{$options{entry}->{databases}}) { - $db .= sprintf( - '| %s | %s | %s |' . "\n", - $dbname, - $options{entry}->{databases}->{$dbname}->{space_used_human}, - $options{entry}->{databases}->{$dbname}->{space_free_human} - ); - } - - $db .= <<"END_DATABASE"; - -| Table | Engine | Used | Free | Frag | -| :-------- | :----- | :--- | :--- | :--- | -END_DATABASE - - foreach my $dbname (sort keys %{$options{entry}->{databases}}) { - foreach my $table (sort keys %{$options{entry}->{databases}->{$dbname}->{tables}}) { - $db .= sprintf( - '| %s | %s | %s | %s | %.2f%% |' . "\n", - $dbname . '.' . $table, - $options{entry}->{databases}->{$dbname}->{tables}->{$table}->{engine}, - $options{entry}->{databases}->{$dbname}->{tables}->{$table}->{space_used_human}, - $options{entry}->{databases}->{$dbname}->{tables}->{$table}->{space_free_human}, - $options{entry}->{databases}->{$dbname}->{tables}->{$table}->{frag} - ); - } - } - - $db .= "\n"; - return $db; -} - -sub md_node_centreon_pluginpacks { - my ($self, %options) = @_; - - return '' if (!defined($options{entry})); - - my $pp = "#### Plugin-Packs\n\n"; - if ($options{entry}->{status_code} != 0) { - $pp .= '_**Error:** cannot get informations ' . $options{entry}->{status_message} . "\n\n"; - return $pp; - } - - $pp .= <<"END_PP"; -| Pack installed | Version | -| :-------------- | :------ | -END_PP - - foreach my $entry (sort { $a->{slug} cmp $b->{slug} } @{$options{entry}->{installed}}) { - $pp .= <<"END_PP"; -| $entry->{slug} | $entry->{version} | -END_PP - } - - $pp .= "\n"; - return $pp; -} - -sub md_node_system { - my ($self, %options) = @_; - - my $os = defined($options{node}->{metrics}->{'system::os'}) ? $options{node}->{metrics}->{'system::os'}->{os}->{value} : '-'; - my $kernel = defined($options{node}->{metrics}->{'system::os'}) ? $options{node}->{metrics}->{'system::os'}->{kernel}->{value} : '-'; - - my $cpu = $self->md_node_system_cpu(entry => $options{node}->{metrics}->{'system::cpu'}); - my $load = $self->md_node_system_load(entry => $options{node}->{metrics}->{'system::load'}); - my $memory = $self->md_node_system_memory(entry => $options{node}->{metrics}->{'system::memory'}); - my $disks = $self->md_node_system_disk(entry => $options{node}->{metrics}->{'system::disk'}); - my $disks_io = $self->md_node_system_diskio(entry => $options{node}->{metrics}->{'system::diskio'}); - - $self->{md_content} .= "### System - -#### Overall - -os: $os \\ -kernel: $kernel - - -${cpu}${load}${memory} -
- -${disks}${disks_io}"; - -} - -sub md_node_centreon { - my ($self, %options) = @_; - - my $realtime = $self->md_node_centreon_realtime(entry => $options{node}->{metrics}->{'centreon::realtime'}); - my $rrd = $self->md_node_centreon_rrd(entry => $options{node}->{metrics}->{'centreon::rrd'}); - my $database = $self->md_node_centreon_database(entry => $options{node}->{metrics}->{'centreon::database'}); - my $packages = $self->md_node_centreon_packages(entry => $options{node}->{metrics}->{'centreon::packages'}); - my $pp = $self->md_node_centreon_pluginpacks(entry => $options{node}->{metrics}->{'centreon::pluginpacks'}); - - $self->{md_content} .= "### Centreon - -${realtime}${rrd}${database}${packages}${pp}"; - -} - -sub md_node { - my ($self, %options) = @_; - - $self->{md_content} .= "## " . $options{node}->{name} . "\n\n"; - if ($options{node}->{status_code} != 0) { - $self->{md_content} .= '_**Error:** cannot get informations ' . $options{node}->{status_message} . "\n\n"; - return ; - } - - $self->md_node_system(%options); - $self->md_node_centreon(%options); -} - -sub md_output { - my ($self) = @_; - - if (!open(FH, '>', $self->{markdown})) { - $self->{logger}->writeLogError("cannot open file '" . $self->{markdown} . "': $!"); - exit(1); - } - $self->{md_content} = "# Audit\n\n"; - - foreach my $node_id (sort { $self->{audit}->{nodes}->{$a}->{name} cmp $self->{audit}->{nodes}->{$b}->{name} } keys %{$self->{audit}->{nodes}}) { - $self->md_node(node => $self->{audit}->{nodes}->{$node_id}); - } - - print FH $self->{md_content}; - close FH; -} - -sub run { - my $self = shift; - - $self->SUPER::run(); - $self->schedule_audit(); - $self->get_audit_log(); -} - -__END__ - -=head1 NAME - -gorgone_audit.pl - script to execute and get audit - -=head1 SYNOPSIS - -gorgone_audit.pl [options] - -=head1 OPTIONS - -=over 8 - -=item B<--url> - -Specify the api url (default: 'http://127.0.0.1:8085'). - -=item B<--markdown> - -Markdown output format (default: 'audit.md'). - -=item B<--severity> - -Set the script log severity (default: 'info'). - -=item B<--help> - -Print a brief help message and exits. - -=back - -=head1 DESCRIPTION - -B - -=cut - diff --git a/centreon-gorgone/contrib/gorgone_config_init.pl b/centreon-gorgone/contrib/gorgone_config_init.pl deleted file mode 100644 index b570288833..0000000000 --- a/centreon-gorgone/contrib/gorgone_config_init.pl +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use FindBin; -use lib "$FindBin::Bin"; -# to be launched from contrib directory -use lib "$FindBin::Bin/../"; - -gorgone::script::gorgone_config_init->new()->run(); - -package gorgone::script::gorgone_config_init; - -use strict; -use warnings; -use gorgone::standard::misc; - -use base qw(gorgone::class::script); - -use vars qw($centreon_config); - -sub new { - my $class = shift; - my $self = $class->SUPER::new("gorgone_config_init", - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 0 - ); - - bless $self, $class; - $self->add_options( - 'centcore-config:s' => \$self->{centcore_config}, - 'gorgone-config:s' => \$self->{gorgone_config}, - ); - return $self; -} - -sub init { - my $self = shift; - $self->SUPER::init(); - - $self->{centcore_config} = '/etc/centreon/conf.pm' if (!defined($self->{centcore_config}) || $self->{centcore_config} eq ''); - $self->{gorgone_config} = '/etc/centreon-gorgone/config.yaml' if (!defined($self->{gorgone_config}) || - $self->{gorgone_config} eq ''); -} - -sub read_centcore_config { - my ($self) = @_; - - unless (my $return = do $self->{centcore_config}) { - $self->{logger}->writeLogError("couldn't parse $self->{centcore_config}: $@") if $@; - $self->{logger}->writeLogError("couldn't do $self->{centcore_config}: $!") unless defined $return; - $self->{logger}->writeLogError("couldn't run $self->{centcore_config}") unless $return; - exit(1); - } - - if (!defined($centreon_config->{VarLib})) { - $self->{logger}->writeLogError("config file doesn't look like a centcore config file"); - exit(1); - } - - $centreon_config->{VarLib} =~ s/\/$//; - if ($centreon_config->{db_host} =~ /^(.*?):(\d+)$/) { - $centreon_config->{db_host} = $1; - $centreon_config->{db_port} = $2; - } -} - -sub write_gorgone_config { - my ($self) = @_; - - my $fh; - if (!open($fh, '>', $self->{gorgone_config})) { - $self->{logger}->writeLogError("couldn't open file '$self->{gorgone_config}': $!"); - exit(1); - } - - my $db_port = ''; - if (defined($centreon_config->{db_port})) { - $db_port = ';port=' . $centreon_config->{db_port}; - } - - my $content = <<"END_FILE"; -name: gorgoned -description: Configuration init by gorgone_config_init -configuration: - centreon: - database: - db_configuration: - dsn: "mysql:host=$centreon_config->{db_host}${db_port};dbname=$centreon_config->{centreon_db}" - username: "$centreon_config->{db_user}" - password: "$centreon_config->{db_passwd}" - db_realtime: - dsn: "mysql:host=$centreon_config->{db_host}${db_port};dbname=$centreon_config->{centstorage_db}" - username: "$centreon_config->{db_user}" - password: "$centreon_config->{db_passwd}" - gorgone: - gorgonecore: - hostname: - id: - privkey: /var/lib/centreon-gorgone/.keys/rsakey.priv.pem - pubkey: /var/lib/centreon-gorgone/.keys/rsakey.pub.pem - modules: - - name: httpserver - package: gorgone::modules::core::httpserver::hooks - enable: true - address: 0.0.0.0 - port: 8085 - ssl: false - auth: - enabled: false - allowed_hosts: - enabled: true - subnets: - - 127.0.0.1/32 - - - name: cron - package: gorgone::modules::core::cron::hooks - enable: true - - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: proxy - package: gorgone::modules::core::proxy::hooks - enable: true - - - name: nodes - package: gorgone::modules::centreon::nodes::hooks - enable: true - - - name: legacycmd - package: gorgone::modules::centreon::legacycmd::hooks - enable: true - cmd_file: "$centreon_config->{VarLib}/centcore.cmd" - cache_dir: "$centreon_config->{CacheDir}" - cache_dir_trap: "/etc/snmp/centreon_traps/" - remote_dir: "$centreon_config->{CacheDir}/config/remote-data/" - - - name: engine - package: gorgone::modules::centreon::engine::hooks - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" - - - name: statistics - package: "gorgone::modules::centreon::statistics::hooks" - enable: true - broker_cache_dir: "/var/cache/centreon/broker-stats/" - cron: - - id: broker_stats - timespec: "*/5 * * * *" - action: BROKERSTATS - parameters: - timeout: 10 - - id: engine_stats - timespec: "*/5 * * * *" - action: ENGINESTATS - parameters: - timeout: 10 -END_FILE - - print $fh $content; - close($fh); -} - -sub run { - my $self = shift; - - $self->SUPER::run(); - $self->read_centcore_config(); - $self->write_gorgone_config(); - - $self->{logger}->writeLogInfo("file '$self->{gorgone_config}' created success"); -} - -__END__ - -=head1 NAME - -gorgone_config_init.pl - script to create gorgone config to replace centcore - -=head1 SYNOPSIS - -gorgone_config_init.pl [options] - -=head1 OPTIONS - -=over 8 - -=item B<--centcore-config> - -Specify the path to the centcore configuration file (default: '/etc/centreon/conf.pm'). - -=item B<--gorgone-config> - -Specify the gorgone config file created (default: '/etc/centreon-gorgone/config.yaml'). - -=item B<--severity> - -Set the script log severity (default: 'error'). - -=item B<--help> - -Print a brief help message and exits. - -=back - -=head1 DESCRIPTION - -B - -=cut - diff --git a/centreon-gorgone/contrib/gorgone_install_plugins.pl b/centreon-gorgone/contrib/gorgone_install_plugins.pl deleted file mode 100644 index 970d25f55f..0000000000 --- a/centreon-gorgone/contrib/gorgone_install_plugins.pl +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/perl -# -# Copyright 2022 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -my $plugins = []; -my $type; -if ($ARGV[0] !~ /^--type=(deb|rpm)$/) { - print "need to set option --type=[deb|rpm]\n"; - exit(1); -} -$type = $1; - -for (my $i = 1; $i < scalar(@ARGV); $i++) { - if ($ARGV[$i] =~ /^centreon-plugin-([A-Za-z\-_=0-9]+)$/) { - push @$plugins, $ARGV[$i]; - } -} - -if (scalar(@$plugins) <= 0) { - print "nothing to install\n"; - exit(0); -} - -my $command; -if ($type eq 'rpm') { - $command = 'yum -y install'; - foreach (@$plugins) { - $command .= " '" . $_ . "-*'" - } -} elsif ($type eq 'deb') { - $command = 'apt-get -y install'; - foreach (@$plugins) { - $command .= " '" . $_ . "-*'" - } -} -$command .= ' 2>&1'; - -my $output = `$command`; -if ($? == -1) { - print "failed to execute: $!\n"; - exit(1); -} elsif ($? & 127) { - printf "child died with signal %d, %s coredump\n", - ($? & 127), ($? & 128) ? 'with' : 'without'; - exit(1); -} - -my $exit = $? >> 8; -print "succeeded command (code: $exit): " . $output; -exit(0); diff --git a/centreon-gorgone/contrib/gorgone_key_generation.pl b/centreon-gorgone/contrib/gorgone_key_generation.pl deleted file mode 100644 index a7ec62bbad..0000000000 --- a/centreon-gorgone/contrib/gorgone_key_generation.pl +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/perl -use strict; -use warnings FATAL => 'all'; -use Try::Tiny; -use Crypt::PK::RSA; -use File::Basename qw( fileparse ); - -# generate key if there is none. -# Gorgone can generate it's own key, but as we need the thumbprint in the configuration we need to generate them before launching gorgone. -# this script only create key if the files don't exists, and silently finish if the files already exists. - -my ($privkey, $pubkey); - -my $priv_dest = '/var/lib/centreon-gorgone/.keys/rsakey.priv.pem'; -my $pub_dest = '/var/lib/centreon-gorgone/.keys/rsakey.pub.pem'; -$ARGV[0] and $priv_dest = $ARGV[0]; -$ARGV[1] and $pub_dest = $ARGV[1]; -if (-f $priv_dest or -f $pub_dest){ - print("files already exist, no overriding is done.\n"); - exit 0; -} -try { - my $pkrsa = Crypt::PK::RSA->new(); - $pkrsa->generate_key(256, 65537); - $pubkey = $pkrsa->export_key_pem('public_x509'); - $privkey = $pkrsa->export_key_pem('private'); -} catch { - die("Cannot generate server keys: $_\n"); -}; - -my ( $priv_key_name, $priv_folder_name ) = fileparse $priv_dest; -`mkdir -p $priv_folder_name`; -open(my $priv_fh, '>', $priv_dest) or die("failed opening $priv_dest : $!"); -print $priv_fh $privkey; -print "private key saved to file.\n"; - -my ( $pub_key_name, $pub_folder_name ) = fileparse $pub_dest; -`mkdir -p $pub_folder_name`; -open(my $pub_fh, '>', $pub_dest) or die("failed opening $pub_dest : $!"); -print $pub_fh $pubkey; -print "pub key saved to file.\n"; diff --git a/centreon-gorgone/contrib/gorgone_key_thumbprint.pl b/centreon-gorgone/contrib/gorgone_key_thumbprint.pl deleted file mode 100644 index bf7b9fdd5d..0000000000 --- a/centreon-gorgone/contrib/gorgone_key_thumbprint.pl +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use FindBin; -use lib "$FindBin::Bin"; -# to be launched from contrib directory -use lib "$FindBin::Bin/../"; - -gorgone::script::gorgone_key_thumbprint->new()->run(); - -package gorgone::script::gorgone_key_thumbprint; - -use strict; -use warnings; -use gorgone::standard::misc; -use Crypt::PK::RSA; - -use base qw(gorgone::class::script); - -sub new { - my $class = shift; - my $self = $class->SUPER::new("gorgone_key_thumbprint", - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 0 - ); - - bless $self, $class; - $self->add_options( - 'key-path:s' => \$self->{key_path}, - ); - return $self; -} - -sub init { - my $self = shift; - $self->SUPER::init(); - - $self->{key_path} = '/etc/pki/gorgone/pubkey.pem' if (!defined($self->{key_path}) || $self->{key_path} eq ''); -} - -sub read_key { - my ($self, $key_path) = @_; - - my $fh; - if (!open($fh, '<', $key_path)) { - $self->{logger}->writeLogError("Couldn't open file '$key_path': $!"); - exit(1); - } - my $content = do { local $/; <$fh> }; - close($fh); - - return $content; -} - -sub get_key_thumbprint { - my ($self, $key_string) = @_; - - my $kh; - $key_string =~ s/\\n/\n/g; - eval { - $kh = Crypt::PK::RSA->new(\$key_string); - }; - if ($@) { - $self->{logger}->writeLogError("Cannot load key: $@"); - return -1; - } - - return $kh->export_key_jwk_thumbprint('SHA256'); -} - -sub run { - my $self = shift; - - $self->SUPER::run(); - my $key = $self->read_key($self->{key_path}); - my $thumbprint = $self->get_key_thumbprint($key); - - $self->{logger}->writeLogInfo("File '$self->{key_path}' JWK thumbprint: " . $thumbprint); -} - -__END__ - -=head1 NAME - -gorgone_key_thumbprint.pl - script to get the JWK thumbprint of a RSA key. - -=head1 SYNOPSIS - -gorgone_key_thumbprint.pl [options] - -=head1 OPTIONS - -=over 8 - -=item B<--key-path> - -Specify the path to the RSA key (default: '/etc/pki/gorgone/pubkey.pem'). - -=item B<--severity> - -Set the script log severity (default: 'error'). - -=item B<--help> - -Print a brief help message and exits. - -=back - -=head1 DESCRIPTION - -B - -=cut - diff --git a/centreon-gorgone/contrib/mbi/centreonBIETL b/centreon-gorgone/contrib/mbi/centreonBIETL deleted file mode 100644 index 4e666a0f92..0000000000 --- a/centreon-gorgone/contrib/mbi/centreonBIETL +++ /dev/null @@ -1,382 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use FindBin; -use lib "$FindBin::Bin"; -# to be launched from contrib directory -use lib "$FindBin::Bin/../"; - -gorgone::script::centreonBIETL->new()->run(); - -package gorgone::script::centreonBIETL; - -use strict; -use warnings; -use Data::Dumper; -use gorgone::modules::centreon::mbi::libs::Utils; -use gorgone::standard::misc; -use gorgone::class::http::http; -use JSON::XS; - -use base qw(gorgone::class::script); - -sub new { - my $class = shift; - my $self = $class->SUPER::new( - 'centreonBIETL', - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 0 - ); - - bless $self, $class; - - $self->{moptions}->{rebuild} = 0; - $self->{moptions}->{daily} = 0; - $self->{moptions}->{import} = 0; - $self->{moptions}->{dimensions} = 0; - $self->{moptions}->{event} = 0; - $self->{moptions}->{perfdata} = 0; - $self->{moptions}->{start} = ''; - $self->{moptions}->{end} = ''; - $self->{moptions}->{create_tables} = 0; - $self->{moptions}->{ignore_databin} = 0; - $self->{moptions}->{centreon_only} = 0; - $self->{moptions}->{nopurge} = 0; - - $self->add_options( - 'url:s' => \$self->{url}, - 'status' => \$self->{status}, - 'r' => \$self->{moptions}->{rebuild}, - 'd' => \$self->{moptions}->{daily}, - 'I' => \$self->{moptions}->{import}, - 'D' => \$self->{moptions}->{dimensions}, - 'E' => \$self->{moptions}->{event}, - 'P' => \$self->{moptions}->{perfdata}, - 's:s' => \$self->{moptions}->{start}, - 'e:s' => \$self->{moptions}->{end}, - 'c' => \$self->{moptions}->{create_tables}, - 'i' => \$self->{moptions}->{ignore_databin}, - 'C' => \$self->{moptions}->{centreon_only}, - 'p' => \$self->{moptions}->{nopurge} - ); - return $self; -} - -sub init { - my $self = shift; - $self->SUPER::init(); - - $self->{url} = 'http://127.0.0.1:8085' if (!defined($self->{url}) || $self->{url} eq ''); - $self->{http} = gorgone::class::http::http->new(logger => $self->{logger}); - - return if (defined($self->{status})); - - my $utils = gorgone::modules::centreon::mbi::libs::Utils->new($self->{logger}); - if ($utils->checkBasicOptions($self->{moptions}) == 1) { - exit(1); - } - - if ($self->{moptions}->{create_tables} == 0 && - $self->{moptions}->{import} == 0 && - $self->{moptions}->{dimensions} == 0 && - $self->{moptions}->{event} == 0 && - $self->{moptions}->{perfdata} == 0) { - $self->{moptions}->{import} = 1; - $self->{moptions}->{dimensions} = 1; - $self->{moptions}->{event} = 1; - $self->{moptions}->{perfdata} = 1; - } -} - -sub json_decode { - my ($self, %options) = @_; - - my $decoded; - eval { - $decoded = JSON::XS->new->decode($options{content}); - }; - if ($@) { - $self->{logger}->writeLogError("cannot decode json response: $@"); - exit(1); - } - - return $decoded; -} - -sub run_etl { - my ($self) = @_; - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'POST', - hostname => '', - full_url => $self->{url} . '/api/centreon/mbietl/run', - query_form_post => JSON::XS->new->encode($self->{moptions}), - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{token})) { - $self->{logger}->writeLogError('cannot get token'); - exit(1); - } - - $self->{token} = $decoded->{token}; -} - -sub display_messages { - my ($self, %options) = @_; - - if (defined($options{data}->{messages})) { - foreach (@{$options{data}->{messages}}) { - if ($_->[0] eq 'D') { - $self->{logger}->writeLogDebug($_->[1]) - } elsif ($_->[0] eq 'I') { - $self->{logger}->writeLogInfo($_->[1]); - } elsif ($_->[0] eq 'E') { - $self->{logger}->writeLogError($_->[1]); - } - } - } -} - -sub get_etl_log { - my ($self) = @_; - - my $log_id; - while (1) { - my $get_param = []; - if (defined($log_id)) { - $get_param = ['id=' . $log_id]; - } - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'GET', - hostname => '', - full_url => $self->{url} . '/api/log/' . $self->{token}, - get_param => $get_param, - header => [ - 'Accept-Type: application/json; charset=utf-8' - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{data})) { - $self->{logger}->writeLogError("Cannot get log information"); - exit(1); - } - - my $stop = 0; - foreach (@{$decoded->{data}}) { - my $data = $self->json_decode(content => $_->{data}); - next if (defined($log_id) && $log_id >= $_->{id}); - $log_id = $_->{id}; - - if ($_->{code} == 600) { - $self->display_messages(data => $data); - } elsif ($_->{code} == 1) { - $self->display_messages(data => $data); - $stop = 1; - } elsif ($_->{code} == 2) { - $self->display_messages(data => $data); - $stop = 1; - } - } - - last if ($stop == 1); - sleep(2); - } -} - -sub get_etl_status { - my ($self) = @_; - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'GET', - hostname => '', - full_url => $self->{url} . '/api/centreon/mbietl/status', - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{token})) { - $self->{logger}->writeLogError('cannot get token'); - exit(1); - } - - my $token = $decoded->{token}; - my $log_id; - my $result; - - while (1) { - my $get_param = []; - if (defined($log_id)) { - $get_param = ['id=' . $log_id]; - } - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'GET', - hostname => '', - full_url => $self->{url} . '/api/log/' . $token, - get_param => $get_param, - header => [ - 'Accept-Type: application/json; charset=utf-8' - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{data})) { - $self->{logger}->writeLogError("Cannot get log information"); - exit(1); - } - - my $stop = 0; - foreach (@{$decoded->{data}}) { - my $data = $self->json_decode(content => $_->{data}); - next if (defined($log_id) && $log_id >= $_->{id}); - $log_id = $_->{id}; - - if ($_->{code} == 1) { - $self->{logger}->writeLogError('cannot get etl status'); - exit(1); - } elsif ($_->{code} == 2) { - $result = $data; - $stop = 1; - } - } - - last if ($stop == 1); - sleep(2); - } - - print "ETL status: $result->{statusStr}\n"; - if ($result->{statusStr} ne 'ready') { - print "planning: $result->{planningStr}\n"; - foreach ('import', 'dimensions', 'event', 'perfdata') { - next if (!defined($result->{sections}->{$_})); - - print " $_ status: $result->{sections}->{$_}->{statusStr}"; - if (defined($result->{sections}->{$_}->{steps_total})) { - print " ($result->{sections}->{$_}->{steps_executed}/$result->{sections}->{$_}->{steps_total})"; - } - print "\n"; - } - } -} - -sub run { - my $self = shift; - - $self->SUPER::run(); - - if (defined($self->{status})) { - $self->get_etl_status(); - } else { - $self->run_etl(); - $self->get_etl_log(); - } -} - -__END__ - -=head1 NAME - -centreonBIETL - script to execute mbi etl - -=head1 SYNOPSIS - -centreonBIETL [options] - -=head1 OPTIONS - -=over 8 - -=item B<--url> - -Specify the api url (default: 'http://127.0.0.1:8085'). - -=item B<--severity> - -Set the script log severity (default: 'info'). - -=item B<--help> - -Print a brief help message and exits. - -Execution modes - - -c Create the reporting database model - -d Daily execution to calculate statistics on yesterday - -r Rebuild mode to calculate statitics on a historical period. Can be used with: - Extra arguments for options -d and -r (if none of the following is specified, these one are selected by default: -IDEP): - -I Extract data from the monitoring server - Extra arguments for option -I: - -C Extract only Centreon configuration database only. Works with option -I. - -i Ignore perfdata extraction from monitoring server - -o Extract only perfdata from monitoring server - - -D Calculate dimensions - -E Calculate event and availability statistics - -P Calculate perfdata statistics - Common options for -rIDEP: - -s Start date in format YYYY-MM-DD. - By default, the program uses the data retention period from Centreon BI configuration - -e End date in format YYYY-MM-DD. - By default, the program uses the data retention period from Centreon BI configuration - -p Do not empty statistic tables, delete only entries for the processed period. - Does not work on raw data tables, only on Centreon BI statistics tables. - -=back - -=head1 DESCRIPTION - -B - -=cut diff --git a/centreon-gorgone/contrib/mbi/dimensionBuilder.pl b/centreon-gorgone/contrib/mbi/dimensionBuilder.pl deleted file mode 100644 index 1e81760852..0000000000 --- a/centreon-gorgone/contrib/mbi/dimensionBuilder.pl +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use FindBin; -use lib "$FindBin::Bin"; -# to be launched from contrib directory -use lib "$FindBin::Bin/../"; - -gorgone::script::dimensionsBuilder->new()->run(); - -package gorgone::script::dimensionsBuilder; - -use strict; -use warnings; -use Data::Dumper; -use gorgone::modules::centreon::mbi::libs::Utils; -use gorgone::standard::misc; -use gorgone::class::http::http; -use JSON::XS; - -use base qw(gorgone::class::script); - -sub new { - my $class = shift; - my $self = $class->SUPER::new( - 'dimensionsBuilder', - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 0 - ); - - bless $self, $class; - - $self->{moptions}->{rebuild} = 0; - $self->{moptions}->{daily} = 0; - $self->{moptions}->{import} = 0; - $self->{moptions}->{dimensions} = 1; - $self->{moptions}->{event} = 0; - $self->{moptions}->{perfdata} = 0; - $self->{moptions}->{start} = ''; - $self->{moptions}->{end} = ''; - $self->{moptions}->{nopurge} = 0; - $self->{moptions}->{centile} = 0; - - $self->add_options( - 'url:s' => \$self->{url}, - 'r|rebuild' => \$self->{moptions}->{rebuild}, - 'd|daily' => \$self->{moptions}->{daily}, - 'centile' => \$self->{moptions}->{centile}, - 'p|no-purge' => \$self->{moptions}->{nopurge} - ); - return $self; -} - -sub init { - my $self = shift; - $self->SUPER::init(); - - $self->{url} = 'http://127.0.0.1:8085' if (!defined($self->{url}) || $self->{url} eq ''); - $self->{http} = gorgone::class::http::http->new(logger => $self->{logger}); - my $utils = gorgone::modules::centreon::mbi::libs::Utils->new($self->{logger}); - if ($utils->checkBasicOptions($self->{moptions}) == 1) { - exit(1); - } -} - -sub json_decode { - my ($self, %options) = @_; - - my $decoded; - eval { - $decoded = JSON::XS->new->decode($options{content}); - }; - if ($@) { - $self->{logger}->writeLogError("cannot decode json response: $@"); - exit(1); - } - - return $decoded; -} - -sub run_etl { - my ($self) = @_; - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'POST', - hostname => '', - full_url => $self->{url} . '/api/centreon/mbietl/run', - query_form_post => JSON::XS->new->encode($self->{moptions}), - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{token})) { - $self->{logger}->writeLogError('cannot get token'); - exit(1); - } - - $self->{token} = $decoded->{token}; -} - -sub display_messages { - my ($self, %options) = @_; - - if (defined($options{data}->{messages})) { - foreach (@{$options{data}->{messages}}) { - if ($_->[0] eq 'D') { - $self->{logger}->writeLogDebug($_->[1]) - } elsif ($_->[0] eq 'I') { - $self->{logger}->writeLogInfo($_->[1]); - } elsif ($_->[0] eq 'E') { - $self->{logger}->writeLogError($_->[1]); - } - } - } -} - -sub get_etl_log { - my ($self) = @_; - - my $log_id; - while (1) { - my $get_param = []; - if (defined($log_id)) { - $get_param = ['id=' . $log_id]; - } - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'GET', - hostname => '', - full_url => $self->{url} . '/api/log/' . $self->{token}, - get_param => $get_param, - header => [ - 'Accept-Type: application/json; charset=utf-8' - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{data})) { - $self->{logger}->writeLogError("Cannot get log information"); - exit(1); - } - - my $stop = 0; - foreach (@{$decoded->{data}}) { - my $data = $self->json_decode(content => $_->{data}); - next if (defined($log_id) && $log_id >= $_->{id}); - $log_id = $_->{id}; - - if ($_->{code} == 600) { - $self->display_messages(data => $data); - } elsif ($_->{code} == 1) { - $self->display_messages(data => $data); - $stop = 1; - } elsif ($_->{code} == 2) { - $self->display_messages(data => $data); - $stop = 1; - } - } - - last if ($stop == 1); - sleep(2); - } -} - -sub run { - my $self = shift; - - $self->SUPER::run(); - $self->run_etl(); - $self->get_etl_log(); -} - -__END__ - -=head1 NAME - -dimensionsBuilder.pl - script to compute dimensions - -=head1 SYNOPSIS - -dimensionsBuilder.pl [options] - -=head1 OPTIONS - -=over 8 - -=item B<--url> - -Specify the api url (default: 'http://127.0.0.1:8085'). - -=item B<--severity> - -Set the script log severity (default: 'info'). - -=item B<--help> - -Print a brief help message and exits. - -=back - - Rebuild options: - [-r|--rebuild] : Rebuild dimensions - [--no-purge] : Do not delete previous dimensions while rebuilding - [--centile] : import only centile dimensions without deleting other dimensions - Daily run options: - [-d|--daily] - -=head1 DESCRIPTION - -B - -=cut diff --git a/centreon-gorgone/contrib/mbi/eventStatisticsBuilder.pl b/centreon-gorgone/contrib/mbi/eventStatisticsBuilder.pl deleted file mode 100644 index 6f993f5a6e..0000000000 --- a/centreon-gorgone/contrib/mbi/eventStatisticsBuilder.pl +++ /dev/null @@ -1,249 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use FindBin; -use lib "$FindBin::Bin"; -# to be launched from contrib directory -use lib "$FindBin::Bin/../"; - -gorgone::script::eventStatisticsBuilder->new()->run(); - -package gorgone::script::eventStatisticsBuilder; - -use strict; -use warnings; -use Data::Dumper; -use gorgone::modules::centreon::mbi::libs::Utils; -use gorgone::standard::misc; -use gorgone::class::http::http; -use JSON::XS; - -use base qw(gorgone::class::script); - -sub new { - my $class = shift; - my $self = $class->SUPER::new( - 'eventStatisticsBuilder', - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 0 - ); - - bless $self, $class; - - $self->{moptions}->{rebuild} = 0; - $self->{moptions}->{daily} = 0; - $self->{moptions}->{import} = 0; - $self->{moptions}->{dimensions} = 0; - $self->{moptions}->{event} = 1; - $self->{moptions}->{perfdata} = 0; - $self->{moptions}->{start} = ''; - $self->{moptions}->{end} = ''; - $self->{moptions}->{nopurge} = 0; - $self->{moptions}->{host_only} = 0; - $self->{moptions}->{service_only} = 0; - $self->{moptions}->{availability_only} = 0; - $self->{moptions}->{events_only} = 0; - - $self->add_options( - 'url:s' => \$self->{url}, - 'r|rebuild' => \$self->{moptions}->{rebuild}, - 'd|daily' => \$self->{moptions}->{daily}, - 's:s' => \$self->{moptions}->{start}, - 'e:s' => \$self->{moptions}->{end}, - 'host-only' => \$self->{moptions}->{host_only}, - 'service-only' => \$self->{moptions}->{service_only}, - 'availability-only' => \$self->{moptions}->{availability_only}, - 'events-only' => \$self->{moptions}->{events_only}, - 'no-purge' => \$self->{moptions}->{nopurge} - ); - - return $self; -} - -sub init { - my $self = shift; - $self->SUPER::init(); - - $self->{url} = 'http://127.0.0.1:8085' if (!defined($self->{url}) || $self->{url} eq ''); - $self->{http} = gorgone::class::http::http->new(logger => $self->{logger}); - my $utils = gorgone::modules::centreon::mbi::libs::Utils->new($self->{logger}); - if ($utils->checkBasicOptions($self->{moptions}) == 1) { - exit(1); - } -} - -sub json_decode { - my ($self, %options) = @_; - - my $decoded; - eval { - $decoded = JSON::XS->new->decode($options{content}); - }; - if ($@) { - $self->{logger}->writeLogError("cannot decode json response: $@"); - exit(1); - } - - return $decoded; -} - -sub run_etl { - my ($self) = @_; - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'POST', - hostname => '', - full_url => $self->{url} . '/api/centreon/mbietl/run', - query_form_post => JSON::XS->new->encode($self->{moptions}), - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{token})) { - $self->{logger}->writeLogError('cannot get token'); - exit(1); - } - - $self->{token} = $decoded->{token}; -} - -sub display_messages { - my ($self, %options) = @_; - - if (defined($options{data}->{messages})) { - foreach (@{$options{data}->{messages}}) { - if ($_->[0] eq 'D') { - $self->{logger}->writeLogDebug($_->[1]) - } elsif ($_->[0] eq 'I') { - $self->{logger}->writeLogInfo($_->[1]); - } elsif ($_->[0] eq 'E') { - $self->{logger}->writeLogError($_->[1]); - } - } - } -} - -sub get_etl_log { - my ($self) = @_; - - my $log_id; - while (1) { - my $get_param = []; - if (defined($log_id)) { - $get_param = ['id=' . $log_id]; - } - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'GET', - hostname => '', - full_url => $self->{url} . '/api/log/' . $self->{token}, - get_param => $get_param, - header => [ - 'Accept-Type: application/json; charset=utf-8' - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{data})) { - $self->{logger}->writeLogError("Cannot get log information"); - exit(1); - } - - my $stop = 0; - foreach (@{$decoded->{data}}) { - my $data = $self->json_decode(content => $_->{data}); - next if (defined($log_id) && $log_id >= $_->{id}); - $log_id = $_->{id}; - - if ($_->{code} == 600) { - $self->display_messages(data => $data); - } elsif ($_->{code} == 1) { - $self->display_messages(data => $data); - $stop = 1; - } elsif ($_->{code} == 2) { - $self->display_messages(data => $data); - $stop = 1; - } - } - - last if ($stop == 1); - sleep(2); - } -} - -sub run { - my $self = shift; - - $self->SUPER::run(); - $self->run_etl(); - $self->get_etl_log(); -} - -__END__ - -=head1 NAME - -eventStatisticsBuilder.pl - script to calculate events and availbility statistics - -=head1 SYNOPSIS - -eventStatisticsBuilder.pl [options] - -=head1 OPTIONS - -=over 8 - -=item B<--url> - -Specify the api url (default: 'http://127.0.0.1:8085'). - -=item B<--severity> - -Set the script log severity (default: 'info'). - -=item B<--help> - -Print a brief help message and exits. - -=back - - Rebuild options: - [-s|--start] [-e|--end] [-r|--rebuild] [--no-purge] - Daily run options: - [-d|--daily] - Other options:\n"; - --host-only Process only host events and availability statistics - --service-only Process only service events and availability statistics - --availability-only Build only availability statistics - --events-only Build only event statistics - -=head1 DESCRIPTION - -B - -=cut diff --git a/centreon-gorgone/contrib/mbi/importData.pl b/centreon-gorgone/contrib/mbi/importData.pl deleted file mode 100644 index 82e429c4ab..0000000000 --- a/centreon-gorgone/contrib/mbi/importData.pl +++ /dev/null @@ -1,250 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use FindBin; -use lib "$FindBin::Bin"; -# to be launched from contrib directory -use lib "$FindBin::Bin/../"; - -gorgone::script::importData->new()->run(); - -package gorgone::script::importData; - -use strict; -use warnings; -use Data::Dumper; -use gorgone::modules::centreon::mbi::libs::Utils; -use gorgone::standard::misc; -use gorgone::class::http::http; -use JSON::XS; - -use base qw(gorgone::class::script); - -sub new { - my $class = shift; - my $self = $class->SUPER::new( - 'importData', - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 0 - ); - - bless $self, $class; - - $self->{moptions}->{rebuild} = 0; - $self->{moptions}->{daily} = 0; - $self->{moptions}->{import} = 1; - $self->{moptions}->{dimensions} = 0; - $self->{moptions}->{event} = 0; - $self->{moptions}->{perfdata} = 0; - $self->{moptions}->{start} = ''; - $self->{moptions}->{end} = ''; - $self->{moptions}->{create_tables} = 0; - $self->{moptions}->{databin_only} = 0; - $self->{moptions}->{ignore_databin} = 0; - $self->{moptions}->{centreon_only} = 0; - $self->{moptions}->{nopurge} = 0; - $self->{moptions}->{bam_only} = 0; - - $self->add_options( - 'url:s' => \$self->{url}, - 'r|rebuild' => \$self->{moptions}->{rebuild}, - 'd|daily' => \$self->{moptions}->{daily}, - 's:s' => \$self->{moptions}->{start}, - 'e:s' => \$self->{moptions}->{end}, - 'c|create-tables' => \$self->{moptions}->{create_tables}, - 'databin-only' => \$self->{moptions}->{databin_only}, - 'i|ignore-databin' => \$self->{moptions}->{ignore_databin}, - 'C|centreon-only' => \$self->{moptions}->{centreon_only}, - 'p|no-purge' => \$self->{moptions}->{nopurge}, - 'bam-only' => \$self->{moptions}->{bam_only} - ); - return $self; -} - -sub init { - my $self = shift; - $self->SUPER::init(); - - $self->{url} = 'http://127.0.0.1:8085' if (!defined($self->{url}) || $self->{url} eq ''); - $self->{http} = gorgone::class::http::http->new(logger => $self->{logger}); - my $utils = gorgone::modules::centreon::mbi::libs::Utils->new($self->{logger}); - if ($utils->checkBasicOptions($self->{moptions}) == 1) { - exit(1); - } -} - -sub json_decode { - my ($self, %options) = @_; - - my $decoded; - eval { - $decoded = JSON::XS->new->decode($options{content}); - }; - if ($@) { - $self->{logger}->writeLogError("cannot decode json response: $@"); - exit(1); - } - - return $decoded; -} - -sub run_etl { - my ($self) = @_; - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'POST', - hostname => '', - full_url => $self->{url} . '/api/centreon/mbietl/run', - query_form_post => JSON::XS->new->encode($self->{moptions}), - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{token})) { - $self->{logger}->writeLogError('cannot get token'); - exit(1); - } - - $self->{token} = $decoded->{token}; -} - -sub display_messages { - my ($self, %options) = @_; - - if (defined($options{data}->{messages})) { - foreach (@{$options{data}->{messages}}) { - if ($_->[0] eq 'D') { - $self->{logger}->writeLogDebug($_->[1]) - } elsif ($_->[0] eq 'I') { - $self->{logger}->writeLogInfo($_->[1]); - } elsif ($_->[0] eq 'E') { - $self->{logger}->writeLogError($_->[1]); - } - } - } -} - -sub get_etl_log { - my ($self) = @_; - - my $log_id; - while (1) { - my $get_param = []; - if (defined($log_id)) { - $get_param = ['id=' . $log_id]; - } - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'GET', - hostname => '', - full_url => $self->{url} . '/api/log/' . $self->{token}, - get_param => $get_param, - header => [ - 'Accept-Type: application/json; charset=utf-8' - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{data})) { - $self->{logger}->writeLogError("Cannot get log information"); - exit(1); - } - - my $stop = 0; - foreach (@{$decoded->{data}}) { - my $data = $self->json_decode(content => $_->{data}); - next if (defined($log_id) && $log_id >= $_->{id}); - $log_id = $_->{id}; - - if ($_->{code} == 600) { - $self->display_messages(data => $data); - } elsif ($_->{code} == 1) { - $self->display_messages(data => $data); - $stop = 1; - } elsif ($_->{code} == 2) { - $self->display_messages(data => $data); - $stop = 1; - } - } - - last if ($stop == 1); - sleep(2); - } -} - -sub run { - my $self = shift; - - $self->SUPER::run(); - $self->run_etl(); - $self->get_etl_log(); -} - -__END__ - -=head1 NAME - -importData.pl - script to execute import centreon datas - -=head1 SYNOPSIS - -importData.pl [options] - -=head1 OPTIONS - -=over 8 - -=item B<--url> - -Specify the api url (default: 'http://127.0.0.1:8085'). - -=item B<--severity> - -Set the script log severity (default: 'info'). - -=item B<--help> - -Print a brief help message and exits. - -=back - - First run - [-c|--create-tables] - Rebuild options: - [-r|--rebuild] [--databin-only] [--centreon-only] [--ignore-databin] [--bam-only] - [-s|--start] [-e|--end] Not mandatory : if you don't use these options, the retention parameters will be taken into account - [--no-purge] Only use this mode with rebuild mode to import missing data. - This command may create duplicate entries if executed on a non appropriate period - Daily run options: - [-d|--daily] - -=head1 DESCRIPTION - -B - -=cut diff --git a/centreon-gorgone/contrib/mbi/perfdataStatisticsBuilder.pl b/centreon-gorgone/contrib/mbi/perfdataStatisticsBuilder.pl deleted file mode 100644 index da32dd6fd6..0000000000 --- a/centreon-gorgone/contrib/mbi/perfdataStatisticsBuilder.pl +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use FindBin; -use lib "$FindBin::Bin"; -# to be launched from contrib directory -use lib "$FindBin::Bin/../"; - -gorgone::script::perfdataStatisticsBuilder->new()->run(); - -package gorgone::script::perfdataStatisticsBuilder; - -use strict; -use warnings; -use Data::Dumper; -use gorgone::modules::centreon::mbi::libs::Utils; -use gorgone::standard::misc; -use gorgone::class::http::http; -use JSON::XS; - -use base qw(gorgone::class::script); - -sub new { - my $class = shift; - my $self = $class->SUPER::new( - 'perfdataStatisticsBuilder', - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 0 - ); - - bless $self, $class; - - $self->{moptions}->{rebuild} = 0; - $self->{moptions}->{daily} = 0; - $self->{moptions}->{import} = 0; - $self->{moptions}->{dimensions} = 0; - $self->{moptions}->{event} = 0; - $self->{moptions}->{perfdata} = 1; - $self->{moptions}->{start} = ''; - $self->{moptions}->{end} = ''; - $self->{moptions}->{nopurge} = 0; - $self->{moptions}->{month_only} = 0; - $self->{moptions}->{centile_only} = 0; - $self->{moptions}->{no_centile} = 0; - - $self->add_options( - 'url:s' => \$self->{url}, - 'r|rebuild' => \$self->{moptions}->{rebuild}, - 'd|daily' => \$self->{moptions}->{daily}, - 's:s' => \$self->{moptions}->{start}, - 'e:s' => \$self->{moptions}->{end}, - 'month-only' => \$self->{moptions}->{month_only}, - 'centile-only' => \$self->{moptions}->{centile_only}, - 'no-centile' => \$self->{moptions}->{no_centile}, - 'no-purge' => \$self->{moptions}->{nopurge} - ); - return $self; -} - -sub init { - my $self = shift; - $self->SUPER::init(); - - $self->{url} = 'http://127.0.0.1:8085' if (!defined($self->{url}) || $self->{url} eq ''); - $self->{http} = gorgone::class::http::http->new(logger => $self->{logger}); - my $utils = gorgone::modules::centreon::mbi::libs::Utils->new($self->{logger}); - if ($utils->checkBasicOptions($self->{moptions}) == 1) { - exit(1); - } -} - -sub json_decode { - my ($self, %options) = @_; - - my $decoded; - eval { - $decoded = JSON::XS->new->decode($options{content}); - }; - if ($@) { - $self->{logger}->writeLogError("cannot decode json response: $@"); - exit(1); - } - - return $decoded; -} - -sub run_etl { - my ($self) = @_; - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'POST', - hostname => '', - full_url => $self->{url} . '/api/centreon/mbietl/run', - query_form_post => JSON::XS->new->encode($self->{moptions}), - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{token})) { - $self->{logger}->writeLogError('cannot get token'); - exit(1); - } - - $self->{token} = $decoded->{token}; -} - -sub display_messages { - my ($self, %options) = @_; - - if (defined($options{data}->{messages})) { - foreach (@{$options{data}->{messages}}) { - if ($_->[0] eq 'D') { - $self->{logger}->writeLogDebug($_->[1]) - } elsif ($_->[0] eq 'I') { - $self->{logger}->writeLogInfo($_->[1]); - } elsif ($_->[0] eq 'E') { - $self->{logger}->writeLogError($_->[1]); - } - } - } -} - -sub get_etl_log { - my ($self) = @_; - - my $log_id; - while (1) { - my $get_param = []; - if (defined($log_id)) { - $get_param = ['id=' . $log_id]; - } - - my ($code, $content) = $self->{http}->request( - http_backend => 'curl', - method => 'GET', - hostname => '', - full_url => $self->{url} . '/api/log/' . $self->{token}, - get_param => $get_param, - header => [ - 'Accept-Type: application/json; charset=utf-8' - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL'], - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{logger}->writeLogError("Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); - exit(1); - } - - my $decoded = $self->json_decode(content => $content); - if (!defined($decoded->{data})) { - $self->{logger}->writeLogError("Cannot get log information"); - exit(1); - } - - my $stop = 0; - foreach (@{$decoded->{data}}) { - my $data = $self->json_decode(content => $_->{data}); - next if (defined($log_id) && $log_id >= $_->{id}); - $log_id = $_->{id}; - - if ($_->{code} == 600) { - $self->display_messages(data => $data); - } elsif ($_->{code} == 1) { - $self->display_messages(data => $data); - $stop = 1; - } elsif ($_->{code} == 2) { - $self->display_messages(data => $data); - $stop = 1; - } - } - - last if ($stop == 1); - sleep(2); - } -} - -sub run { - my $self = shift; - - $self->SUPER::run(); - $self->run_etl(); - $self->get_etl_log(); -} - -__END__ - -=head1 NAME - -perfdataStatisticsBuilder.pl - script to calculate perfdata statistics - -=head1 SYNOPSIS - -perfdataStatisticsBuilder.pl [options] - -=head1 OPTIONS - -=over 8 - -=item B<--url> - -Specify the api url (default: 'http://127.0.0.1:8085'). - -=item B<--severity> - -Set the script log severity (default: 'info'). - -=item B<--help> - -Print a brief help message and exits. - -=back - - Rebuild options: - [-r | --rebuild] [-s|--start] [-e|--end] [--no-purge] [--month-only] [--centile-only] [--no-centile] - Daily run options: - [-d | --daily] - -=head1 DESCRIPTION - -B - -=cut diff --git a/centreon-gorgone/contrib/mojolicious_client.pl b/centreon-gorgone/contrib/mojolicious_client.pl deleted file mode 100644 index 79c349ee3c..0000000000 --- a/centreon-gorgone/contrib/mojolicious_client.pl +++ /dev/null @@ -1,34 +0,0 @@ -use strict; -use warnings; -use Mojo::UserAgent; - -my $ua = Mojo::UserAgent->new(); -# ws or wss -$ua->websocket( - 'ws://127.0.0.1:8086/' => sub { - my ($ua, $tx) = @_; - - print "error: ", $tx->res->error->{message}, "\n" if $tx->res->error; - print 'WebSocket handshake failed!\n' and return unless $tx->is_websocket; - - $tx->on( - finish => sub { - my ($tx, $code, $reason) = @_; - print "WebSocket closed with status $code.\n"; - } - ); - $tx->on( - message => sub { - my ($tx, $msg) = @_; - print "WebSocket message: $msg\n"; - } - ); - - $tx->send({json => { username => 'admin', password => 'plop' } }); - $tx->send({json => { method => 'POST', uri => '/core/action/command', userdata => 'command1', data => [ { command => 'ls' } ] } }); - } -); -$ua->inactivity_timeout(120); -Mojo::IOLoop->start() unless (Mojo::IOLoop->is_running); - -exit(0); diff --git a/centreon-gorgone/contrib/mojolicious_server.pl b/centreon-gorgone/contrib/mojolicious_server.pl deleted file mode 100644 index 3f0c60d802..0000000000 --- a/centreon-gorgone/contrib/mojolicious_server.pl +++ /dev/null @@ -1,67 +0,0 @@ -use strict; -use warnings; -use Mojolicious::Lite; -use Mojo::Server::Daemon; -use IO::Socket::SSL; -use DateTime; - -sub sigalrm_handler -{ - printf (STDOUT "Timeout: Timeout Error Occured.\n"); - alarm(10); -} -$SIG{ALRM} = \&sigalrm_handler; - - -plugin 'basic_auth_plus'; - -my $clients = {}; - -IO::Socket::SSL::set_defaults(SSL_passwd_cb => sub { return 'secret' } ); - -websocket '/echo' => sub { - my $self = shift; - - print sprintf("Client connected: %s\n", $self->tx->connection); - my $ws_id = sprintf "%s", $self->tx->connection; - $clients->{$ws_id} = $self->tx; - - $self->on(message => sub { - my ($self, $msg) = @_; - - my $dt = DateTime->now( time_zone => 'Asia/Tokyo'); - - for (keys %$clients) { - $clients->{$_}->send({json => { - hms => $dt->hms, - text => $msg, - }}); - } - }); - - $self->on(finish => sub { - my ($self, $code, $reason) = @_; - - print "Client disconnected: $code\n"; - delete $clients->{ $self->tx->connection }; - }); -}; - -get '/' => sub { - my $self = shift; - - $self->render(json => { message => 'ok' }) - if $self->basic_auth( - "Realm Name" => { - username => 'username', - password => 'password' - } - ); -}; - -my $daemon = Mojo::Server::Daemon->new( - app => app, - listen => ["https://*:3000?reuse=1&cert=/etc/pki/tls/certs/localhost.crt&key=/etc/pki/tls/private/localhost.key"] -); -alarm(10); -$daemon->run(); diff --git a/centreon-gorgone/contrib/test-client.pl b/centreon-gorgone/contrib/test-client.pl deleted file mode 100644 index c8de55eaf2..0000000000 --- a/centreon-gorgone/contrib/test-client.pl +++ /dev/null @@ -1,187 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -use ZMQ::LibZMQ4; -use ZMQ::Constants qw(:all); -use JSON::XS; -use UUID; -use Data::Dumper; -use Sys::Hostname; -use gorgone::class::clientzmq; -use gorgone::standard::library; - -my ($client, $client2); -my $identities_token = {}; -my $stopped = {}; -my $results = {}; - -sub get_command_result { - my ($current_retries, $retries) = (0, 4); - $stopped->{$client2->{identity}} = '^(1|2)$'; - $client2->send_message( - action => 'COMMAND', data => { content => { command => 'ls /' } }, target => 100, - json_encode => 1 - ); - while (1) { - my $poll = []; - - $client2->ping(poll => $poll); - my $rev = zmq_poll($poll, 15000); - - if (defined($results->{$client2->{identity}})) { - print "The result: " . Data::Dumper::Dumper($results->{$client2->{identity}}); - last; - } - - if (!defined($rev) || $rev == 0) { - $current_retries++; - last if ($current_retries >= $retries); - - if (defined($identities_token->{$client2->{identity}})) { - # We ask a sync - print "==== send logs ===\n"; - $client2->send_message(action => 'GETLOG', target => 150, json_encode => 1); - $client2->send_message(action => 'GETLOG', token => $identities_token->{$client2->{identity}}, data => { token => $identities_token->{$client2->{identity}} }, - json_encode => 1); - } - } - - } -} - -sub read_response_result { - my (%options) = @_; - - $options{data} =~ /^\[ACK\]\s+\[(.*?)\]\s+(.*)$/m; - $identities_token->{$options{identity}} = $1; - - my $data; - eval { - $data = JSON::XS->new->utf8->decode($2); - }; - if ($@) { - return undef; - } - - if (defined($data->{data}->{action}) && $data->{data}->{action} eq 'getlog') { - if (defined($data->{data}->{result})) { - foreach my $key (keys %{$data->{data}->{result}}) { - if ($data->{data}->{result}->{$key}->{code} =~ /$stopped->{$options{identity}}/) { - $results->{$options{identity}} = $data->{data}->{result}; - last; - } - } - } - } -} - -sub read_response { - my (%options) = @_; - - print "==== PLOP = " . $options{data} . "===\n"; -} - -my ($symkey, $status, $hostname, $ciphertext); - -my $uuid; -#$uuid = 'toto'; -UUID::generate($uuid); - -#$client = gorgone::class::clientzmq->new( -# identity => 'toto', -# cipher => 'Cipher::AES', -# vector => '0123456789012345', -# server_pubkey => 'keys/central/pubkey.crt', -# client_pubkey => 'keys/poller/pubkey.crt', -# client_privkey => 'keys/poller/privkey.pem', -# target_type => 'tcp', -# target_path => '127.0.0.1:5555', -# ping => 60, -#); -#$client->init(callback => \&read_response); -$client2 = gorgone::class::clientzmq->new( - identity => 'tata', - cipher => 'Cipher::AES', - vector => '0123456789012345', - server_pubkey => 'keys/central/pubkey.crt', - client_pubkey => 'keys/poller/pubkey.crt', - client_privkey => 'keys/poller/privkey.pem', - target_type => 'tcp', - target_path => '127.0.0.1:5555' -); -$client2->init(callback => \&read_response_result); - -#$client->send_message( -# action => 'SCOMRESYNC', -# data => { container_id => 'toto' }, -# json_encode => 1 -#); -#$client->send_message(action => 'PUTLOG', data => { code => 120, etime => time(), token => 'plopplop', data => { 'nawak' => 'nawak2' } }, -# json_encode => 1); -#$client2->send_message(action => 'RELOADCRON', data => { }, -# json_encode => 1); - -# We send a request to a poller -#$client2->send_message(action => 'ENGINECOMMAND', data => { command => '[1417705150] ENABLE_HOST_CHECK;host1', engine_pipe => '/var/lib/centreon-engine/rw/centengine.cmd' }, target => 120, -# json_encode => 1); - -#$client2->send_message(action => 'COMMAND', data => { content => { command => 'ls' } }, target => 150, -# json_encode => 1); -#$client2->send_message(action => 'CONSTATUS'); -$client2->send_message( - action => 'LOADMODULE', - data => { content => { name => 'engine', package => 'gorgone::modules::centreon::engine::hooks', enable => 'true', command_file => 'plop' } }, - json_encode => 1 -); - -# It will transform -#$client2->send_message(action => 'GETLOG', data => { cmd => 'ls' }, target => 120, -# json_encode => 1); -#$client2->send_message(action => 'GETLOG', data => {}, target => 140, -# json_encode => 1); - -get_command_result(); - -#while (1) { -# my $poll = []; - -# $client->ping(poll => $poll); -# $client2->ping(poll => $poll); -# zmq_poll($poll, 5000); -#} - -while (1) { - #my $poll = [$client->get_poll(), $client2->get_poll()]; - my $poll = [$client2->get_poll()]; - -# $client->ping(poll => $poll); -# $client2->ping(poll => $poll); - zmq_poll($poll, 5000); -} - -$client->close(); -$client2->close(); -exit(0); - -#zmq_close($requester); - diff --git a/centreon-gorgone/docs/api.md b/centreon-gorgone/docs/api.md deleted file mode 100644 index 4ee643f273..0000000000 --- a/centreon-gorgone/docs/api.md +++ /dev/null @@ -1,406 +0,0 @@ -# API - -Centreon Gorgone provides a RestAPI through its HTTP server module. - -## Internal endpoints - -### Get Nodes Connection Status - -| Endpoint | Method | -| :- | :- | -| /internal/constatus | `GET` | - -#### Headers - -| Header | Value | -| :- | :- | -| Accept | application/json | - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/internal/constatus" \ - --header "Accept: application/json" -``` - -#### Response example - -```json -{ - "action": "constatus", - "data": { - "2": { - "last_ping_sent": 1579684258, - "type": "push_zmq", - "nodes": {}, - "last_ping_recv": 1579684258 - } - }, - "message": "ok" -} -``` - -### Get Public Key Thumbprint - -| Endpoint | Method | -| :- | :- | -| /internal/thumbprint | `GET` | - -#### Headers - -| Header | Value | -| :- | :- | -| Accept | application/json | - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/internal/thumbprint" \ - --header "Accept: application/json" -``` - -#### Response example - -```json -{ - "action": "getthumbprint", - "data": { - "thumbprint": "cS4B3lZq96qcP4FTMhVMuwAhztqRBQERKyhnEitnTFM" - }, - "message": "ok" -} -``` - -### Get Runtime Informations And Statistics - -| Endpoint | Method | -| :- | :- | -| /internal/information | `GET` | - -#### Headers - -| Header | Value | -| :- | :- | -| Accept | application/json | - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/internal/information" \ - --header "Accept: application/json" -``` - -#### Response example - -```json -{ - "action": "information", - "data": { - "modules": { - "httpserver": "gorgone::modules::core::httpserver::hooks", - "dbcleaner": "gorgone::modules::core::dbcleaner::hooks", - "cron": "gorgone::modules::core::cron::hooks", - "engine": "gorgone::modules::centreon::engine::hooks", - "action": "gorgone::modules::core::action::hooks", - "statistics": "gorgone::modules::centreon::statistics::hooks", - "nodes": "gorgone::modules::centreon::nodes::hooks", - "legacycmd": "gorgone::modules::centreon::legacycmd::hooks" - }, - "api_endpoints": { - "GET_/centreon/statistics/broker": "BROKERSTATS", - "GET_/internal/thumbprint": "GETTHUMBPRINT", - "GET_/core/cron/definitions": "GETCRON", - "GET_/internal/information": "INFORMATION", - "POST_/core/cron/definitions": "ADDCRON", - "POST_/core/action/command": "COMMAND", - "POST_/centreon/engine/command": "ENGINECOMMAND", - "POST_/core/proxy/remotecopy": "REMOTECOPY", - "PATCH_/core/cron/definitions": "UPDATECRON", - "DELETE_/core/cron/definitions": "DELETECRON", - "GET_/internal/constatus": "CONSTATUS" - }, - "counters": { - "external": { - "total": 0 - }, - "total": 183, - "internal": { - "legacycmdready": 1, - "statisticsready": 1, - "addcron": 1, - "cronready": 1, - "centreonnodesready": 1, - "httpserverready": 1, - "command": 51, - "putlog": 75, - "dbcleanerready": 1, - "information": 1, - "brokerstats": 8, - "total": 183, - "setcoreid": 2, - "getlog": 37, - "engineready": 1, - "actionready": 1 - }, - "proxy": { - "total": 0 - } - } - }, - "message": "ok" -} -``` - -## Modules endpoints - -The available endpoints depend on which modules are loaded. - -Endpoints are basically built from: - -* API root, -* Module's namespace, -* Module's name, -* Action - -#### Example - -```bash -curl --request POST "https://hostname:8443/api/core/action/command" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "[ - { - \"command\": \"echo 'Test command'\" - } -]" -``` - -Find more informations directly from modules documentations [here](../docs/modules.md). - -As Centreon Gorgone is asynchronous, those endpoints will return a token corresponding to the action. - -#### Example - -```json -{ - "token": "3f25bc3a797fe989d1fb052b1886a806e73fe2d8ccfc6377ee3d4490f8ad03c02cb2533edcc1b3d8e1770e28d6f2de83bd98923b66c0c33395e5f835759de4b1" -} -``` - -That being said, its possible to make Gorgone work synchronously by providing two parameters. - -First one is `log_wait` with a numeric value in microseconds: this value defines the amount of time the API will wait before trying to retrieve log results. - -Second one is `sync_wait` with a numeric value in microseconds: this value defines the amount of time the API will wait after asking for logs synchronisation if a remote node is involved. - -Note: the `sync_wait` parameter is induced if you ask for a log directly specifying a node, by using the log endpoint, and the default value is 10000 microseconds (10 milliseconds). - -#### Examples - -##### Launch a command locally and wait for the result - -Using the `/core/action/command` endpoint with `log_wait` parameter set to 100000: - -```bash -curl --request POST "https://hostname:8443/api/core/action/command&log_wait=100000" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "[ - { - \"command\": \"echo 'Test command'\" - } -]" -``` - -This call will ask for the API to execute an action and will give a result after 100ms that can be: - -* Logs, like the log endpoint could provide, -* A no_log error with a token to retrieve the logs later. - -Note: there is no need for logs synchronisation when dealing with local actions. - -##### Launch a command remotly and wait for the result - -Using the `/nodes/:id/core/action/command` endpoint with `log_wait` parameter set to 100000: - -```bash -curl --request POST "https://hostname:8443/api/nodes/2/core/action/command&log_wait=100000&sync_wait=200000" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "[ - { - \"command\": \"echo 'Test command'\" - } -]" -``` - -This call will ask for the API to execute an action on the node with ID 2, will then wait for 100ms before getting a result, but will wait for an extra 200ms for logs synchronisation before giving a result, that can be: - -* Logs, like the log endpoint could provide, -* A no_log error with a token to retrieve the logs later. - -## Log endpoint - -To retrieve the logs, a specific endpoint can be called as follow. - -| Endpoint | Method | -| :- | :- | -| /log/:token | `GET` | - -#### Headers - -| Header | Value | -| :- | :- | -| Accept | application/json | - -#### Path variables - -| Variable | Description | -| :- | :- | -| token | Token of the action | - -#### Examples - -```bash -curl --request GET "https://hostname:8443/api/log/3f25bc3a797fe989d1fb052b1886a806e73fe2d8ccfc6377ee3d4490f8ad03c02cb2533edcc1b3d8e1770e28d6f2de83bd98923b66c0c33395e5f835759de4b1" \ - --header "Accept: application/json" -``` - -```bash -curl --request GET "https://hostname:8443/api/nodes/2/log/3f25bc3a797fe989d1fb052b1886a806e73fe2d8ccfc6377ee3d4490f8ad03c02cb2533edcc1b3d8e1770e28d6f2de83bd98923b66c0c33395e5f835759de4b1" \ - --header "Accept: application/json" -``` - -This second example will force logs synchonisation before looking for results to retrieve. Default temporisation is 10ms and can be changed by providing `sync_wait` parameter. - -#### Response example - -```json -{ - "data": [ - { - "ctime": 1576083003, - "etime": 1576083003, - "id": "15638", - "instant": 0, - "data": "{\"message\":\"commands processing has started\",\"request_content\":[{\"timeout\":10,\"command\":\"echo 'Test command'\"}]}", - "token": "3f25bc3a797fe989d1fb052b1886a806e73fe2d8ccfc6377ee3d4490f8ad03c02cb2533edcc1b3d8e1770e28d6f2de83bd98923b66c0c33395e5f835759de4b1", - "code": 0 - }, - { - "ctime": 1576083003, - "etime": 1576083003, - "id": "15639", - "instant": 0, - "data": "{\"metadata\":null,\"message\":\"command has started\",\"command\":\"echo 'Test command'\"}", - "token": "3f25bc3a797fe989d1fb052b1886a806e73fe2d8ccfc6377ee3d4490f8ad03c02cb2533edcc1b3d8e1770e28d6f2de83bd98923b66c0c33395e5f835759de4b1", - "code": 0 - }, - { - "ctime": 1576083003, - "etime": 1576083003, - "id": "15640", - "instant": 0, - "data": "{\"metadata\":null,\"metrics\":{\"duration\":0,\"start\":1576083003,\"end\":1576083003},\"message\":\"command has finished\",\"command\":\"echo 'Test command'\",\"result\":{\"exit_code\":0,\"stdout\":\"Test command\"}}", - "token": "3f25bc3a797fe989d1fb052b1886a806e73fe2d8ccfc6377ee3d4490f8ad03c02cb2533edcc1b3d8e1770e28d6f2de83bd98923b66c0c33395e5f835759de4b1", - "code": 2 - }, - { - "ctime": 1576083003, - "etime": 1576083003, - "id": "15641", - "instant": 0, - "data": "{\"message\":\"commands processing has finished\"}", - "token": "3f25bc3a797fe989d1fb052b1886a806e73fe2d8ccfc6377ee3d4490f8ad03c02cb2533edcc1b3d8e1770e28d6f2de83bd98923b66c0c33395e5f835759de4b1", - "code": 2 - } - ], - "token": "3f25bc3a797fe989d1fb052b1886a806e73fe2d8ccfc6377ee3d4490f8ad03c02cb2533edcc1b3d8e1770e28d6f2de83bd98923b66c0c33395e5f835759de4b1", - "message": "Logs found" -} -``` - -## Errors - -### Unauthorized - -```json -{ - "error": "http_error_401", - "message": "unauthorized" -} -``` - -### Forbidden - -```json -{ - "error": "http_error_403", - "message": "forbidden" -} -``` - -### Unknown endpoint - -```json -{ - "error": "endpoint_unknown", - "message": "endpoint not implemented" -} -``` - -### Unknown method - -```json -{ - "error": "method_unknown", - "message": "Method not implemented" -} -``` - -### No logs for provided token - -```json -{ - "error": "no_log", - "message": "No log found for token", - "data": [], - "token": "" -} -``` - -### JSON decoding error for request - -```json -{ - "error": "decode_error", - "message": "Cannot decode response" -} -``` - -### JSON encoding error for response - -```json -{ - "error": "encode_error", - "message": "Cannot encode response" -} -``` - -### No results for internal actions - -```json -{ - "error": "no_result", - "message": "No result found for action " -} -``` - -### No token found when using wait parameter - -```json -{ - "error": "no_token", - "message": "Cannot retrieve token from ack" -} -``` diff --git a/centreon-gorgone/docs/api/centreon-logo.png b/centreon-gorgone/docs/api/centreon-logo.png deleted file mode 100755 index 5458fb678d..0000000000 Binary files a/centreon-gorgone/docs/api/centreon-logo.png and /dev/null differ diff --git a/centreon-gorgone/docs/api/gorgone-openapi.yaml b/centreon-gorgone/docs/api/gorgone-openapi.yaml deleted file mode 100644 index a7e6a203ce..0000000000 --- a/centreon-gorgone/docs/api/gorgone-openapi.yaml +++ /dev/null @@ -1,1044 +0,0 @@ -openapi: 3.0.1 -info: - title: Centreon Gorgone RestAPI - description: | - # Information - Centreon Gorgone and his "gorgoned" daemon is a lightweight, distributed, modular tasks handler. - - It provides a set of actions like: - - - Execute commands - - Send files/directories, - - Schedule cron-like tasks, - - Push or execute tasks through SSH. - - The daemon can be installed on Centreon environments like Centreon Central, Remote and Poller servers. - - It uses ZeroMQ library. - x-logo: - url: ./centreon-logo.png - contact: - url: 'https://www.centreon.com' - license: - name: Apache 2.0 - url: 'http://www.apache.org/licenses/LICENSE-2.0.html' - version: "1.0" -externalDocs: - description: You can contact us on our community Slack - url: 'https://centreon.slack.com/messages/CCRGLQSE5' -servers: - - url: '{protocol}://{server}:{port}/api' - description: "Local Gorgone instance" - variables: - protocol: - enum: - - http - - https - default: http - description: "HTTP schema" - server: - default: localhost - description: "IP address or hostname of Gorgone instance" - port: - default: '8085' - description: "Port used by HTTP server" - - url: '{protocol}://{server}:{port}/api/nodes/{id}' - description: "Remote Gorgone instance" - variables: - protocol: - enum: - - http - - https - default: http - description: "HTTP schema" - server: - default: localhost - description: "IP address or hostname of Gorgone instance" - port: - default: '8085' - description: "Port used by HTTP server" - id: - default: '1' - description: "ID of the remote Gorgone node" -tags: - - name: Internal - description: "Internal events." - - name: Logs - description: "Logs management." - - name: Cron - description: "Module aiming to reproduce a cron-like scheduler that can send events to other Gorgone modules." - - name: Action - description: "Module aiming to execute actions on the server running the Gorgone daemon or remotly using SSH." - - name: Engine - description: "Module aiming to provide a bridge to communicate with Centreon Engine daemon." - - name: Statistics - description: "Module aiming to deal with statistics collection of Centreon Engine and Broker." - - name: Autodiscovery - description: "Module aiming to extend Centreon Autodiscovery server functionalities." -security: - - Basic Authentication: [] -paths: - /internal/constatus: - get: - tags: - - Internal - summary: "Get nodes connection status" - description: "Get the connection status of all nodes managed by the Gorgone daemon." - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/NodesStatus' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /internal/information: - get: - tags: - - Internal - summary: "Get runtime informations and statistics" - description: "Get informations and statistics about loaded modules, available endpoints and number of events computed at runtime." - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Information' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /internal/thumbprint: - get: - tags: - - Internal - summary: "Get public key thumbprint" - description: "Get the thumbprint of the public key of the Gorgone daemon." - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Thumbprint' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /internal/logger: - post: - tags: - - Internal - summary: "Set logger severity level" - description: "Set the logger severity level for all modules." - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/SeverityLevel' - responses: - '204': - description: OK - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /log/{token}: - get: - tags: - - Logs - summary: "Retrieve event's logs" - description: "Retrieve the event's logs based on event's token." - parameters: - - $ref: '#/components/parameters/Token' - - $ref: '#/components/parameters/Code' - - $ref: '#/components/parameters/Limit' - - $ref: '#/components/parameters/Ctime' - - $ref: '#/components/parameters/Etime' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /core/cron/definitions: - get: - tags: - - Cron - summary: "List definitions" - description: "List all cron definitions." - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - post: - tags: - - Cron - summary: "Add definitions" - description: "Add one or multiple cron definitions to runtime." - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CronDefinitions' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /core/cron/definitions/{definition_id}: - get: - tags: - - Cron - summary: "Get a definition" - description: "List cron definition identified by id." - parameters: - - $ref: '#/components/parameters/DefinitionId' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - patch: - tags: - - Cron - summary: "Update a definition" - description: "Update a cron definition." - parameters: - - $ref: '#/components/parameters/DefinitionId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CronDefinition' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - delete: - tags: - - Cron - summary: "Delete a definition" - description: "Delete a cron definition." - parameters: - - $ref: '#/components/parameters/DefinitionId' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /core/cron/definitions/{definition_id}/status: - get: - tags: - - Cron - summary: "Get a definition status" - description: "Get a definition execution status." - parameters: - - $ref: '#/components/parameters/DefinitionId' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /core/action/command: - post: - tags: - - Action - summary: "Execute one or several command lines" - description: "Execute a command or a set of commands on server running Gorgone." - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ActionCommands' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /centreon/engine/command: - post: - tags: - - Engine - summary: "Send one or several external commands" - description: | - Send an external command or a set of external commands to a running Centreon Engine instance using command file pipe. - This method needs the commands to be preformatted as Nagios external commands format. - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/EngineCommands' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /centreon/statistics/broker: - get: - tags: - - Statistics - summary: "Launch Broker statistics collection" - description: "Launch Broker statistics collection and store the result on disk." - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /centreon/statistics/broker/{monitoring_server_id}: - get: - tags: - - Statistics - summary: "Launch Broker statistics collection of a specific monitoring server" - description: "Launch Broker statistics collection and store the result on disk." - parameters: - - $ref: '#/components/parameters/MonitoringServerId' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /centreon/autodiscovery/hosts: - post: - tags: - - Autodiscovery - summary: "Add a host discovery job" - description: "Add one Centreon Autodiscovery job to discover hosts." - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/HostDiscoveryJob' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /centreon/autodiscovery/hosts/{job_id}/schedule: - get: - tags: - - Autodiscovery - summary: "Launch a host discovery job" - description: "Launch a host discovery job identified by id (even if in cron mode)." - parameters: - - $ref: '#/components/parameters/HostDiscoveryId' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - /centreon/autodiscovery/hosts/{token}: - delete: - tags: - - Autodiscovery - summary: "Delete a host discovery job" - description: "Delete one Centreon Autodiscovery scheduled job." - parameters: - - $ref: '#/components/parameters/HostDiscoveryToken' - responses: - '200': - description: OK - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/Token' - - $ref: '#/components/schemas/Logs' - - $ref: '#/components/schemas/NoLogs' - - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' -components: - securitySchemes: - Basic Authentication: - type: http - scheme: basic - parameters: - Token: - in: path - name: token - required: true - description: "Token of the event" - schema: - type: string - example: "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165" - Code: - in: query - name: code - required: false - description: "Only retrieve logs with defined code" - schema: - type: integer - enum: [0, 1, 2] - example: 2 - Limit: - in: query - name: limit - required: false - description: "Only retrieve the last x logs" - schema: - type: integer - minimum: 1 - example: 1 - Ctime: - in: query - name: ctime - required: false - description: "Only retrieve logs with a creation time equal or superior to a timestamp" - schema: - type: integer - format: int64 - example: 1577726040 - Etime: - in: query - name: etime - required: false - description: "Only retrieve logs of an event time superior to a timestamp" - schema: - type: integer - format: int64 - example: 1577726040 - DefinitionId: - in: path - name: definition_id - required: true - description: "ID of the definition" - schema: - type: string - example: "broker_stats" - MonitoringServerId: - in: path - name: monitoring_server_id - required: true - description: "ID of the monitoring server" - schema: - type: integer - example: 2 - HostDiscoveryId: - in: path - name: job_id - required: true - description: "ID of the job" - schema: - type: integer - example: 2 - HostDiscoveryToken: - in: path - name: token - required: true - description: "Token of the scheduled job" - schema: - type: string - example: "discovery_14_6b7d1bb8" - responses: - NotFound: - description: "The specified resource was not found" - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - Unauthorized: - description: "Unauthorized" - headers: - WWW-Authenticate: - schema: - type: string - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: "Short error description" - example: "http_error_401" - message: - type: string - description: "Message explaining the error" - example: "unauthorized" - required: - - error - - message - Forbidden: - description: "Forbidden" - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: "Short error description" - example: "http_error_403" - message: - type: string - description: "Message explaining the error" - example: "forbidden" - required: - - error - - message - UnknownEndpoint: - description: "Unknown endpoint" - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: "Short error description" - example: "method_unknown" - message: - type: string - description: "Message explaining the error" - example: "Method not implemented" - required: - - error - - message - UnknownMethod: - description: "Unknown method" - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: "Short error description" - example: "endpoint_unknown" - message: - type: string - description: "Message explaining the error" - example: "endpoint not implemented" - required: - - error - - message - schemas: - Error: - type: object - properties: - error: - type: string - description: "Short error description" - message: - type: string - description: "Message explaining the error" - required: - - error - - message - Token: - type: object - properties: - token: - type: string - format: byte - description: "Token related to the event's result" - example: "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165" - Logs: - type: object - properties: - message: - type: string - description: "Additionnal message" - example: "Logs found" - token: - type: string - format: byte - description: "Token related to the event's result" - example: "03008486ba50b52e529ff5828d1432e5578dd18bb530c145b133dc902c8cfa6b8aac4d58fffb0c5ed44b943d2acbfb7cd1b18c55fcebce62e51999db460112c7" - data: - type: array - description: "Results array containing all logs related to token" - items: - $ref: '#/components/schemas/Log' - Log: - type: object - properties: - ctime: - type: string - format: timestamp - description: "Time when the server has stored the log in its database" - example: 1577727699 - etime: - type: string - format: timestamp - description: "Time when the event has occured" - example: 1577727699 - id: - type: integer - description: "ID of the event" - example: 101483 - instant: - type: integer - example: 0 - data: - type: object - description: "Data stored for this event" - token: - type: string - format: byte - description: "Token related to the event" - example: "03008486ba50b52e529ff5828d1432e5578dd18bb530c145b133dc902c8cfa6b8aac4d58fffb0c5ed44b943d2acbfb7cd1b18c55fcebce62e51999db460112c7" - code: - type: integer - description: "Returned code of the event" - example: 2 - NoLogs: - type: object - properties: - error: - type: string - description: "Short error description" - example: "no_log" - message: - type: string - description: "Message explaining the error" - example: "No log found for token" - token: - type: string - description: "Token related to the event's result" - example: "03008486ba50b52e529ff5828d1432e5578dd18bb530c145b133dc902c8cfa6b8aac4d58fffb0c5ed44b943d2acbfb7cd1b18c55fcebce62e51999db460112c7" - data: - type: array - description: "Empty array" - items: - type: object - NodesStatus: - type: object - properties: - action: - type: string - description: "Event sent to retrieve data" - example: "constatus" - message: - type: string - description: "Response message" - example: "ok" - data: - type: object - properties: - id: - $ref: '#/components/schemas/NodeStatus' - NodeStatus: - type: object - properties: - last_ping_sent: - type: string - format: timestamp - description: "Last ping sent timestamp" - example: 1577726040 - type: - type: string - enum: [push_zmq, pull_zmq, ssh] - description: "Communication type" - example: "push_zmq" - nodes: - type: object - description: "Nodes managed by this Gorgone daemon" - last_ping_recv: - type: string - format: timestamp - description: "Last ping received timestamp" - example: 1577726040 - Information: - type: object - properties: - action: - type: string - description: "Event sent to retrieve data" - example: "information" - message: - type: string - description: "Response message" - example: "ok" - data: - type: object - properties: - modules: - $ref: '#/components/schemas/Modules' - api_endpoints: - $ref: '#/components/schemas/ApiEndpoints' - counters: - $ref: '#/components/schemas/Counters' - Modules: - type: object - description: "List of loaded modules" - additionalProperties: - type: string - example: - httpserver: "gorgone::modules::core::httpserver::hooks" - dbcleaner: "gorgone::modules::core::dbcleaner::hooks" - cron: "gorgone::modules::core::cron::hooks" - engine: "gorgone::modules::centreon::engine::hooks" - action: "gorgone::modules::core::action::hooks" - statistics: "gorgone::modules::centreon::statistics::hooks" - nodes: "gorgone::modules::centreon::nodes::hooks" - legacycmd: "gorgone::modules::centreon::legacycmd::hooks" - proxy: "gorgone::modules::core::proxy::hooks" - ApiEndpoints: - type: object - description: "List of available endpoints" - additionalProperties: - type: string - example: - POST_/internal/logger: "BCASTLOGGER" - GET_/centreon/statistics/broker: "BROKERSTATS" - GET_/internal/thumbprint: "GETTHUMBPRINT" - GET_/core/cron/definitions: "GETCRON" - GET_/internal/information: "INFORMATION" - POST_/core/cron/definitions: "ADDCRON" - POST_/core/action/command: "COMMAND" - POST_/core/proxy/remotecopy: "REMOTECOPY" - POST_/centreon/engine/command: "ENGINECOMMAND" - PATCH_/core/cron/definitions: "UPDATECRON" - DELETE_/core/cron/definitions: "DELETECRON" - GET_/internal/constatus: "CONSTATUS" - Counters: - type: object - description: "List of metric counters" - properties: - total: - type: integer - description: "Total number of events processed since startup" - example: 40210 - external: - type: object - description: "Number of external events since startup" - additionalProperties: - type: string - example: - total: 0 - internal: - type: object - description: "Number of internal events since startup" - additionalProperties: - type: string - example: - legacycmdready: 1 - setlogs: 7841 - enginecommand: 20 - registernodes: 443 - pong: 3397 - proxyready: 5 - statisticsready: 1 - addcron: 1 - cronready: 1 - getthumbprint: 2 - centreonnodesready: 1 - httpserverready: 1 - command: 4446 - putlog: 9809 - dbcleanerready: 1 - information: 6 - brokerstats: 4446 - constatus: 1 - total: 40210 - setcoreid: 443 - getlog: 8893 - engineready: 1 - unregisternodes: 443 - actionready: 1 - proxy: - type: object - description: "Number of events passed through proxy since startup" - additionalProperties: - type: string - example: - enginecommand: 10 - getlog: 4446 - total: 8902 - command: 4446 - Thumbprint: - type: object - properties: - action: - type: string - description: "Event sent to retrieve data" - example: "getthumbprint" - message: - type: string - description: "Response message" - example: "ok" - data: - type: object - properties: - thumbprint: - type: string - description: "Thumbprint of the public key" - example: - "cS4B3lZq96qcP4FTMhVMuwAhztqRBQERKyhnEitnTFM" - SeverityLevel: - type: object - properties: - severity: - type: string - description: "Severity level to be defined for all loaded modules" - enum: - - info - - error - - debug - CronDefinitions: - type: array - items: - $ref: '#/components/schemas/CronDefinition' - CronDefinition: - type: object - properties: - timespec: - type: string - description: "Cron-like time specification" - id: - type: string - description: "Unique identifier of the cron definition" - action: - type: string - description: "Action/event to call at job execution" - parameters: - type: object - description: "Parameters needed by the called action/event" - keep_token: - type: boolean - description: "Boolean to define whether or not the ID of the definition will be used as token for the command" - required: - - timespec - - id - - action - - parameters - ActionCommands: - type: array - items: - $ref: '#/components/schemas/ActionCommand' - ActionCommand: - type: object - properties: - command: - type: string - description: "Command to execute" - example: "echo data > /tmp/date.log" - timeout: - type: integer - description: "Time in seconds before a command is considered timed out" - example: 5 - default: 30 - continue_on_error: - type: boolean - description: "Behaviour in case of execution issue" - example: true - default: false - required: - - command - EngineCommands: - type: object - properties: - command_file: - type: string - description: "Path to the Centreon Engine command file pipe" - example: "/var/lib/centreon-engine/rw/centengine.cmd" - command: - type: array - items: - type: string - description: "External command" - example: "[653284380] SCHEDULE_SVC_CHECK;host1;service1;653284380" - HostDiscoveryJob: - type: object - properties: - job_id: - type: integer - description: "ID of the Host Discovery job" - example: 14 - target: - type: integer - description: "Identifier of the target on which to execute the command" - example: 2 - command_line: - type: string - description: "Command line to execute to perform the discovery" - example: "perl /usr/lib/centreon/plugins/centreon_generic_snmp.pl --plugin=os::linux::local::plugin --mode=discovery-snmp --subnet='10.1.2.3/24' --snmp-port='161' --snmp-version='2c' --snmp-community='public'" - timeout: - type: integer - description: "Time in seconds before the command is considered timed out" - example: 300 - execution: - type: object - description: "Execution mode of this job ('0': execute immediately, '1': schedule with cron)" - properties: - mode: - type: integer - description: "Execution mode ('0': immediate, '1': scheduled)" - example: 0 - parameters: - type: object - description: "Parameters needed by execution mode" - properties: - cron_definition: - type: string - description: "Cron definition" - example: "*/10 * * * *" - post_execution: - type: object - description: "Post-execution settings" - properties: - commands: - type: array - description: "Array of commands (content depends on command)" - items: - type: object - description: "Command" - properties: - action: - type: string - description: "Action to perform" - example: COMMAND - command_line: - type: string - description: "Command line to execute" - example: "/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host --job-id=14" - required: - - job_id - - target - - command_line - - execution - \ No newline at end of file diff --git a/centreon-gorgone/docs/api/index.html b/centreon-gorgone/docs/api/index.html deleted file mode 100644 index e2f378ac27..0000000000 --- a/centreon-gorgone/docs/api/index.html +++ /dev/null @@ -1,504 +0,0 @@ - - - - - - Centreon Gorgone RestAPI - - - - - - - - - -

Information

Centreon Gorgone and his "gorgoned" daemon is a lightweight, distributed, modular tasks handler.

-

It provides a set of actions like:

-
    -
  • Execute commands
  • -
  • Send files/directories,
  • -
  • Schedule cron-like tasks,
  • -
  • Push or execute tasks through SSH.
  • -
-

The daemon can be installed on Centreon environments like Centreon Central, Remote and Poller servers.

-

It uses ZeroMQ library.

-

Authentication

Basic Authentication

Security Scheme Type HTTP
HTTP Authorization Scheme basic

Internal

Internal events.

-

Get nodes connection status

Get the connection status of all nodes managed by the Gorgone daemon.

-
Authorizations:

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/internal/constatus

Local Gorgone instance

-
{protocol}://{server}:{port}/api/internal/constatus

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/internal/constatus

Response samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "action": "constatus",
  • "message": "ok",
  • "data":
    {
    }
}

Get runtime informations and statistics

Get informations and statistics about loaded modules, available endpoints and number of events computed at runtime.

-
Authorizations:

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/internal/information

Local Gorgone instance

-
{protocol}://{server}:{port}/api/internal/information

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/internal/information

Response samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "action": "information",
  • "message": "ok",
  • "data":
    {
    }
}

Get public key thumbprint

Get the thumbprint of the public key of the Gorgone daemon.

-
Authorizations:

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/internal/thumbprint

Local Gorgone instance

-
{protocol}://{server}:{port}/api/internal/thumbprint

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/internal/thumbprint

Response samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "action": "getthumbprint",
  • "message": "ok",
  • "data":
    {
    }
}

Set logger severity level

Set the logger severity level for all modules.

-
Authorizations:
Request Body schema: application/json
severity
string
Enum: "info" "error" "debug"

Severity level to be defined for all loaded modules

-

Responses

204

OK

-
401

Unauthorized

-
403

Forbidden

-
post/internal/logger

Local Gorgone instance

-
{protocol}://{server}:{port}/api/internal/logger

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/internal/logger

Request samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "severity": "info"
}

Response samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "error": "http_error_401",
  • "message": "unauthorized"
}

Logs

Logs management.

-

Retrieve event's logs

Retrieve the event's logs based on event's token.

-
Authorizations:
path Parameters
token
required
string
Example: 1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165

Token of the event

-
query Parameters
code
integer
Enum: 0 1 2
Example: code=2

Only retrieve logs with defined code

-
limit
integer >= 1
Example: limit=1

Only retrieve the last x logs

-
ctime
integer <int64>
Example: ctime=1577726040

Only retrieve logs with a creation time equal or superior to a timestamp

-
etime
integer <int64>
Example: etime=1577726040

Only retrieve logs of an event time superior to a timestamp

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/log/{token}

Local Gorgone instance

-
{protocol}://{server}:{port}/api/log/{token}

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/log/{token}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "message": "Logs found",
  • "token": "03008486ba50b52e529ff5828d1432e5578dd18bb530c145b133dc902c8cfa6b8aac4d58fffb0c5ed44b943d2acbfb7cd1b18c55fcebce62e51999db460112c7",
  • "data":
    [
    ]
}

Cron

Module aiming to reproduce a cron-like scheduler that can send events to other Gorgone modules.

-

List definitions

List all cron definitions.

-
Authorizations:

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/core/cron/definitions

Local Gorgone instance

-
{protocol}://{server}:{port}/api/core/cron/definitions

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/core/cron/definitions

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Add definitions

Add one or multiple cron definitions to runtime.

-
Authorizations:
Request Body schema: application/json
Array
timespec
required
string

Cron-like time specification

-
id
required
string

Unique identifier of the cron definition

-
action
required
string

Action/event to call at job execution

-
parameters
required
object

Parameters needed by the called action/event

-
keep_token
boolean

Boolean to define whether or not the ID of the definition will be used as token for the command

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
post/core/cron/definitions

Local Gorgone instance

-
{protocol}://{server}:{port}/api/core/cron/definitions

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/core/cron/definitions

Request samples

Content type
application/json
Copy
Expand all Collapse all
[
  • {
    }
]

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Get a definition

List cron definition identified by id.

-
Authorizations:
path Parameters
definition_id
required
string
Example: broker_stats

ID of the definition

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/core/cron/definitions/{definition_id}

Local Gorgone instance

-
{protocol}://{server}:{port}/api/core/cron/definitions/{definition_id}

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/core/cron/definitions/{definition_id}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Update a definition

Update a cron definition.

-
Authorizations:
path Parameters
definition_id
required
string
Example: broker_stats

ID of the definition

-
Request Body schema: application/json
timespec
required
string

Cron-like time specification

-
id
required
string

Unique identifier of the cron definition

-
action
required
string

Action/event to call at job execution

-
parameters
required
object

Parameters needed by the called action/event

-
keep_token
boolean

Boolean to define whether or not the ID of the definition will be used as token for the command

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
patch/core/cron/definitions/{definition_id}

Local Gorgone instance

-
{protocol}://{server}:{port}/api/core/cron/definitions/{definition_id}

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/core/cron/definitions/{definition_id}

Request samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "timespec": "string",
  • "id": "string",
  • "action": "string",
  • "parameters": { },
  • "keep_token": true
}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Delete a definition

Delete a cron definition.

-
Authorizations:
path Parameters
definition_id
required
string
Example: broker_stats

ID of the definition

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
delete/core/cron/definitions/{definition_id}

Local Gorgone instance

-
{protocol}://{server}:{port}/api/core/cron/definitions/{definition_id}

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/core/cron/definitions/{definition_id}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Get a definition status

Get a definition execution status.

-
Authorizations:
path Parameters
definition_id
required
string
Example: broker_stats

ID of the definition

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/core/cron/definitions/{definition_id}/status

Local Gorgone instance

-
{protocol}://{server}:{port}/api/core/cron/definitions/{definition_id}/status

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/core/cron/definitions/{definition_id}/status

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Action

Module aiming to execute actions on the server running the Gorgone daemon or remotly using SSH.

-

Execute one or several command lines

Execute a command or a set of commands on server running Gorgone.

-
Authorizations:
Request Body schema: application/json
Array
command
required
string

Command to execute

-
timeout
integer
Default: 30

Time in seconds before a command is considered timed out

-
continue_on_error
boolean
Default: false

Behaviour in case of execution issue

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
post/core/action/command

Local Gorgone instance

-
{protocol}://{server}:{port}/api/core/action/command

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/core/action/command

Request samples

Content type
application/json
Copy
Expand all Collapse all
[
  • {
    }
]

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Engine

Module aiming to provide a bridge to communicate with Centreon Engine daemon.

-

Send one or several external commands

Send an external command or a set of external commands to a running Centreon Engine instance using command file pipe. -This method needs the commands to be preformatted as Nagios external commands format.

-
Authorizations:
Request Body schema: application/json
command_file
string

Path to the Centreon Engine command file pipe

-
command
Array of strings

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
post/centreon/engine/command

Local Gorgone instance

-
{protocol}://{server}:{port}/api/centreon/engine/command

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/centreon/engine/command

Request samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "command_file": "/var/lib/centreon-engine/rw/centengine.cmd",
  • "command":
    [
    ]
}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Statistics

Module aiming to deal with statistics collection of Centreon Engine and Broker.

-

Launch Broker statistics collection

Launch Broker statistics collection and store the result on disk.

-
Authorizations:

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/centreon/statistics/broker

Local Gorgone instance

-
{protocol}://{server}:{port}/api/centreon/statistics/broker

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/centreon/statistics/broker

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Launch Broker statistics collection of a specific monitoring server

Launch Broker statistics collection and store the result on disk.

-
Authorizations:
path Parameters
monitoring_server_id
required
integer
Example: 2

ID of the monitoring server

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/centreon/statistics/broker/{monitoring_server_id}

Local Gorgone instance

-
{protocol}://{server}:{port}/api/centreon/statistics/broker/{monitoring_server_id}

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/centreon/statistics/broker/{monitoring_server_id}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Autodiscovery

Module aiming to extend Centreon Autodiscovery server functionalities.

-

Add a host discovery job

Add one Centreon Autodiscovery job to discover hosts.

-
Authorizations:
Request Body schema: application/json
job_id
required
integer

ID of the Host Discovery job

-
target
required
integer

Identifier of the target on which to execute the command

-
command_line
required
string

Command line to execute to perform the discovery

-
timeout
integer

Time in seconds before the command is considered timed out

-
execution
required
object

Execution mode of this job ('0': execute immediately, '1': schedule with cron)

-
post_execution
object

Post-execution settings

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
post/centreon/autodiscovery/hosts

Local Gorgone instance

-
{protocol}://{server}:{port}/api/centreon/autodiscovery/hosts

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/centreon/autodiscovery/hosts

Request samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "job_id": 14,
  • "target": 2,
  • "command_line": "perl /usr/lib/centreon/plugins/centreon_generic_snmp.pl --plugin=os::linux::local::plugin --mode=discovery-snmp --subnet='10.1.2.3/24' --snmp-port='161' --snmp-version='2c' --snmp-community='public'",
  • "timeout": 300,
  • "execution":
    {
    },
  • "post_execution":
    {
    }
}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Launch a host discovery job

Launch a host discovery job identified by id (even if in cron mode).

-
Authorizations:
path Parameters
job_id
required
integer
Example: 2

ID of the job

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
get/centreon/autodiscovery/hosts/{job_id}/schedule

Local Gorgone instance

-
{protocol}://{server}:{port}/api/centreon/autodiscovery/hosts/{job_id}/schedule

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/centreon/autodiscovery/hosts/{job_id}/schedule

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Delete a host discovery job

Delete one Centreon Autodiscovery scheduled job.

-
Authorizations:
path Parameters
token
required
string
Example: discovery_14_6b7d1bb8

Token of the scheduled job

-

Responses

200

OK

-
401

Unauthorized

-
403

Forbidden

-
delete/centreon/autodiscovery/hosts/{token}

Local Gorgone instance

-
{protocol}://{server}:{port}/api/centreon/autodiscovery/hosts/{token}

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/centreon/autodiscovery/hosts/{token}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}
- - - - \ No newline at end of file diff --git a/centreon-gorgone/docs/client_server_zmq.md b/centreon-gorgone/docs/client_server_zmq.md deleted file mode 100644 index 079e12087e..0000000000 --- a/centreon-gorgone/docs/client_server_zmq.md +++ /dev/null @@ -1,90 +0,0 @@ -# Client/Server ZMQ communication - -When using ZMQ protocol, all communications are encrypted using symmetric-key encryption based on public/private keys from both client and server. - -In a Centreon context, the **client** is the Gorgone daemon running on the **Centreon Central**, the **servers** are the daemon running on **Pollers**. - -## Generate private and public keys - -On both client and server, generate RSA private and public keys using *centreon* user. - -```bash -$ mkdir -p /var/spool/centreon/.gorgone/ -$ chmod 700 /var/spool/centreon/.gorgone -$ openssl genrsa -out /var/spool/centreon/.gorgone/privkey.pem 4092 -Generating RSA private key, 4092 bit long modulus -...................................++ -...........................................................................................................................................................................++ -e is 65537 (0x10001) -$ openssl rsa -in /var/spool/centreon/.gorgone/privkey.pem -out /var/spool/centreon/.gorgone/pubkey.pem -pubout -outform PEM -writing RSA key -$ chmod 644 /var/spool/centreon/.gorgone/pubkey.pem -$ chmod 600 /var/spool/centreon/.gorgone/privkey.pem -``` - -Copy the server public key onto the client in a specific directory (for example */var/spool/centreon/.gorgone/*) - -## Get the string-formatted JWK thumbprint - -On the client, execute the following command: - -```bash -$ perl /usr/local/bin/gorgone_key_thumbprint.pl --key-path='/var/spool/centreon/.gorgone/pubkey.pem' -2019-09-30 11:00:00 - INFO - File '/var/spool/centreon/.gorgone/pubkey.pem' JWK thumbprint: pnI6EWkiTbazjikJXRkLmjml5wvVECYtQduJUjS4QK4 -``` - -## Set the configurations - -*Make the IDs match Centreon Pollers ID to benefit from [legacy cmd](../docs/modules/core/legacycmd.md) module's actions.* - -#### Server - -In the */etc/centreon/config.d/20-gorgoned.yaml* configuration file, add the following directives under the -*gorgonecore* -section: - -```yaml -gorgone: - gorgonecore: - id: 1 - privkey: /var/spool/centreon/.gorgone/privkey.pem - pubkey: /var/spool/centreon/.gorgone/pubkey.pem -``` - -Add the [register](../docs/modules/core/register.md) module and define the path to the dedicated configuration file. - -```yaml -modules: - - name: register - package: "gorgone::modules::core::register::hooks" - enable: true - config_file: /etc/centreon/gorgone-targets.yml -``` - -Create the file */etc/centreon/gorgone-targets.yml* and fill it with the following configuration: - -```yaml -nodes: - - id: 2 - type: push_zmq - address: 10.1.2.3 - port: 5556 -``` - -#### Client - -In the */etc/centreon/config.d/20-gorgoned.yaml* configuration file, add the following directives: - -```yaml -gorgone: - gorgonecore: - id: 2 - external_com_type: tcp - external_com_path: "*:5556" - privkey: /var/spool/centreon/.gorgone/privkey.pem - pubkey: /var/spool/centreon/.gorgone/pubkey.pem - authorized_clients: - - key: pnI6EWkiTbazjikJXRkLmjml5wvVECYtQduJUjS4QK4 -``` - -The *authorized_clients* entry allows to define the client public key thumbprint retrieved earlier. diff --git a/centreon-gorgone/docs/configuration.md b/centreon-gorgone/docs/configuration.md deleted file mode 100644 index 0789429e9b..0000000000 --- a/centreon-gorgone/docs/configuration.md +++ /dev/null @@ -1,105 +0,0 @@ -# Configuration - -| Directive | Description | -| :------------ | :---------------------------------------------------------------------- | -| name | Name of the configuration | -| description | Short string to decribe the configuration | -| configuration | First configuration entry point | -| centreon | Entry point to set Centreon configuration | -| database | Entry point to set Centreon databases data source names and credentials | -| gorgonecore | Entry point to set Gorgone main configuration | -| modules | Table to load and configuration Gorgone modules | - -## *database* - -Usefull in a Centreon Central installation to access Centreon databases. - -| Directive | Description | -| :-------- | :------------------------------- | -| dsn | Data source name of the database | -| username | Username to access the database | -| password | Username's password | - -#### Example - -```yaml -configuration: - centreon: - database: - db_configuration: - dsn: "mysql:host=localhost;dbname=centreon" - username: centreon - password: centreon - db_realtime: - dsn: "mysql:host=localhost;dbname=centreon_storage" - username: centreon - password: centreon -``` - -## *gorgonecore* - -| Directive | Description | Default value | -| :-------------------- | :---------------------------------------------------------------------- | :--------------------------------------------- | -| internal_com_type | Type of the internal ZMQ socket | `ipc` | -| internal_com_path | Path to the internal ZMQ socket | `/tmp/gorgone/routing.ipc` | -| internal_com_crypt | Crypt internal communication | `true` | -| internal_com_cipher | Internal communication cipher | `AES` | -| internal_com_padding | Internal communication padding | `1` (mean: PKCS5) | -| internal_com_keysize | Internal communication key size | `32` (bytes) | -| internal_com_rotation | Internal communication time before key rotation | `1440` (minutes) | -| external_com_type | Type of the external ZMQ socket | `tcp` | -| external_com_path | Path to the external ZMQ socket | `*:5555` | -| external_com_cipher | Cipher used for encryption | `AES` | -| external_com_keysize | Size in bytes of the symmetric encryption key | `32` | -| external_com_padding | External communication padding | `1` (mean: PKCS5) | -| external_com_rotation | External communication time before key rotation | `1440` (minutes) | -| timeout | Time in seconds before killing child processes when stopping Gorgone | `50` | -| gorgone_db_type | Type of the Gorgone database | `SQLite` | -| gorgone_db_name | Path and name of the database | `dbname=/var/lib/centreon-gorgone/history.sdb` | -| gorgone_db_host | Hostname/IP address of the server hosting the database | | -| gorgone_db_port | Port of the database listener | | -| gorgone_db_user | Username to access the database | | -| gorgone_db_password | Username's password | | -| hostname | Hostname of the server running Gorgone | Result of *hostname* system function. | -| id | Identifier of server running Gorgone | None. Must be unique over all Gorgone daemons. | -| privkey | Path to the Gorgone core private key | `keys/rsakey.priv.pem` | -| pubkey | Path to the Gorgone core public key | `keys/rsakey.pub.pem` | -| fingerprint_mode | Validation mode of zmq nodes to connect (can be: always, first, strict) | `first` | -| fingerprint_mgr | Hash of the definition class to store fingerprints | | -| authorized_clients | Table of string-formated JWK thumbprints of clients public key | | -| proxy_name | Name of the proxy module definition | `proxy` (loaded internally) | - -#### Example - -```yaml -configuration: - gorgone: - gorgonecore: - internal_com_type: ipc - internal_com_path: /tmp/gorgone/routing.ipc - external_com_type: tcp - external_com_path: "*:5555" - timeout: 50 - gorgone_db_type: SQLite - gorgone_db_name: dbname=/var/lib/centreon-gorgone/history.sdb - gorgone_db_host: - gorgone_db_port: - gorgone_db_user: - gorgone_db_password: - hostname: - id: - privkey: keys/central/privkey.pem - cipher: "Cipher::AES" - keysize: 32 - vector: 0123456789012345 - fingerprint_mode: first - fingerprint_mgr: - package: gorgone::class::fingerprint::backend::sql - authorized_clients: - - key: pnI6EWkiTbazjikJXRkLmjml5wvVECYtQduJUjS4QK4 - proxy_name: proxy -``` - -## *modules* - -See the *configuration* titles of the modules documentations listed [here](../docs/modules.md). diff --git a/centreon-gorgone/docs/getting_started.md b/centreon-gorgone/docs/getting_started.md deleted file mode 100644 index 5611a2464b..0000000000 --- a/centreon-gorgone/docs/getting_started.md +++ /dev/null @@ -1,201 +0,0 @@ -# Getting started - -## Installation - -### From package - -Using Centreon standard yum repositories, execute the following command to install Gorgone: - -```bash -yum install centreon-gorgone -``` - -### From sources centos 7 - -Using Github project, execute the following command to retrieve Gorgone source code: - -```bash -git clone https://github.com/centreon/centreon-gorgone -``` - -The daemon uses the following Perl modules: - -* Repository 'centreon-stable': - * ZMQ::LibZMQ4 - * UUID - * Digest::MD5::File -* Repository 'centos base': - * JSON::PP - * JSON::XS - * YAML - * DBD::SQLite - * DBD::mysql - * Crypt::CBC - * HTTP::Daemon - * HTTP::Status - * MIME::Base64 - * NetAddr::IP -* Repository 'epel': - * HTTP::Daemon::SSL - * Schedule::Cron -* From offline packages: - * Hash::Merge - * YAML::XS - * Crypt::Cipher::AES (module CryptX) - * Crypt::PK::RSA (module CryptX) - * Crypt::PRNG (module CryptX) - -Execute the following commands to install them all: - -```bash -yum install 'perl(JSON::PP)' 'perl(Digest::MD5::File)' 'perl(NetAddr::IP)' 'perl(Schedule::Cron)' 'perl(Crypt::CBC)' 'perl(ZMQ::LibZMQ4)' 'perl(JSON::XS)' 'perl(YAML)' 'perl(DBD::SQLite)' 'perl(DBD::mysql)' 'perl(UUID)' 'perl(HTTP::Daemon)' 'perl(HTTP::Daemon::SSL)' 'perl(HTTP::Status)' 'perl(MIME::Base64)' -yum install packaging/packages/perl-CryptX-0.064-1.el7.x86_64.rpm packaging/packages/perl-YAML-LibYAML-0.80-1.el7.x86_64.rpm packaging/packages/perl-Hash-Merge-0.300-1.el7.noarch.rpm packaging/packages/perl-Clone-Choose-0.010-1.el7.noarch.rpm -``` - -### From sources centos 8 - -Using Github project, execute the following command to retrieve Gorgone source code: - -```bash -git clone https://github.com/centreon/centreon-gorgone -``` - -The daemon uses the following Perl modules: - -* Repository 'centos base': - * JSON::PP - * YAML - * DBD::SQLite - * DBD::mysql - * HTTP::Status - * MIME::Base64 - * NetAddr::IP -* Repository 'epel': - * Crypt::CBC - * HTTP::Daemon::SSL - * Schedule::Cron - * Hash::Merge -* From offline packages: - * ZMQ::LibZMQ4 - * UUID - * Digest::MD5::File - * JSON::XS - * HTTP::Daemon - * YAML::XS - * Crypt::Cipher::AES (module CryptX) - * Crypt::PK::RSA (module CryptX) - * Crypt::PRNG (module CryptX) - -Execute the following commands to install them all: - -```bash -dnf install packaging/packages/*.el8*.rpm -dnf install 'perl(Hash::Merge)' 'perl(JSON::PP)' 'perl(NetAddr::IP)' 'perl(Schedule::Cron)' 'perl(Crypt::CBC)' 'perl(YAML)' 'perl(DBD::SQLite)' 'perl(DBD::mysql)' 'perl(HTTP::Daemon::SSL)' 'perl(HTTP::Status)' 'perl(MIME::Base64)' -``` - -## Configuration - -You can retrieve `centcore` configuration, i.e. database hostname and credentials in */etc/centreon/conf.pm*, and build a minimal configuration by applying the [migration procedure](../docs/migration.md). - -All directives are available [here](../docs/configuration.md). - -## Create the database - -Gorgone uses a SQLite database to store all events messages. - -If it does not exist, the daemon will automatically create it in the path set by the `gorgone_db_name` configuration directive. - -However, you can manualy create it with the database schema: - -```bash -sqlite3 -init schema/gorgone_database.sql /var/lib/centreon-gorgone/history.sdb -``` - -Database schema: - -```sql -CREATE TABLE IF NOT EXISTS `gorgone_identity` ( - `id` INTEGER PRIMARY KEY, - `ctime` int(11) DEFAULT NULL, - `identity` varchar(2048) DEFAULT NULL, - `key` varchar(4096) DEFAULT NULL, - `parent` int(11) DEFAULT '0' -); - -CREATE INDEX IF NOT EXISTS idx_gorgone_identity ON gorgone_identity (identity); -CREATE INDEX IF NOT EXISTS idx_gorgone_parent ON gorgone_identity (parent); - -CREATE TABLE IF NOT EXISTS `gorgone_history` ( - `id` INTEGER PRIMARY KEY, - `token` varchar(2048) DEFAULT NULL, - `code` int(11) DEFAULT NULL, - `etime` int(11) DEFAULT NULL, - `ctime` int(11) DEFAULT NULL, - `instant` int(11) DEFAULT '0', - `data` TEXT DEFAULT NULL -); - -CREATE INDEX IF NOT EXISTS idx_gorgone_history_id ON gorgone_history (id); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_token ON gorgone_history (token); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_etime ON gorgone_history (etime); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_code ON gorgone_history (code); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_ctime ON gorgone_history (ctime); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_instant ON gorgone_history (instant); - -CREATE TABLE IF NOT EXISTS `gorgone_synchistory` ( - `id` int(11) DEFAULT NULL, - `ctime` int(11) DEFAULT NULL, - `last_id` int(11) DEFAULT NULL -); - -CREATE INDEX IF NOT EXISTS idx_gorgone_synchistory_id ON gorgone_synchistory (id); - -CREATE TABLE IF NOT EXISTS `gorgone_target_fingerprint` ( - `id` INTEGER PRIMARY KEY, - `target` varchar(2048) DEFAULT NULL, - `fingerprint` varchar(4096) DEFAULT NULL -); - -CREATE INDEX IF NOT EXISTS idx_gorgone_target_fingerprint_target ON gorgone_target_fingerprint (target); -``` - -## Launch the daemon - -If you are using the package, just launch the service as below: - -```bash -systemctl start gorgoned -``` - -Make sure the daemon is running: - -```bash -$ systemctl status gorgoned -● gorgoned.service - Centreon Gorgone - Loaded: loaded (/etc/systemd/system/gorgoned.service; disabled; vendor preset: disabled) - Active: active (running) since Mon 2019-09-30 09:36:19 CEST; 2min 29s ago - Main PID: 5168 (perl) - CGroup: /system.slice/gorgoned.service - ├─5168 /usr/bin/perl /usr/bin/gorgoned --config=/etc/centreon-gorgone/config.yaml --logfile=/var/log/centreon/gorgoned.log --severity=info - ├─5175 gorgone-dbcleaner - ├─5182 gorgone-action - ├─5187 gorgone-nodes - ├─5190 gorgone-legacycmd - ├─5203 gorgone-proxy - ├─5204 gorgone-proxy - ├─5205 gorgone-proxy - ├─5206 gorgone-proxy - └─5207 gorgone-proxy - -Sep 30 09:36:19 localhost systemd[1]: Started Centreon Gorgone. -``` - -If you are using the sources, execute the following command: - -```bash -perl gorgoned --config=config/config.yaml --severity=info -``` - -## Full-ZMQ setup - -To use Gorgone distributed on multiple servers using ZMQ, follow the example given [here](../docs/client_server_zmq.md). diff --git a/centreon-gorgone/docs/guide.md b/centreon-gorgone/docs/guide.md deleted file mode 100644 index a60df55dea..0000000000 --- a/centreon-gorgone/docs/guide.md +++ /dev/null @@ -1,268 +0,0 @@ -# Gorgone protocol - -"gorgone-core" (main mandatory module) can have 2 interfaces: - -* Internal: uncrypted dialog (used by internal modules. Commonly in ipc) -* External: crypted dialog (used by third-party clients. Commonly in tcp) - -## Handshake scenario - -Third-party clients have to use the ZeroMQ library and the following process: - -1. Client: need to create an uniq identity (will be used in "zmq_setsockopt" and "ZMQ_IDENTITY") -2. Client -> Server: ask the server pubkey - - ```text - [GETPUBKEY] - ``` - -3. Server -> Client: send back the pubkey - - ```text - [PUBKEY] [base64 encoding pubkey] - ``` - -4. Client -> Server: send the following message with HELO crypted with the public key of the server (and base64 encoding) and provides client pubkey (base64 encoding): - - ```text - [HOSTNAME] [CLIENTPUBKEY] [HELO] - ``` - -5. Server -> Client: uncrypt the client message: - - * If uncrypted message result is not "HELO", server refuses the connection and send it back: - - ```text - [ACK] [] { "code": 1, "data": { "message": "handshake issue" } } - ``` - - * If uncrypted message result is "HELO", server accepts the connection if the clientpubkey is authorized. It creates a symmetric key and send the following message crypted with client pubkey: - - ```text - [KEY] { "hostname": "xxxx", "key": "ab0182xxxx", "iv": "ab0182xxx", "cipher": "AES", "padding": 1 } - ``` - -4. Client: uncrypts the server message with its private key. -5. Client and Server uses the symmetric key+base64 encoding to dialog. - -The server keeps sessions for 24 hours since the last message of the client. - -Otherwise, it purges the identity/symmetric-key of the client. - -If a third-party client with the same identity try to open a new session, the server deletes the old identity/symmetric-key. - -Be sure to have the same parameters to crypt/uncrypt with the symmetric key. Commonly: 'AES' cipher, keysize of 32 bytes, vector '0123456789012345'. - -## Client request - -After a successful handshake, client requests use the following syntax: - -```text -[ACTION] [TOKEN] [TARGET] DATA -``` - -* ACTION: the request, for example 'COMMAND' or 'ENGINECOMMAND'. It depends of the target server capabilites, -* TOKEN: can be used to create some "sessions". If empty, the server creates an uniq token for each requests, -* TARGET: which "gorgoned" must execute the request. With the following option, you can execute a command on a specific server through another. The poller ID is needed. If empty, the server (which is connected with the client) is the target. -* DATA: JSON stream. It depends on the request. - -For each client requests, the server get an immediate response: - -```text -[ACK] [TOKEN] { "code": "x", "data": { "message": "xxxxx" } } -``` - -* TOKEN: a uniq ID to follow the request, -* DATA: a JSON stream - - * 0 : OK - * 1 : NOK - -There are some exceptions for 'CONSTATUS' and 'GETLOG' requests. - -## Core requests - -### CONSTATUS - -The following request gives you a table with the last ping response of "gorgoned" nodes connected to the server. -The command is useful to know if some pollers are disconnected. - -The client request: - -```text -[CONSTATUS] [] [] -``` - -The server response: - -```text -[CONSTATUS] [token_id] DATA -``` - -An example of the JSON stream: - -```json -{ - "code": 1, - "data": { - "action": "constatus", - "mesage": "ok", - "data": { - "last_ping_sent": "xxxx", - "last_ping_recv": "xxxx", - "nodes": { - "1": "xxx", - "2": "xxx" - } - } - } -} -``` - -'last_ping' and 'entries' values are unix timestamp in seconds. - -The 'last_ping' value is the date when the daemon have launched a PING broadcast to the poller connected. - -The 'entries' values are the last time the poller have responded to the PING broadcast. - -### GETLOG - -The following request gives you the capability to follow your requests. "gorgone" protocol is asynchronous. - -An example: when you request a command execution, the server gives you a direct response and a token. This token can be used to know what happened to your command. - -The client request: - -```text -[GETLOG] [TOKEN] [TARGET] { "code": "xx", "ctime": "xx", "etime": "xx", "token": "xx", "id": "xx" } -``` - -At least one of the 5 values must be defined: - -* code: get logs if code = value -* token: get logs if token = value -* ctime: get logs if creation time in seconds >= value -* etime: get logs if event time in seconds >= value -* id: get logs if id > value - -The 'etime' value gives the time when the event has occured. - -The 'ctime' value gives the time when the server has stored the log in its database. - -The server response: - -```text -[ACK] [token_id] DATA -``` - -An example of the json stream: - -```json -{ - "code": 1, - "data": { - "action": "getlog", - "message": "ok", - "result": [ - { - "id": 10, - "token": "xxxx", - "code": 1, - "etime": 1419252684, - "ctime": 1419252686, - "data": "xxxx", - }, - { - "id": 100, - "token": "xxxx", - "code": 1, - "etime": 1419252688, - "ctime": 1419252690, - "data": "xxxx", - } - ] - } -} -``` - -Each 'gorgoned' nodes store its logs. But every minute (by default), the Central server gets the new logs of its connected nodes and stores it. - -A client can force a synchronization with the following request: - -```text -[GETLOG] [] [target_id] -``` - -The client have to set the target ID (it can be the Poller ID). - -### PUTLOG - -The request shouldn't be used by third-party program. It's commonly used by the internal modules. - -The client request: - -```text -[PUTLOG] [TOKEN] [TARGET] { "code": xxx, "etime": "xxx", "token": "xxxx", "data": { some_datas } } -``` - -### REGISTERNODES - -The request shouldn't be used by third-party program. It's commonly used by the internal modules. - -The client request (no carriage returns. only for reading): - -```text -[REGISTERNODES] [TOKEN] [TARGET] { "nodes": [ - { "id": 20, "type": "pull" }, - { "id": 100, "type": "push_ssh", "address": "10.0.0.1", "ssh_port": 22 }, - { - "id": 150, "type": "push_zmq", "address": "10.3.2.1", - "nodes": [ { "id": 400, { "id": 455 } ] - } - ] -} -``` - -## Common codes - -Common code responses for all module requests: - -* 0: action proceed -* 1: action finished OK -* 2: action finished KO - -Modules can have extra codes. - -# FAQ - -## Which modules should I enable ? - -A Central with gorgoned should have the following modules: - -* action, -* proxy, -* cron, -* httpserver. - -A Poller with gorgoned should have the following modules: - -* action, -* pull (if the connection to the Central should be opened by the Poller). - -## I want to create a client. How should I proceed ? - -First, you must choose a language which can use ZeroMQ library and have some knowledge about ZeroMQ. - -I recommend the following scenario: - -* Create a ZMQ_DEALER, -* Manage the handshake with the server (see :ref:`handshake-scenario`), -* Do a request: - * If you don't need to get the result: close the connection, - * If you need to get the result: - 1. Get the token, - 2. If you have used a target, force a synchronization with 'GETLOG' (without token), - 3. Do a 'GETLOG' request with the token to get the result, - 4. Repeat actions 2 and 3 if you don't have a result yet (you should stop after X retries). - -You can inspire from the code of '[test-client.pl](../contrib/test-client.pl)'. diff --git a/centreon-gorgone/docs/migration.md b/centreon-gorgone/docs/migration.md deleted file mode 100644 index ce115818a1..0000000000 --- a/centreon-gorgone/docs/migration.md +++ /dev/null @@ -1,107 +0,0 @@ -# Migrate from Centreon *centcore* - -To build a configuration file based on */etc/centreon/conf.pm*, execute the following command line. - -If using package: - -```bash -$ perl /usr/local/bin/gorgone_config_init.pl -2019-09-30 11:00:00 - INFO - file '/etc/centreon-gorgone/config.yaml' created success -``` - -If using sources: - -```bash -$ perl ./contrib/gorgone_config_init.pl -2019-09-30 11:00:00 - INFO - file '/etc/centreon-gorgone/config.yaml' created success -``` - -As a result the following configuration file will be created at */etc/centreon-gorgone/config.yaml*: - -```yaml -name: config.yaml -description: Configuration init by gorgone_config_init -configuration: - centreon: - database: - db_configuration: - dsn: "mysql:host=localhost;port=3306;dbname=centreon" - username: "centreon" - password: "centreon" - db_realtime: - dsn: "mysql:host=localhost;port=3306;dbname=centreon_storage" - username: "centreon" - password: "centreon" - gorgone: - gorgonecore: - privkey: "/var/lib/centreon-gorgone/.keys/rsakey.priv.pem" - pubkey: "/var/lib/centreon-gorgone/.keys/rsakey.pub.pem" - modules: - - name: httpserver - package: gorgone::modules::core::httpserver::hooks - enable: false - address: 0.0.0.0 - port: 8085 - ssl: false - auth: - enabled: false - allowed_hosts: - enabled: true - subnets: - - 127.0.0.1/32 - - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: cron - package: gorgone::modules::core::cron::hooks - enable: false - cron: !include cron.d/*.yaml - - - name: proxy - package: gorgone::modules::core::proxy::hooks - enable: true - - - name: legacycmd - package: gorgone::modules::centreon::legacycmd::hooks - enable: true - cmd_file: "/var/lib/centreon/centcore.cmd" - cache_dir: "/var/cache/centreon/" - cache_dir_trap: "/etc/snmp/centreon_traps/" - remote_dir: "/var/lib/centreon/remote-data/" - - - name: engine - package: "gorgone::modules::centreon::engine::hooks" - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" - - - name: pollers - package: gorgone::modules::centreon::pollers::hooks - enable: true - - - name: broker - package: "gorgone::modules::centreon::broker::hooks" - enable: true - cache_dir: "/var/cache/centreon//broker-stats/" - cron: - - id: broker_stats - timespec: "*/2 * * * *" - action: BROKERSTATS - parameters: - timeout: 10 -``` diff --git a/centreon-gorgone/docs/modules.md b/centreon-gorgone/docs/modules.md deleted file mode 100644 index fb1f1ee940..0000000000 --- a/centreon-gorgone/docs/modules.md +++ /dev/null @@ -1,21 +0,0 @@ -# Modules - -List of the available modules: - -* Core - * [Action](../docs/modules/core/action.md) - * [Cron](../docs/modules/core/cron.md) - * [DB Cleaner](../docs/modules/core/dbcleaner.md) - * [HTTP Server](../docs/modules/core/httpserver.md) - * [Proxy](../docs/modules/core/proxy.md) - * [Pull](../docs/modules/core/pull.md) - * [Register](../docs/modules/core/register.md) -* Centreon - * [Autodiscovery](../docs/modules/centreon/autodiscovery.md) - * [Broker](../docs/modules/centreon/statistics.md) - * [Engine](../docs/modules/centreon/engine.md) - * [Legacy Cmd](../docs/modules/centreon/legacycmd.md) - * [Nodes](../docs/modules/centreon/nodes.md) -* Plugins - * [Newtest](../docs/modules/plugins/newtest.md) - * [Scom](../docs/modules/plugins/scom.md) diff --git a/centreon-gorgone/docs/modules/centreon/autodiscovery.md b/centreon-gorgone/docs/modules/centreon/autodiscovery.md deleted file mode 100644 index e9446458fa..0000000000 --- a/centreon-gorgone/docs/modules/centreon/autodiscovery.md +++ /dev/null @@ -1,318 +0,0 @@ -# Autodiscovery - -## Description - -This module aims to extend Centreon Autodiscovery server functionalities. - -## Configuration - -| Directive | Description | Default value | -| :-------------- | :--------------------------------------------------------------------- | :------------ | -| global\_timeout | Time in seconds before a discovery command is considered timed out | `300` | -| check\_interval | Time in seconds defining frequency at which results will be search for | `15` | - -#### Example - -```yaml -name: autodiscovery -package: "gorgone::modules::centreon::autodiscovery::hooks" -enable: true -global_timeout: 60 -check_interval: 10 -``` - -## Events - -| Event | Description | -| :----------------------- | :---------------------------------------------- | -| AUTODISCOVERYREADY | Internal event to notify the core | -| HOSTDISCOVERYLISTENER | Internal event to get host discovery results | -| SERVICEDISCOVERYLISTENER | Internal event to get service discovery results | -| ADDHOSTDISCOVERYJOB | Add a host discovery job | -| DELETEHOSTDISCOVERYJOB | Delete a host discovery job | -| LAUNCHHOSTDISCOVERY | Execute a host discovery job | -| LAUNCHSERVICEDISCOVERY | Execute a service discovery job | - -## API - -### Add a host discovery job - -| Endpoint | Method | -| :---------------------------- | :----- | -| /centreon/autodiscovery/hosts | `POST` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | -| Content-Type | application/json | - -#### Body - -| Key | Value | -| :-------------- | :--------------------------------------------------------- | -| job\_id | ID of the Host Discovery job | -| target | Identifier of the target on which to execute the command | -| command_line | Command line to execute to perform the discovery | -| timeout | Time in seconds before the command is considered timed out | -| execution | Execution settings | -| post\_execution | Post-execution settings | - -With the following keys for the `execution` entry: - -| Key | Value | -| :--------- | :---------------------------------------------- | -| mode | Execution mode ('0': immediate, '1': scheduled) | -| parameters | Parameters needed by execution mode | - -With the following keys for the `post_execution` entry: - -| Key | Value | -| :------- | :------------------------------- | -| commands | Array of commands to be executed | - -```json -{ - "job_id": "", - "target": "", - "command_line": "", - "timeout": "", - "execution": { - "mode": "", - "parameters": "", - }, - "post_execution": { - "commands": "", - } -} -``` - -#### Examples - -##### Execute immediately without post-execution commands - -```bash -curl --request POST "https://hostname:8443/api/centreon/autodiscovery/hosts" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"job_id\": 14, - \"target\": 3, - \"command_line\": \"perl /usr/lib/centreon/plugins/centreon_generic_snmp.pl --plugin=os::linux::local::plugin --mode=discovery-snmp --subnet='10.1.2.3/24' --snmp-port='161' --snmp-version='2c' --snmp-community='public'\", - \"timeout\": 300, - \"execution\": { - \"mode\": 0, - \"parameters\": {} - }, - \"post_execution\": {} -}" -``` - -##### Execute immediately with post-execution commands - -```bash -curl --request POST "https://hostname:8443/api/centreon/autodiscovery/hosts" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"job_id\": 14, - \"target\": 3, - \"command_line\": \"perl /usr/lib/centreon/plugins/centreon_generic_snmp.pl --plugin=os::linux::local::plugin --mode=discovery-snmp --subnet='10.1.2.3/24' --snmp-port='161' --snmp-version='2c' --snmp-community='public'\", - \"timeout\": 300, - \"execution\": { - \"mode\": 0, - \"parameters\": {} - }, - \"post_execution\": { - \"commands\": [ - { - \"action\": \"COMMAND\", - \"command_line\": \"/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host --job-id=14\" - } - ] - } -}" -``` - -##### Schedule execution without post-execution commands - -```bash -curl --request POST "https://hostname:8443/api/centreon/autodiscovery/hosts" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"job_id\": 14, - \"target\": 3, - \"command_line\": \"perl /usr/lib/centreon/plugins/centreon_generic_snmp.pl --plugin=os::linux::local::plugin --mode=discovery-snmp --subnet='10.1.2.3/24' --snmp-port='161' --snmp-version='2c' --snmp-community='public'\", - \"timeout\": 300, - \"execution\": { - \"mode\": 1, - \"parameters\": { - \"cron_definition\": \"*/10 * * * *\" - } - }, - \"post_execution\": {} -}" -``` - -##### Schedule execution with post-execution commands - -```bash -curl --request POST "https://hostname:8443/api/centreon/autodiscovery/hosts" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"job_id\": 14, - \"target\": 3, - \"command_line\": \"perl /usr/lib/centreon/plugins/centreon_generic_snmp.pl --plugin=os::linux::local::plugin --mode=discovery-snmp --subnet='10.1.2.3/24' --snmp-port='161' --snmp-version='2c' --snmp-community='public'\", - \"timeout\": 300, - \"execution\": { - \"mode\": 1, - \"parameters\": { - \"cron_definition\": \"*/10 * * * *\" - } - }, - \"post_execution\": { - \"commands\": [ - { - \"action\": \"COMMAND\", - \"command_line\": \"/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host --job-id=14\" - } - ] - } -}" -``` - -### Launch a host discovery job - -| Endpoint | Method | -| :----------------------------------------- | :----- | -| /centreon/autodiscovery/hosts/:id/schedule | `GET` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | - -#### Path variables - -| Variable | Description | -| :------- | :-------------------- | -| id | Identifier of the job | - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/centreon/autodiscovery/hosts/:id/schedule" \ - --header "Accept: application/json" -``` - -### Delete a host discovery job - -| Endpoint | Method | -| :----------------------------------- | :------- | -| /centreon/autodiscovery/hosts/:token | `DELETE` | - -#### Headers - -| Header | Value | -| :----- | :--------------- | -| Accept | application/json | - -#### Path variables - -| Variable | Description | -| :------- | :------------------------- | -| token | Token of the scheduled job | - -#### Example - -```bash -curl --request DELETE "https://hostname:8443/api/centreon/autodiscovery/hosts/discovery_14_6b7d1bb8" \ - --header "Accept: application/json" -``` - -### Execute a service discovery job - -| Endpoint | Method | -| :------------------------------- | :----- | -| /centreon/autodiscovery/services | `POST` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | -| Content-Type | application/json | - -#### Body - -| Key | Value | -| :------------------- | :------------------------------------------------------------------------------------------------ | -| filter\_rules | Array of rules to use for discovery (empty means all) | -| force\_rule | Run disabled rules ('0': not forced, '1': forced) | -| filter\_hosts | Array of hosts against which run the discovery (empty means all) | -| filter\_pollers | Array of pollers for which linked hosts will be discovered against (empty means all) | -| manual | Run discovery for manual scan from web UI ('0': automatic, '1': manual) | -| dry\_run | Run discovery without configuration change ('0': changes, '1': dry run) | -| no\_generate\_config | No configuration generation (even if there is some changes) ('0': generation, '1': no generation) | - -```json -{ - "filter_rules": "", - "force_rule": "", - "filter_hosts": "", - "filter_pollers": "", - "manual": "", - "dry_run": "", - "no_generate_config": "" -} -``` - -#### Examples - -##### Execute discovery with defined rules (even if disabled) - -```bash -curl --request POST "https://hostname:8443/api/centreon/autodiscovery/services" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"filter_rules\": [ - \"OS-Linux-SNMP-Disk-Name\", - \"OS-Linux-SNMP-Traffic-Name\" - ], - \"force_rule\": 1 -}" -``` - -##### Execute discovery for defined hosts - -```bash -curl --request POST "https://hostname:8443/api/centreon/autodiscovery/services" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"filter_hosts\": [ - \"Host-1\", - \"Host-2\", - \"Host-3\" - ] -}" -``` - -##### Execute discovery for defined poller (without changes) - -```bash -curl --request POST "https://hostname:8443/api/centreon/autodiscovery/services" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"filter_pollers\": [ - \"Poller-1\" - ], - \"dry_run\": 1 -}" -``` diff --git a/centreon-gorgone/docs/modules/centreon/engine.md b/centreon-gorgone/docs/modules/centreon/engine.md deleted file mode 100644 index 4c8c561d5b..0000000000 --- a/centreon-gorgone/docs/modules/centreon/engine.md +++ /dev/null @@ -1,72 +0,0 @@ -# Engine - -## Description - -This module aims to provide a bridge to communicate with Centreon Engine daemon. - -## Configuration - -| Directive | Description | Default value | -| :----------- | :-------------------------------------------- | :------------------------------------------- | -| command_file | Path to the Centreon Engine command file pipe | `/var/lib/centreon-engine/rw/centengine.cmd` | - -#### Example - -```yaml -name: engine -package: "gorgone::modules::centreon::engine::hooks" -enable: true -command_file: "/var/lib/centreon-engine/rw/centengine.cmd" -``` - -## Events - -| Event | Description | -| :------------ | :--------------------------------------------------------------------------- | -| ENGINEREADY | Internal event to notify the core | -| ENGINECOMMAND | Send a Centreon external command to Centreon Engine daemon command file pipe | - -## API - -### Execute a command line - -| Endpoint | Method | -| :----------------------- | :----- | -| /centreon/engine/command | `POST` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | -| Content-Type | application/json | - -#### Body - -| Key | Value | -| :----------- | :-------------------------------------------- | -| command_file | Path to the Centreon Engine command file pipe | -| commands | Array of external commands (old-style format) | - -```json -{ - "command_file": "", - "commands": [ - "" - ] -} -``` - -#### Example - -```bash -curl --request POST "https://hostname:8443/api/centreon/engine/command" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"command_file\": \"/var/lib/centreon-engine/rw/centengine.cmd\", - \"commands\": [ - \"[653284380] SCHEDULE_SVC_CHECK;host1;service1;653284380\" - ] -}" -``` diff --git a/centreon-gorgone/docs/modules/centreon/legacycmd.md b/centreon-gorgone/docs/modules/centreon/legacycmd.md deleted file mode 100644 index d7221114f7..0000000000 --- a/centreon-gorgone/docs/modules/centreon/legacycmd.md +++ /dev/null @@ -1,48 +0,0 @@ -# Legacy Cmd - -## Description - -This module aims to mimick the behaviour of the antique *centcore* daemon. - -As for *centcore*, it reads a file (called command file) and process every commands that it knows of. - -The module relies on the following modules to process commands: - -* [Action](../core/action.md) -* [Proxy](../core/proxy.md) -* [Engine](engine.md) - -## Configuration - -| Directive | Description | Default value | -| :--------------------------- | :----------------------------------------------------------- | :---------------------------------------- | -| cmd_file | *Command file* to read commands from | `/var/lib/centreon/centcore.cmd` | -| cmd_dir | Directory where to watch for *command files* | `/var/lib/centreon/` | -| cache_dir | Directory where to process Centreon configuration files | `/var/cache/centreon/` | -| cache_dir_trap | Directory where to process Centreontrapd databases | `/etc/snmp/centreon_traps/` | -| remote_dir | Directory where to export Remote Servers configuration | `/var/cache/centreon/config/remote-data/` | -| bulk_external_cmd | Bulk external commands (DOWNTIME, ACK,...) | `50` | -| bulk_external_cmd_sequential | Order bulk external commands and other commands (Eg. RELOAD) | `1` | - -#### Example - -```yaml -name: legacycmd -package: "gorgone::modules::centreon::legacycmd::hooks" -enable: true -cmd_file: "/var/lib/centreon/centcore.cmd" -cmd_dir: "/var/lib/centreon/" -cache_dir: "/var/cache/centreon/" -cache_dir_trap: "/etc/snmp/centreon_traps/" -remote_dir: "/var/cache/centreon/config/remote-data/" -``` - -## Events - -| Event | Description | -| :------------- | :-------------------------------- | -| LEGACYCMDREADY | Internal event to notify the core | - -## API - -No API endpoints. diff --git a/centreon-gorgone/docs/modules/centreon/nodes.md b/centreon-gorgone/docs/modules/centreon/nodes.md deleted file mode 100644 index b7eb23bbaa..0000000000 --- a/centreon-gorgone/docs/modules/centreon/nodes.md +++ /dev/null @@ -1,53 +0,0 @@ -# Nodes - -## Description - -This module aims to automatically register Poller servers as Gorgone nodes, in opposition to the [register](../core/register.md) module. - -For now, nodes can be registered as SSH nodes or ZMQ nodes. - -## Configuration - -No specific configuration. - -#### Example - -```yaml -name: nodes -package: "gorgone::modules::centreon::nodes::hooks" -enable: true -``` - -## Events - -| Event | Description | -| :----------------- | :-------------------------------- | -| CENTREONNODESREADY | Internal event to notify the core | - -## API - -### Synchronize centreon nodes configuration - -| Endpoint | Method | -| :------------------- | :----- | -| /centreon/nodes/sync | `POST` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | -| Content-Type | application/json | - -#### Body - -No parameters. - -#### Example - -```bash -curl --request POST "https://hostname:8443/api/centreon/nodes/sync" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{}" -``` diff --git a/centreon-gorgone/docs/modules/centreon/statistics.md b/centreon-gorgone/docs/modules/centreon/statistics.md deleted file mode 100644 index 82ce80de5d..0000000000 --- a/centreon-gorgone/docs/modules/centreon/statistics.md +++ /dev/null @@ -1,69 +0,0 @@ -# Broker - -## Description - -This module aims to deal with statistics collection of Centreon Engine and Broker. - -## Configuration - -| Directive | Description | Default value | -| :--------------- | :--------------------------------------------------------------------------------------------- | :-------------------------------- | -| broker_cache_dir | Path to the Centreon Broker statistics directory (local) use to store node's broker statistics | `/var/lib/centreon/broker-stats/` | - -The configuration needs a cron definition to unsure that statistics collection will be done cyclically. - -#### Example - -```yaml -name: statistics -package: "gorgone::modules::centreon::statistics::hooks" -enable: false -broker_cache_dir: "/var/lib/centreon/broker-stats/" -cron: - - id: broker_stats - timespec: "*/5 * * * *" - action: BROKERSTATS - parameters: - timeout: 10 - collect_localhost: false -``` - -## Events - -| Event | Description | -| :-------------- | :----------------------------------------------- | -| STATISTICSREADY | Internal event to notify the core | -| BROKERSTATS | Collect Centreon Broker statistics files on node | - -## API - -### Collect Centreon Broker statistics on one or several nodes - -| Endpoint | Method | -| :------------------------------ | :----- | -| /centreon/statistics/broker | `GET` | -| /centreon/statistics/broker/:id | `GET` | - -#### Headers - -| Header | Value | -| :----- | :--------------- | -| Accept | application/json | - -#### Path variables - -| Variable | Description | -| :------- | :--------------------- | -| id | Identifier of the node | - -#### Example - -```bash -curl --request POST "https://hostname:8443/api/centreon/statistics/broker" \ - --header "Accept: application/json" -``` - -```bash -curl --request POST "https://hostname:8443/api/centreon/statistics/broker/2" \ - --header "Accept: application/json" -``` diff --git a/centreon-gorgone/docs/modules/core/action.md b/centreon-gorgone/docs/modules/core/action.md deleted file mode 100644 index c885dcd0ca..0000000000 --- a/centreon-gorgone/docs/modules/core/action.md +++ /dev/null @@ -1,90 +0,0 @@ -# Action - -## Description - -This module aims to execute actions on the server running the Gorgone daemon or remotly using SSH. - -## Configuration - -| Directive | Description | Default value | -| :--------------- | :------------------------------------------------------------- | :------------ | -| command_timeout | Time in seconds before a command is considered timed out | `30` | -| whitelist_cmds | Boolean to enable commands whitelist | `false` | -| allowed_cmds | Regexp list of allowed commands | | -| paranoid_plugins | Block centengine restart/reload if plugin dependencies missing | `false` | - -#### Example - -```yaml -name: action -package: "gorgone::modules::core::action::hooks" -enable: true -command_timeout: 30 -whitelist_cmds: true -allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ -``` - -## Events - -| Event | Description | -| :---------- | :-------------------------------------------------------------------------------------- | -| ACTIONREADY | Internal event to notify the core | -| PROCESSCOPY | Process file or archive received from another daemon | -| COMMAND | Execute a shell command on the server running the daemon or on another server using SSH | - -## API - -### Execute a command line - -| Endpoint | Method | -| :------------------- | :----- | -| /core/action/command | `POST` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | -| Content-Type | application/json | - -#### Body - -| Key | Value | -| :---------------- | :------------------------------------------------------- | -| command | Command to execute | -| timeout | Time in seconds before a command is considered timed out | -| continue_on_error | Behaviour in case of execution issue | - -```json -[ - { - "command": "", - "timeout": "", - "continue_on_error": "" - } -] -``` - -#### Example - -```bash -curl --request POST "https://hostname:8443/api/core/action/command" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "[ - { - \"command\": \"echo 'Test command' >> /tmp/here.log\" - } -]" -``` diff --git a/centreon-gorgone/docs/modules/core/cron.md b/centreon-gorgone/docs/modules/core/cron.md deleted file mode 100644 index b4e5be4d22..0000000000 --- a/centreon-gorgone/docs/modules/core/cron.md +++ /dev/null @@ -1,229 +0,0 @@ -# Cron - -## Description - -This module aims to reproduce a cron-like scheduler that can send events to other Gorgone modules. - -## Configuration - -No specific configuration is needed. - -Below the configuration to add cron definitions: - -| Directive | Description | -| :--------- | :---------------------------------------------------------------------------------------------- | -| id | Unique identifier of the cron definition | -| timespec | Cron-like time specification | -| action | Action/event to call at job execution | -| parameters | Parameters needed by the called action/event | -| keep_token | Boolean to define whether or not the ID of the definition will be used as token for the command | - -#### Example - -```yaml -name: cron -package: "gorgone::modules::core::cron::hooks" -enable: true -cron: - - id: echo_date - timespec: "* * * * *" - action: COMMAND - parameters: - - command: "date >> /tmp/date.log" - timeout: 10 - keep_token: true -``` - -## Events - -| Event | Description | -| :- | :- | -| CRONREADY | Internal event to notify the core | -| GETCRON | Get one or all cron definitions | -| ADDCRON | Add one or several cron definitions | -| DELETECRON | Delete a cron definition | -| UPDATECRON | Update a cron definition | - -## API - -### Get one or all definitions configuration - -| Endpoint | Method | -| :------------------------- | :----- | -| /core/cron/definitions | `GET` | -| /core/cron/definitions/:id | `GET` | - -#### Headers - -| Header | Value | -| :----- | :--------------- | -| Accept | application/json | - -#### Path variables - -| Variable | Description | -| :------- | :-------------------------------- | -| id | Identifier of the cron definition | - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/core/cron/definitions" \ - --header "Accept: application/json" -``` - -```bash -curl --request GET "https://hostname:8443/api/core/cron/definitions/echo_date" \ - --header "Accept: application/json" -``` - -### Get one definition status - -| Endpoint | Method | -| :-------------------------------- | :----- | -| /core/cron/definitions/:id/status | `GET` | - -#### Headers - -| Header | Value | -| :----- | :--------------- | -| Accept | application/json | - -#### Path variables - -| Variable | Description | -| :------- | :-------------------------------- | -| id | Identifier of the cron definition | - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/core/cron/definitions/echo_date/status" \ - --header "Accept: application/json" -``` - -### Add one or several cron definitions - -| Endpoint | Method | -| :--------------------- | :----- | -| /core/cron/definitions | `POST` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | -| Content-Type | application/json | - -#### Body - -| Key | Value | -| :--------- | :---------------------------------------------------------------------------------------------- | -| id | ID of the definition | -| timespec | Cron-like time specification | -| command | Action/event to call at job execution | -| parameters | Parameters needed by the called action/event | -| keep_token | Boolean to define whether or not the ID of the definition will be used as token for the command | - -```json -[ - { - "id": "", - "timespec": "", - "command": "", - "parameters": "", - "keep_token": "" - } -] -``` - -#### Example - -```bash -curl --request POST "https://hostname:8443/api/core/cron/definitions" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "[ - { - \"timespec\": \"*/15 * * * *\", - \"id\": \"job_123\", - \"action\": \"COMMAND\", - \"parameters\": [ - { - \"command\": \"date >> /tmp/the_date_again.log\", - \"timeout\": 5 - } - ], - \"keep_token\": true - } -]" -``` - -### Update a definition - -| Endpoint | Method | -| :------------------------- | :------ | -| /core/cron/definitions/:id | `PATCH` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | -| Content-Type | application/json | - -#### Path variables - -| Variable | Description | -| :------- | :-------------------------------- | -| id | Identifier of the cron definition | - -#### Body - -One or several keys allowed by the add endpoint. - -```json -{ - "id": "", - "timespec": "", - "command": "", - "parameters": "", - "keep_token": "" -} -``` - -#### Example - -```bash -curl --request PATCH "https://hostname:8443/api/core/cron/definitions/job_123" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data "{ - \"timespec\": \"*/2 * * * *\" -}" -``` - -### Delete a definition - -| Endpoint | Method | -| :------------------------- | :------- | -| /core/cron/definitions/:id | `DELETE` | - -#### Headers - -| Header | Value | -| :----- | :--------------- | -| Accept | application/json | - -#### Path variables - -| Variable | Description | -| :------- | :-------------------------------- | -| id | Identifier of the cron definition | - -#### Example - -```bash -curl --request DELETE "https://hostname:8443/api/core/cron/definitions/job_123" \ - --header "Accept: application/json" -``` diff --git a/centreon-gorgone/docs/modules/core/dbcleaner.md b/centreon-gorgone/docs/modules/core/dbcleaner.md deleted file mode 100644 index c80af1aad6..0000000000 --- a/centreon-gorgone/docs/modules/core/dbcleaner.md +++ /dev/null @@ -1,34 +0,0 @@ -# DB Cleaner - -## Description - -This module aims to maintain the Gorgone daemon database by purging entries cyclically. - -The module is loaded by default. Adding it to the configuration will overload daemon default configuration. - -## Configuration - -| Directive | Description | Default value | -| :------------------ | :----------------------------------------------------------------------- | :------------ | -| purge_sessions_time | Time in seconds before deleting sessions in the `gorgone_identity` table | `3600` | -| purge_history_time | Time in seconds before deleting history in the `gorgone_history` table | `604800` | - -#### Example - -```yaml -name: dbcleaner -package: "gorgone::modules::core::dbcleaner::hooks" -enable: true -purge_sessions_time: 3600 -purge_history_time: 604800 -``` - -## Events - -| Event | Description | -| :------------- | :-------------------------------- | -| DBCLEANERREADY | Internal event to notify the core | - -## API - -No API endpoints. diff --git a/centreon-gorgone/docs/modules/core/httpserver.md b/centreon-gorgone/docs/modules/core/httpserver.md deleted file mode 100644 index cae8e874bd..0000000000 --- a/centreon-gorgone/docs/modules/core/httpserver.md +++ /dev/null @@ -1,56 +0,0 @@ -# HTTP Server - -## Description - -This module aims to provide a HTTP/S server to expose handy endpoints to talk to Gorgone. - -It relies on a core API module to server Gorgone events and can dispatch any other piece of code. - -## Configuration - -| Directive | Description | Default value | -| :------------ | :----------------------------------------------- | :------------ | -| address | IP address for the server to bind to | `0.0.0.0` | -| port | Port on which the server will listen to requests | `8080` | -| ssl | Boolean to enable SSL terminaison | `false` | -| ssl_cert_file | Path to the SSL certificate (if SSL enabled) | | -| ssl_key_file | Path to the SSL key (if SSL enabled) | | -| auth | Basic credentials to access the server | | -| allowed_hosts | Peer address to access the server | | - -#### Example - -```yaml -name: httpserver -package: "gorgone::modules::core::httpserver::hooks" -enable: true -address: 0.0.0.0 -port: 8443 -ssl: true -ssl_cert_file: /etc/pki/tls/certs/server-cert.pem -ssl_key_file: /etc/pki/tls/server-key.pem -auth: - enabled: true - user: admin - password: password -allowed_hosts: - enabled: true - subnets: - - 127.0.0.1/32 - - 10.30.2.0/16 -``` - -Below the configuration to add other endpoints: - -```yaml -dispatch: - - endpoint: "/mycode" - method: GET - class: "path::to::my::code" -``` - -## Events - -| Event | Description | -| :-------------- | :-------------------------------- | -| HTTPSERVERREADY | Internal event to notify the core | diff --git a/centreon-gorgone/docs/modules/core/proxy.md b/centreon-gorgone/docs/modules/core/proxy.md deleted file mode 100644 index 5891cee4fb..0000000000 --- a/centreon-gorgone/docs/modules/core/proxy.md +++ /dev/null @@ -1,93 +0,0 @@ -# Proxy - -## Description - -This module aims to give the possibility to Gorgone to become distributed. - -It is not needed in a Centreon standalone configuration, but must be enabled if there is Poller or Remote servers. - -The module includes mechanisms like ping to make sure nodes are alive, synchronisation to store logs in the Central Gorgone database, etc. - -A SSH client library make routing to non-gorgoned nodes possible. - -## Configuration - -| Directive | Description | Default value | -| :------------------- | :------------------------------------------------------------------ | :------------ | -| pool | Number of childs to instantiate to process events | `5` | -| synchistory_time | Time in seconds between two logs synchronisation | `60` | -| synchistory_timeout | Time in seconds before logs synchronisation is considered timed out | `30` | -| ping | Time in seconds between two node pings | `60` | -| pong_discard_timeout | Time in seconds before a node is considered dead | `300` | - -#### Example - -```yaml -name: proxy -package: "gorgone::modules::core::proxy::hooks" -enable: false -pool: 5 -synchistory_time: 60 -synchistory_timeout: 30 -ping: 60 -pong_discard_timeout: 300 -``` - -## Events - -| Event | Description | -| :-------------- | :----------------------------------------------------------------------------- | -| PROXYREADY | Internal event to notify the core | -| REMOTECOPY | Copy files or directories from the server running the daemon to another server | -| SETLOGS | Internal event to insert logs into the database | -| PONG | Internal event to handle node ping response | -| REGISTERNODES | Internal event to register nodes | -| UNREGISTERNODES | Internal event to unregister nodes | -| PROXYADDNODE | Internal event to add nodes for proxying | -| PROXYDELNODE | Internal event to delete nodes from proxying | -| PROXYADDSUBNODE | Internal event to add nodes of nodes for proxying | -| PONGRESET | Internal event to deal with no pong nodes | - -## API - -### Copy files or directory to remote server - -| Endpoint | Method | -| :------------------------- | :----- | -| /api/core/proxy/remotecopy | `POST` | - -#### Headers - -| Header | Value | -| :----------- | :--------------- | -| Accept | application/json | -| Content-Type | application/json | - -#### Body - -| Key | Value | -| :---------- | :------------------------------------------------ | -| source | Path of the source file or directory | -| destination | Path of the destination file or directory | -| cache_dir | Path to the cache directory for archiving purpose | - -```json -{ - "source": "", - "destination": "", - "cache_dir": "" -} -``` - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/core/proxy/remotecopy" \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - --data " { - \"source\": \"/var/cache/centreon/config/engine/2/\", - \"destination\": \"/etc/centreon-engine\", - \"cache_dir\": \"/var/cache/centreon\" -}" -``` diff --git a/centreon-gorgone/docs/modules/core/pull.md b/centreon-gorgone/docs/modules/core/pull.md deleted file mode 100644 index d62357089d..0000000000 --- a/centreon-gorgone/docs/modules/core/pull.md +++ /dev/null @@ -1,25 +0,0 @@ -# Pull - -## Description - -This module should be used on remote nodes where the connection has to be opened from the node to the Central Gorgone. - -## Configuration - -No specific configuration. - -#### Example - -```yaml -name: pull -package: "gorgone::modules::core::pull::hooks" -enable: true -``` - -## Events - -No events. - -## API - -No API endpoints. diff --git a/centreon-gorgone/docs/modules/core/register.md b/centreon-gorgone/docs/modules/core/register.md deleted file mode 100644 index e1db2ebe8e..0000000000 --- a/centreon-gorgone/docs/modules/core/register.md +++ /dev/null @@ -1,96 +0,0 @@ -# Register - -## Description - -This module aims to provide a way to register nodes manually, in opposition to the [pollers](../centreon/pollers.md) module. - -Nodes are either servers running Gorgone daemon or simple equipment with SSH server. - -## Configuration - -There is no specific configuration in the Gorgone daemon configuration file, only a directive to set a path to a dedicated configuration file. - -| Directive | Description | Default value | -| :----------- | :------------------------------------------- | :------------ | -| config\_file | Path to the configuration file listing nodes | | - -#### Example - -```yaml -name: register -package: "gorgone::modules::core::register::hooks" -enable: true -config_file: config/registernodes.yaml -``` - -Nodes are listed in a separate configuration file in a `nodes` table as below: - -##### Using ZMQ (Gorgone running on node) - -| Directive | Description | -| :-------------- | :------------------------------------------------------------------------- | -| id | Unique identifier of the node (can be Poller’s ID if using prevail option) | -| type | Way for the daemon to connect to the node (push\_zmq) | -| address | IP address of the node | -| port | Port to connect to on the node | -| server\_pubkey | Server public key (Default: ask the server pubkey when it connects) | -| client\_pubkey | Client public key (Default: use global public key) | -| client\_privkey | Client private key (Default: use global private key) | -| cipher | Cipher used for encryption (Default: “Cipher::AES”) | -| vector | Encryption vector (Default: 0123456789012345) | -| prevail | Defines if this configuration prevails on `nodes` module configuration | -| nodes | Table to register subnodes managed by node (pathscore is not mandatory) | - -#### Example - -```yaml -nodes: - - id: 4 - type: push_zmq - address: 10.1.2.3 - port: 5556 - nodes: - - id: 2 - pathscore: 1 - - id: 20 - pathscore: 10 -``` - -##### Using SSH - -| Directive | Description | -| :----------------------- | :------------------------------------------------------------------------------------------------ | -| id | Unique identifier of the node (can be Poller’s ID if using prevail option) | -| type | Way for the daemon to connect to the node (push\_ssh) | -| address | IP address of the node | -| ssh\_port | Port to connect to on the node | -| ssh\_directory | Path to the SSH directory, used for files like known\_hosts and identity (private and public key) | -| ssh\_known\_hosts | Path to the known hosts file | -| ssh\_identity | Path to the identity file | -| ssh\_username | SSH username | -| ssh\_password | SSH password (if no SSH key) | -| ssh\_connect\_timeout | Time is seconds before a connection is considered timed out | -| strict\_serverkey\_check | Boolean to strictly check the node fingerprint | -| prevail | Defines if this configuration prevails on `nodes` module configuration | - -#### Example - -```yaml -nodes: - - id: 8 - type: push_ssh - address: 10.4.5.6 - ssh_port: 2222 - ssh_identity: ~/.ssh/the_rsa_key - ssh_username: user - strict_serverkey_check: false - prevail: 1 -``` - -## Events - -No events. - -## API - -No API endpoints. diff --git a/centreon-gorgone/docs/modules/plugins/newtest.md b/centreon-gorgone/docs/modules/plugins/newtest.md deleted file mode 100644 index 6705c91a37..0000000000 --- a/centreon-gorgone/docs/modules/plugins/newtest.md +++ /dev/null @@ -1,137 +0,0 @@ -# IP-Label Newtest - -## Description - -This module aims to retrieve Newtest services. - -It uses the Newtest webservice in order to connect and retrieve the informations of one (or more) Newtest Management Console (NMC). - -By default *newtest* starts X processes (it depends of the configuration). - -Here are the steps done by one process: - -1. Centreon configuration: get the robots and scenarios already configured, - -2. Get the list of robots and scenarios from the NMC, - -3. Create the needed configuration in Centreon with CLAPI (no disable or delete actions), - -4. Get the last status of scenarios from the NMC, - -5. Submit the result to Centreon through *centcore*. - -#### Requirements - -| Dependency | Version | Repository | -| :----------------- | :----------: | :----------------- | -| perl-SOAP-Lite | 1.10 | centreon base | -| perl-TimeDate | 2.30 | redhat/centos base | - -## Configuration - -| Directive | Description | Default value | -| :- | :- | :- | -| clapi_command | Path to the CLAPI binary | `/usr/bin/centreon` | -| clapi_timeout | Time in seconds before CLAPI command execution is considered timed out | `10` | -| clapi_username | CLAPI username | | -| clapi_password | CLAPI username's password | | -| centcore_cmd | Path to centcore command file | `/var/lib/centreon/centcore.cmd` | -| clapi_action_applycfg | CLAPI action used to apply Poller configuration | | -| clapi_generate_config_timeout | Time in seconds before the configuration generation is considered timed out | `180` | -| check_containers_time | Time in seconds between two containers synchronisation | `3600` | - -#### Example - -```yaml -name: newtest -package: "gorgone::modules::plugins::newtest::hooks" -enable: false -check_containers_time: 3600 -clapi_command: /usr/bin/centreon -clapi_username: admin -clapi_password: centreon -clapi_action_applycfg: POLLERRELOAD -centcore_cmd: /var/lib/centreon/centcore.cmd -``` - -Add an entry in the *containers* table with the following attributes per NWC definition: - -| Directive | Description | -| :------------ | :---------- | -| name | Name of the NWC configuration entrie | -| resync_time | Time in seconds between two NWC/Centreon synchronisations | -| nmc_endpoint | Address of the NMC endpoint | -| username | Username to connect to NWC endpoint | -| password | Username's password | -| host_template | Host template used when the daemon creates a host in Centreon | -| host_prefix | Name used when the daemon creates and looks for a host in Centreon | -| service_template | Service template used when the daemon creates a host in Centreon | -| service_prefix | Name used when the daemon creates and looks for a service in Centreon | -| poller_name | Poller used when the daemon creates a host in Centreon | -| list_scenario_status | Informations to look for from the NWC endpoint | - -#### Example - -```yaml -containers: - - name: nwc_1 - resync_time: 300 - nmc_endpoint: "http://__NMC_ADDRESS__/nws/managementconsoleservice.asmx" - username: user - password: pass - host_template: generic-active-host-custom - host_prefix: Robot-%s - service_template: generic-passive-service-custom - service_prefix: Scenario-%s - poller_name: Central - list_scenario_status: '{ "search": "All", "instances": [] }' - - name: nwc_2 - resync_time: 600 - nmc_endpoint: "http://__NMC_ADDRESS__/nws/managementconsoleservice.asmx" - username: user - password: pass - host_template: generic-active-host-custom - host_prefix: Robot-%s - service_template: generic-passive-service-custom - service_prefix: Scenario-%s - poller_name: Central - list_scenario_status: '{ "search": "Robot", "instances": ["XXXX"] }' -``` - -## Events - -| Event | Description | -| :- | :- | -| NEWTESTREADY | Internal event to notify the core | -| NEWTESTRESYNC | Synchronise NWC and Centreon configuration | - -## API - -### Force synchronisation between NWC endpoints and Centreon configuration - -| Endpoint | Method | -| :- | :- | -| /plugins/newtest/resync | `GET` | - -#### Headers - -| Header | Value | -| :- | :- | -| Accept | application/json | - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/plugins/newtest/resync" \ - --header "Accept: application/json" -``` - -## Troubleshooting - -It is possible to get this kind of error in logs of *newtest*: - -```bash -die: syntax error at line 1, column 0, byte 0 at /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi/XML/Parser.pm line 189 -``` - -It often means that a timeout occur. diff --git a/centreon-gorgone/docs/modules/plugins/scom.md b/centreon-gorgone/docs/modules/plugins/scom.md deleted file mode 100644 index a18477da00..0000000000 --- a/centreon-gorgone/docs/modules/plugins/scom.md +++ /dev/null @@ -1,90 +0,0 @@ -# Microsoft SCOM - -## Description - -This module aims to retreive alerts from Microsoft SCOM and store them in Centreon DSM slots. - -## Configuration - -| Directive | Description | Default value | -| :- | :- | :- | -| dsmclient_bin | Path to the Centreon DSM client | `/usr/share/centreon/bin/`dsmclient.pl| -| centcore_cmd | Path to centcore command file | `/var/lib/centreon/centcore.cmd` | -| check_containers_time | Time in seconds between two containers synchronisation | `3600` | - -#### Example - -```yaml -name: scom -package: "gorgone::modules::plugins::scom::hooks" -enable: false -check_containers_time: 3600 -dsmclient_bin: /usr/share/centreon/bin/dsmclient.pl -centcore_cmd: /var/lib/centreon/centcore.cmd -``` - -Add an entry in the *containers* table with the following attributes per SCOM server: - -| Directive | Description | -| :------------ | :---------- | -| name | Name of the SCOM configuration entrie | -| api_version | SCOM API version | -| url | URL of the SCOM API | -| username | Username to connect to SCOM API | -| password | Username's password | -| httpauth | API authentication type | -| resync_time | Time in seconds between two SCOM/Centreon synchronisations | -| dsmhost | Name of the Centreon host to link alerts to | -| dsmslot | Name of the Centreon DSM slots to link alerts to | -| dsmmacro | Name of the Centreon DSM macro to fill | -| dsmalertmessage | Output template for Centreon DSM service when there is an alert | -| dsmrecoverymessage | Output template for Centreon DSM service when alert is recovered | -| curlopts | Options table for Curl library | - -#### Example - -```yaml -containers: - - name: SCOM_prod - api_version: 2016 - url: "http://scomserver/api/" - username: user - password: pass - httpauth: basic - resync_time: 300 - dsmhost: ADH3 - dsmslot: Scom-% - dsmmacro: ALARM_ID - dsmalertmessage: "%{monitoringobjectdisplayname} %{name}" - dsmrecoverymessage: slot ok - curlopts: - CURLOPT_SSL_VERIFYPEER: 0 -``` - -## Events - -| Event | Description | -| :- | :- | -| SCOMREADY | Internal event to notify the core | -| SCOMRESYNC | Synchronise SCOM and Centreon realtime | - -## API - -### Force synchronisation between SCOM endpoints and Centreon realtime - -| Endpoint | Method | -| :- | :- | -| /plugins/scom/resync | `GET` | - -#### Headers - -| Header | Value | -| :- | :- | -| Accept | application/json | - -#### Example - -```bash -curl --request GET "https://hostname:8443/api/plugins/scom/resync" \ - --header "Accept: application/json" -``` diff --git a/centreon-gorgone/docs/poller_pull_configuration.md b/centreon-gorgone/docs/poller_pull_configuration.md deleted file mode 100644 index 852c145b1c..0000000000 --- a/centreon-gorgone/docs/poller_pull_configuration.md +++ /dev/null @@ -1,105 +0,0 @@ -# Architecture - -We are showing how to configure gorgone to manage that architecture: - -```text -Central server <------- Distant Poller -``` - -In our case, we have the following configuration (need to adatp to your configuration). - -* Central server: - * address: 10.30.2.203 -* Distant Poller: - * id: 6 (configured in Centreon interface as **zmq**. You get it in the Centreon interface) - * address: 10.30.2.179 - * rsa public key thumbprint: nJSH9nZN2ugQeksHif7Jtv19RQA58yjxfX-Cpnhx09s - -# Distant Poller - -## Installation - -The Distant Poller is already installed and Gorgone also. - -## Configuration - -We configure the file **/etc/centreon-gorgone/config.d/40-gorgoned.yaml**: - -```yaml -name: distant-server -description: Configuration for distant server -gorgone: - gorgonecore: - id: 6 - privkey: "/var/lib/centreon-gorgone/.keys/rsakey.priv.pem" - pubkey: "/var/lib/centreon-gorgone/.keys/rsakey.pub.pem" - - modules: - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: engine - package: gorgone::modules::centreon::engine::hooks - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" - - - name: pull - package: "gorgone::modules::core::pull::hooks" - enable: true - target_type: tcp - target_path: 10.30.2.203:5556 - ping: 1 -``` - -# Central server - -## Installation - -The Central server is already installed and Gorgone also. - -## Configuration - -We configure the file **/etc/centreon-gorgone/config.d/40-gorgoned.yaml**: - -```yaml -... -gorgone: - gorgonecore: - ... - external_com_type: tcp - external_com_path: "*:5556" - authorized_clients: - - key: nJSH9nZN2ugQeksHif7Jtv19RQA58yjxfX-Cpnhx09s - ... - modules: - ... - - name: register - package: "gorgone::modules::core::register::hooks" - enable: true - config_file: /etc/centreon-gorgone/nodes-register-override.yml - ... -``` - -We create the file **/etc/centreon-gorgone/nodes-register-override.yml**: - -```yaml -nodes: - - id: 6 - type: pull - prevail: 1 -``` diff --git a/centreon-gorgone/docs/rebound_configuration.md b/centreon-gorgone/docs/rebound_configuration.md deleted file mode 100644 index 4a83f5af2c..0000000000 --- a/centreon-gorgone/docs/rebound_configuration.md +++ /dev/null @@ -1,153 +0,0 @@ -# Architecture - -We are showing how to configure gorgone to manage that architecture: - -```text -Central server <------- Rebound server <------- Distant Poller -``` - -In our case, we have the following configuration (need to adatp to your configuration). - -* Central server: - * address: 10.30.2.203 -* Rebound server: - * id: 1024 (It must be unique. It's an arbitrary number) - * address: 10.30.2.67 - * rsa public key thumbprint: NmnPME43IoWpkQoam6CLnrI5hjmdq6Kq8QMUCCg-F4g -* Distant Poller: - * id: 6 (configured in Centreon interface as **zmq**. You get it in the Centreon interface) - * address: 10.30.2.179 - * rsa public key thumbprint: nJSH9nZN2ugQeksHif7Jtv19RQA58yjxfX-Cpnhx09s - -# Distant Poller - -## Installation - -The Distant Poller is already installed and Gorgone also. - -## Configuration - -We configure the file **/etc/centreon-gorgone/config.d/40-gorgoned.yaml**: - -```yaml -name: distant-server -description: Configuration for distant server -gorgone: - gorgonecore: - id: 6 - privkey: "/var/lib/centreon-gorgone/.keys/rsakey.priv.pem" - pubkey: "/var/lib/centreon-gorgone/.keys/rsakey.pub.pem" - - modules: - - name: action - package: gorgone::modules::core::action::hooks - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: - - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ - - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ - - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ - - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ - - ^/usr/lib/centreon/plugins/.*$ - - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ - - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - - ^centreon - - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host - - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - - - name: engine - package: gorgone::modules::centreon::engine::hooks - enable: true - command_file: "/var/lib/centreon-engine/rw/centengine.cmd" - - - name: pull - package: "gorgone::modules::core::pull::hooks" - enable: true - target_type: tcp - target_path: 10.30.2.67:5556 - ping: 1 -``` - -# Rebound server - -## Installation - -We have installed a CentOS 7 server. We install Gorgone daemon: - -```shell -yum install http://yum.centreon.com/standard/20.04/el7/stable/noarch/RPMS/centreon-release-20.04-1.el7.centos.noarch.rpm -yum install centreon-gorgone -``` - -## Configuration - -We configure the file **/etc/centreon-gorgone/config.d/40-gorgoned.yaml**: - -```yaml -name: rebound-server -description: Configuration for rebound-server -gorgone: - gorgonecore: - id: 1024 - privkey: "/var/lib/centreon-gorgone/.keys/rsakey.priv.pem" - pubkey: "/var/lib/centreon-gorgone/.keys/rsakey.pub.pem" - external_com_type: tcp - external_com_path: "*:5556" - authorized_clients: - - key: nJSH9nZN2ugQeksHif7Jtv19RQA58yjxfX-Cpnhx09s - - modules: - - name: proxy - package: "gorgone::modules::core::proxy::hooks" - enable: true - - - name: pull - package: "gorgone::modules::core::pull::hooks" - enable: true - target_type: tcp - target_path: 10.30.2.203:5556 - ping: 1 -``` - -# Central server - -## Installation - -The Central server is already installed and Gorgone also. - -## Configuration - -We configure the file **/etc/centreon-gorgone/config.d/40-gorgoned.yaml**: - -```yaml -... -gorgone: - gorgonecore: - ... - external_com_type: tcp - external_com_path: "*:5556" - authorized_clients: - - key: NmnPME43IoWpkQoam6CLnrI5hjmdq6Kq8QMUCCg-F4g - ... - modules: - ... - - name: register - package: "gorgone::modules::core::register::hooks" - enable: true - config_file: /etc/centreon-gorgone/nodes-register-override.yml - ... -``` - -We create the file **/etc/centreon-gorgone/nodes-register-override.yml**: - -```yaml -nodes: - - id: 1024 - type: pull - prevail: 1 - nodes: - - id: 6 - pathscore: 1 -``` diff --git a/centreon-gorgone/docs/zmq_architecture.svg b/centreon-gorgone/docs/zmq_architecture.svg deleted file mode 100644 index e1027101a5..0000000000 --- a/centreon-gorgone/docs/zmq_architecture.svg +++ /dev/null @@ -1,713 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - DEALER - - - - DEALER - - - - DEALER - - - Interface Web - - - ROUTER - - - - - ROUTER - - - - - - DEALER - - - - ROUTER - - - - - DEALER - - - - DEALER - - gorgone-crond - - - DEALER - - - - - - DEALER - - gorgone-core - gorgone-proxy - gorgone-action - Gorgoned - Agent - - - - - - - - - - - - Flux chiffrés - gorgone-pull - Agent - - diff --git a/centreon-gorgone/gorgone/class/clientzmq.pm b/centreon-gorgone/gorgone/class/clientzmq.pm deleted file mode 100644 index a293c8695c..0000000000 --- a/centreon-gorgone/gorgone/class/clientzmq.pm +++ /dev/null @@ -1,450 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::clientzmq; - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::misc; -use Crypt::Mode::CBC; -use MIME::Base64; -use Scalar::Util; -use ZMQ::FFI qw(ZMQ_DONTWAIT); -use EV; - -my $connectors = {}; -my $callbacks = {}; -my $sockets = {}; - -sub new { - my ($class, %options) = @_; - my $connector = {}; - $connector->{context} = $options{context}; - $connector->{logger} = $options{logger}; - $connector->{identity} = $options{identity}; - $connector->{extra_identity} = gorgone::standard::library::generate_token(length => 12); - $connector->{core_loop} = $options{core_loop}; - - $connector->{verbose_last_message} = ''; - $connector->{config_core} = $options{config_core}; - - if (defined($connector->{config_core}) && defined($connector->{config_core}->{fingerprint_mgr}->{package})) { - my ($code, $class_mgr) = gorgone::standard::misc::mymodule_load( - logger => $connector->{logger}, - module => $connector->{config_core}->{fingerprint_mgr}->{package}, - error_msg => "Cannot load module $connector->{config_core}->{fingerprint_mgr}->{package}" - ); - if ($code == 0) { - $connector->{fingerprint_mgr} = $class_mgr->new( - logger => $connector->{logger}, - config => $connector->{config_core}->{fingerprint_mgr}, - config_core => $connector->{config_core} - ); - } - } - - if (defined($options{server_pubkey}) && $options{server_pubkey} ne '') { - (undef, $connector->{server_pubkey}) = gorgone::standard::library::loadpubkey( - pubkey => $options{server_pubkey}, - logger => $options{logger} - ); - } - (undef, $connector->{client_pubkey}) = gorgone::standard::library::loadpubkey( - pubkey => $options{client_pubkey}, - logger => $options{logger} - ); - (undef, $connector->{client_privkey}) = gorgone::standard::library::loadprivkey( - privkey => $options{client_privkey}, - logger => $options{logger} - ); - $connector->{target_type} = $options{target_type}; - $connector->{target_path} = $options{target_path}; - $connector->{ping} = defined($options{ping}) ? $options{ping} : -1; - $connector->{ping_timeout} = defined($options{ping_timeout}) ? $options{ping_timeout} : 30; - $connector->{ping_progress} = 0; - $connector->{ping_time} = time(); - $connector->{ping_timeout_time} = time(); - - if (defined($connector->{logger}) && $connector->{logger}->is_debug()) { - $connector->{logger}->writeLogDebug('[core] JWK thumbprint = ' . $connector->{client_pubkey}->export_key_jwk_thumbprint('SHA256')); - } - - $connectors->{ $options{identity} } = $connector; - bless $connector, $class; - return $connector; -} - -sub init { - my ($self, %options) = @_; - - $self->{handshake} = 0; - delete $self->{server_pubkey}; - $sockets->{ $self->{identity} } = gorgone::standard::library::connect_com( - context => $self->{context}, - zmq_type => 'ZMQ_DEALER', - name => $self->{identity} . '-' . $self->{extra_identity}, - logger => $self->{logger}, - type => $self->{target_type}, - path => $self->{target_path}, - zmq_ipv6 => $self->{config_core}->{ipv6} - ); - $callbacks->{ $self->{identity} } = $options{callback} if (defined($options{callback})); -} - -sub close { - my ($self, %options) = @_; - - delete $self->{core_watcher}; - $sockets->{ $self->{identity} }->close(); -} - -sub get_connect_identity { - my ($self, %options) = @_; - - return $self->{identity} . '-' . $self->{extra_identity}; -} - -sub get_server_pubkey { - my ($self, %options) = @_; - - $sockets->{ $self->{identity} }->send('[GETPUBKEY]', ZMQ_DONTWAIT); - $self->event(identity => $self->{identity}); - - my $w1 = $self->{connect_loop}->timer( - 10, - 0, - sub { - $self->{connect_loop}->break(); - } - ); - $self->{connect_loop}->run(); -} - -sub read_key_protocol { - my ($self, %options) = @_; - - $self->{logger}->writeLogDebug('[clientzmq] ' . $self->{identity} . ' - read key protocol: ' . $options{text}); - - return (-1, 'Wrong protocol') if ($options{text} !~ /^\[KEY\]\s+(.*)$/); - - my $data = gorgone::standard::library::json_decode(module => 'clientzmq', data => $1, logger => $self->{logger}); - return (-1, 'Wrong protocol') if (!defined($data)); - - return (-1, 'Wrong protocol') if ( - !defined($data->{hostname}) || - !defined($data->{key}) || $data->{key} eq '' || - !defined($data->{cipher}) || $data->{cipher} eq '' || - !defined($data->{iv}) || $data->{iv} eq '' || - !defined($data->{padding}) || $data->{padding} eq '' - ); - - $self->{key} = pack('H*', $data->{key}); - $self->{iv} = pack('H*', $data->{iv}); - $self->{cipher} = $data->{cipher}; - $self->{padding} = $data->{padding}; - - $self->{crypt_mode} = Crypt::Mode::CBC->new( - $self->{cipher}, - $self->{padding} - ); - - return (0, 'ok'); -} - -sub decrypt_message { - my ($self, %options) = @_; - - my $plaintext; - eval { - $plaintext = $self->{crypt_mode}->decrypt( - MIME::Base64::decode_base64($options{message}), - $self->{key}, - $self->{iv} - ); - }; - if ($@) { - $self->{logger}->writeLogError("[clientzmq] $self->{identity} - decrypt message issue: " . $@); - return (-1, $@); - } - return (0, $plaintext); -} - -sub client_get_secret { - my ($self, %options) = @_; - - # there is an issue - if ($options{message} =~ /^\[ACK\]/) { - return (-1, "issue: $options{message}"); - } - - my $plaintext; - eval { - my $cryptedtext = MIME::Base64::decode_base64($options{message}); - $plaintext = $self->{client_privkey}->decrypt($cryptedtext, 'v1.5'); - }; - if ($@) { - return (-1, "Decoding issue: $@"); - } - - return $self->read_key_protocol(text => $plaintext); -} - -sub check_server_pubkey { - my ($self, %options) = @_; - - $self->{logger}->writeLogDebug("[clientzmq] $self->{identity} - get_server_pubkey check [1]"); - - if ($options{message} !~ /^\s*\[PUBKEY\]\s+\[(.*?)\]/) { - $self->{logger}->writeLogError('[clientzmq] ' . $self->{identity} . ' - cannot read pubbkey response from server: ' . $options{message}) if (defined($self->{logger})); - $self->{verbose_last_message} = 'cannot read pubkey response from server'; - return 0; - } - - my ($code, $verbose_message); - my $server_pubkey_str = MIME::Base64::decode_base64($1); - ($code, $self->{server_pubkey}) = gorgone::standard::library::loadpubkey( - pubkey_str => $server_pubkey_str, - logger => $self->{logger}, - noquit => 1 - ); - - if ($code == 0) { - $self->{logger}->writeLogError('[clientzmq] ' . $self->{identity} . ' cannot load pubbkey') if (defined($self->{logger})); - $self->{verbose_last_message} = 'cannot load pubkey'; - return 0; - } - - # if not set, we are in 'always' mode - if (defined($self->{fingerprint_mgr})) { - my $thumbprint = $self->{server_pubkey}->export_key_jwk_thumbprint('SHA256'); - ($code, $verbose_message) = $self->{fingerprint_mgr}->check_fingerprint( - target => $self->{target_type} . '://' . $self->{target_path}, - fingerprint => $thumbprint - ); - if ($code == 0) { - $self->{logger}->writeLogError($verbose_message) if (defined($self->{logger})); - $self->{verbose_last_message} = $verbose_message; - return 0; - } - } - - $self->{logger}->writeLogDebug("[clientzmq] $self->{identity} - get_server_pubkey ok [1]"); - - return 1; -} - -sub is_connected { - my ($self, %options) = @_; - - # Should be connected (not 100% sure) - if ($self->{handshake} == 2) { - return (0, $self->{ping_time}); - } - return -1; -} - -sub ping { - my ($self, %options) = @_; - my $status = 0; - - if ($self->{ping} > 0 && $self->{ping_progress} == 0 && - time() - $self->{ping_time} > $self->{ping}) { - $self->{ping_progress} = 1; - $self->{ping_timeout_time} = time(); - my $action = defined($options{action}) ? $options{action} : 'PING'; - $self->send_message(action => $action, data => $options{data}, json_encode => $options{json_encode}); - $status = 1; - } - - if ($self->{ping_progress} == 1 && - time() - $self->{ping_timeout_time} > $self->{ping_timeout}) { - $self->{logger}->writeLogError("[clientzmq] No ping response") if (defined($self->{logger})); - $self->{ping_progress} = 0; - $sockets->{ $self->{identity} }->close(); - delete $self->{core_watcher}; - - $self->init(); - $status = 1; - } - - return $status; -} - -sub add_watcher { - my ($self, %options) = @_; - - $self->{core_watcher} = $self->{core_loop}->io( - $sockets->{ $self->{identity} }->get_fd(), - EV::READ, - sub { - $self->event(identity => $self->{identity}); - } - ); -} - -sub event { - my ($self, %options) = @_; - - $connectors->{ $options{identity} }->{ping_time} = time(); - while ($sockets->{ $options{identity} }->has_pollin()) { - # We have a response. So it's ok :) - if ($connectors->{ $options{identity} }->{ping_progress} == 1) { - $connectors->{ $options{identity} }->{ping_progress} = 0; - } - - my ($rv, $message) = gorgone::standard::library::zmq_dealer_read_message(socket => $sockets->{ $options{identity} }); - last if ($rv); - - # in progress - if ($connectors->{ $options{identity} }->{handshake} == 0) { - $self->{connect_loop}->break(); - $connectors->{ $options{identity} }->{handshake} = 1; - if ($connectors->{ $options{identity} }->check_server_pubkey(message => $message) == 0) { - $connectors->{ $options{identity} }->{handshake} = -1; - - } - } elsif ($connectors->{ $options{identity} }->{handshake} == 1) { - $self->{connect_loop}->break(); - - $self->{logger}->writeLogDebug("[clientzmq] $self->{identity} - client_get_secret recv [3]"); - my ($status, $verbose, $symkey, $hostname) = $connectors->{ $options{identity} }->client_get_secret( - message => $message - ); - if ($status == -1) { - $self->{logger}->writeLogDebug("[clientzmq] $self->{identity} - client_get_secret $verbose [3]"); - $connectors->{ $options{identity} }->{handshake} = -1; - $connectors->{ $options{identity} }->{verbose_last_message} = $verbose; - return ; - } - $connectors->{ $options{identity} }->{handshake} = 2; - if (defined($connectors->{ $options{identity} }->{logger})) { - $connectors->{ $options{identity} }->{logger}->writeLogInfo( - "[clientzmq] $self->{identity} - Client connected successfully to '" . $connectors->{ $options{identity} }->{target_type} . - "://" . $connectors->{ $options{identity} }->{target_path} . "'" - ); - $self->add_watcher(); - } - } else { - my ($rv, $data) = $connectors->{ $options{identity} }->decrypt_message(message => $message); - - if ($rv == -1 || $data !~ /^\[([a-zA-Z0-9:\-_]+?)\]\s+/) { - $connectors->{ $options{identity} }->{handshake} = -1; - $connectors->{ $options{identity} }->{verbose_last_message} = 'decrypt issue: ' . $data; - return ; - } - - if ($1 eq 'KEY') { - ($rv) = $connectors->{ $options{identity} }->read_key_protocol(text => $data); - } elsif (defined($callbacks->{$options{identity}})) { - $callbacks->{$options{identity}}->(identity => $options{identity}, data => $data); - } - } - } -} - -sub zmq_send_message { - my ($self, %options) = @_; - - my $message = $options{message}; - if (!defined($message)) { - $message = gorgone::standard::library::build_protocol(%options); - } - - eval { - $message = $self->{crypt_mode}->encrypt( - $message, - $self->{key}, - $self->{iv} - ); - $message = MIME::Base64::encode_base64($message, ''); - }; - if ($@) { - $self->{logger}->writeLogError("[clientzmq] encrypt message issue: " . $@); - return undef; - } - - $options{socket}->send($message, ZMQ_DONTWAIT); - $self->event(identity => $self->{identity}); -} - -sub send_message { - my ($self, %options) = @_; - - if ($self->{handshake} == 0) { - $self->{connect_loop} = new EV::Loop(); - $self->{connect_watcher} = $self->{connect_loop}->io( - $sockets->{ $self->{identity} }->get_fd(), - EV::READ, - sub { - $self->event(identity => $self->{identity}); - } - ); - - if (!defined($self->{server_pubkey})) { - $self->{logger}->writeLogDebug("[clientzmq] $self->{identity} - get_server_pubkey sent [1]"); - $self->get_server_pubkey(); - } else { - $self->{handshake} = 1; - } - } - - if ($self->{handshake} == 1) { - my ($status, $ciphertext) = gorgone::standard::library::client_helo_encrypt( - identity => $self->{identity}, - server_pubkey => $self->{server_pubkey}, - client_pubkey => $self->{client_pubkey}, - ); - if ($status == -1) { - $self->{logger}->writeLogDebug("[clientzmq] $self->{identity} - client_helo crypt handshake issue [2]"); - $self->{verbose_last_message} = 'crypt handshake issue'; - return (-1, $self->{verbose_last_message}); - } - - $self->{logger}->writeLogDebug("[clientzmq] $self->{identity} - client_helo sent [2]"); - - $self->{verbose_last_message} = 'Handshake timeout'; - $sockets->{ $self->{identity} }->send($ciphertext, ZMQ_DONTWAIT); - $self->event(identity => $self->{identity}); - - my $w1 = $self->{connect_loop}->timer( - 10, - 0, - sub { $self->{connect_loop}->break(); } - ); - $self->{connect_loop}->run(); - } - - undef $self->{connect_loop} if (defined($self->{connect_loop})); - - if ($self->{handshake} < 2) { - $self->{handshake} = 0; - return (-1, $self->{verbose_last_message}); - } - - $self->zmq_send_message( - socket => $sockets->{ $self->{identity} }, - %options - ); - - return 0; -} - -1; diff --git a/centreon-gorgone/gorgone/class/core.pm b/centreon-gorgone/gorgone/class/core.pm deleted file mode 100644 index b432de3072..0000000000 --- a/centreon-gorgone/gorgone/class/core.pm +++ /dev/null @@ -1,1326 +0,0 @@ -# -# Copyright 2023 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::core; - -use strict; -use warnings; -use POSIX ":sys_wait_h"; -use MIME::Base64; -use Crypt::Mode::CBC; -use ZMQ::FFI qw(ZMQ_DONTWAIT ZMQ_SNDMORE); -use EV; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use gorgone::class::db; -use gorgone::class::listener; -use gorgone::class::frame; -use Time::HiRes; -use Try::Tiny; - -my ($gorgone); - -use base qw(gorgone::class::script); - -my $VERSION = '23.10.0'; -my %handlers = (TERM => {}, HUP => {}, CHLD => {}, DIE => {}); - -sub new { - my $class = shift; - my $self = $class->SUPER::new( - 'gorgoned', - centreon_db_conn => 0, - centstorage_db_conn => 0, - noconfig => 1 - ); - - bless $self, $class; - - $self->{return_child} = {}; - $self->{stop} = 0; - $self->{internal_register} = {}; - $self->{modules_register} = {}; - $self->{modules_events} = {}; - $self->{modules_id} = {}; - $self->{purge_timer} = time(); - $self->{history_timer} = time(); - $self->{sigterm_start_time} = undef; - $self->{sigterm_last_time} = undef; - $self->{server_privkey} = undef; - $self->{register_parent_nodes} = {}; - $self->{counters} = { total => 0, internal => { total => 0 }, external => { total => 0 }, proxy => { total => 0 } }; - $self->{api_endpoints} = { - 'GET_/internal/thumbprint' => 'GETTHUMBPRINT', - 'GET_/internal/constatus' => 'CONSTATUS', - 'GET_/internal/information' => 'INFORMATION', - 'POST_/internal/logger' => 'BCASTLOGGER', - }; - - return $self; -} - -sub get_version { - my ($self, %options) = @_; - - return $VERSION; -} - -sub init_server_keys { - my ($self, %options) = @_; - - my ($code, $content_privkey, $content_pubkey); - $self->{logger}->writeLogInfo("[core] Initialize server keys"); - - $self->{keys_loaded} = 0; - $self->{config} = { configuration => {} } if (!defined($self->{config}->{configuration})); - $self->{config}->{configuration} = { gorgone => {} } if (!defined($self->{config}->{configuration}->{gorgone})); - $self->{config}->{configuration}->{gorgone}->{gorgonecore} = {} if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore})); - - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey} = '/var/lib/centreon-gorgone/.keys/rsakey.priv.pem' - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey} = '/var/lib/centreon-gorgone/.keys/rsakey.pub.pem' - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey} eq ''); - - if (! -f $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey} && ! -f $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey}) { - ($code, $content_privkey, $content_pubkey) = gorgone::standard::library::generate_keys(logger => $self->{logger}); - return if ($code == 0); - $code = gorgone::standard::misc::write_file( - logger => $self->{logger}, - filename => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey}, - content => $content_privkey, - ); - return if ($code == 0); - $self->{logger}->writeLogInfo("[core] Private key file '$self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey}' written"); - - $code = gorgone::standard::misc::write_file( - logger => $self->{logger}, - filename => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey}, - content => $content_pubkey, - ); - return if ($code == 0); - $self->{logger}->writeLogInfo("[core] Public key file '$self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey}' written"); - } - - my $rv = chmod(0600, $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey}); - if ($rv == 0) { - $self->{logger}->writeLogInfo("[core] chmod private key file '$self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey}': $!"); - } - $rv = chmod(0640, $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey}); - if ($rv == 0) { - $self->{logger}->writeLogInfo("[core] chmod public key file '$self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey}': $!"); - } - - ($code, $self->{server_privkey}) = gorgone::standard::library::loadprivkey( - logger => $self->{logger}, - privkey => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey}, - noquit => 1 - ); - return if ($code == 0); - $self->{logger}->writeLogInfo("[core] Private key file '$self->{config}->{configuration}->{gorgone}->{gorgonecore}->{privkey}' loaded"); - - ($code, $self->{server_pubkey}) = gorgone::standard::library::loadpubkey( - logger => $self->{logger}, - pubkey => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey}, - noquit => 1 - ); - return if ($code == 0); - $self->{logger}->writeLogInfo("[core] Public key file '$self->{config}->{configuration}->{gorgone}->{gorgonecore}->{pubkey}' loaded"); - - $self->{keys_loaded} = 1; -} - -sub init { - my ($self) = @_; - $self->SUPER::init(); - - # redefine to avoid out when we try modules - $SIG{__DIE__} = undef; - - ## load config - if (!defined($self->{config_file})) { - $self->{logger}->writeLogError('[core] please define config file option'); - exit(1); - } - if (! -f $self->{config_file}) { - $self->{logger}->writeLogError("[core] can't find config file '$self->{config_file}'"); - exit(1); - } - $self->{config} = $self->yaml_load_config( - file => $self->{config_file}, - filter => '!($ariane eq "configuration##" || $ariane =~ /^configuration##(?:gorgone|centreon)##/)' - ); - $self->init_server_keys(); - - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_zmq_tcp_keepalive} = - defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_zmq_tcp_keepalive}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_zmq_tcp_keepalive} =~ /^(0|1)$/ ? $1 : 1; - - my $time_hi = Time::HiRes::time(); - $time_hi =~ s/\.//; - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_type} = 'ipc' - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_type}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_type} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_path} = '/tmp/gorgone/routing-' . $time_hi . '.ipc' - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_path}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_path} eq ''); - - if (defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_crypt}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_crypt} =~ /^(?:false|0)$/i) { - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_crypt} = 0; - } else { - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_crypt} = 1; - } - - $self->{internal_crypt} = { enabled => 0 }; - if ($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_crypt} == 1) { - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_cipher} = 'AES' - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_cipher}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_cipher} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_padding} = 1 # PKCS5 padding - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_padding}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_padding} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_keysize} = 32 - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_keysize}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_keysize} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_rotation} = 1440 # minutes - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_rotation}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_rotation} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_rotation} *= 60; - - $self->{cipher} = Crypt::Mode::CBC->new( - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_cipher}, - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_padding} - ); - - my ($rv, $symkey, $iv); - ($rv, $symkey) = gorgone::standard::library::generate_symkey( - keysize => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_keysize} - ); - ($rv, $iv) = gorgone::standard::library::generate_symkey( - keysize => 16 - ); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key_ctime} = time(); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key} = $symkey; - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_oldkey} = undef; - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_identity_keys} = {}; - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_iv} = $iv; - - $self->{internal_crypt} = { - enabled => 1, - cipher => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_cipher}, - padding => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_padding}, - iv => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_iv} - }; - } - - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{timeout} = - defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{timeout}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{timeout} =~ /(\d+)/ ? $1 : 50; - - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_cipher} = 'AES' - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_cipher}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_cipher} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_padding} = 1 # PKCS5 padding - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_padding}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_padding} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_keysize} = 32 - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_keysize}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_keysize} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_rotation} = 1440 # minutes - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_rotation}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_rotation} eq ''); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_rotation} *= 60; - - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mode} = - defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mode}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mode} =~ /^\s*(always|firt|strict)\s*/i ? lc($1) : 'first'; - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mgr} = {} if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mgr})); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mgr}->{package} = 'gorgone::class::fingerprint::backend::sql' - if (!defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mgr}->{package}) || $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mgr}->{package} eq ''); - - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mode} = - defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mode}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{fingerprint_mode} =~ /^\s*(always|firt|strict)\s*/i ? lc($1) : 'first'; - - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_type} = - defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_type}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_type} ne '' ? $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_type} : 'SQLite'; - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_name} = - defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_name}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_name} ne '' ? $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_name} : 'dbname=/var/lib/centreon-gorgone/history.sdb'; - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_autocreate_schema} = - defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_autocreate_schema}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_autocreate_schema} =~ /(\d+)/ ? $1 : 1; - gorgone::standard::library::init_database( - gorgone => $gorgone, - version => $self->get_version(), - type => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_type}, - db => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_name}, - host => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_host}, - port => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_port}, - user => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_user}, - password => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_password}, - autocreate_schema => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{gorgone_db_autocreate_schema}, - force => 2, - logger => $gorgone->{logger} - ); - - $self->{hostname} = $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{hostname}; - if (!defined($self->{hostname}) || $self->{hostname} eq '') { - my ($sysname, $nodename, $release, $version, $machine) = POSIX::uname(); - $self->{hostname} = $sysname; - } - - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{proxy_name} = - (defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{proxy_name}) && $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{proxy_name} ne '') ? $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{proxy_name} : 'proxy'; - $self->{id} = $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{id}; - - $self->load_modules(); - - $self->set_signal_handlers(); -} - -sub init_external_informations { - my ($self) = @_; - - my ($status, $sth) = $self->{db_gorgone}->query({ - query => "SELECT `identity`, `ctime`, `mtime`, `key`, `oldkey`, `iv`, `oldiv` FROM gorgone_identity ORDER BY id DESC" - }); - if ($status == -1) { - $self->{logger}->writeLogError("[core] cannot load gorgone_identity"); - return 0; - } - - $self->{identity_infos} = {}; - while (my $row = $sth->fetchrow_arrayref()) { - next if (!defined($row->[3]) || !defined($row->[2])); - - if (!defined($self->{identity_infos}->{ $row->[0] })) { - $self->{identity_infos}->{ $row->[0] } = { - ctime => $row->[1], - mtime => $row->[2], - key => pack('H*', $row->[3]), - oldkey => defined($row->[4]) ? pack('H*', $row->[4]) : undef, - iv => pack('H*', $row->[5]), - oldiv => defined($row->[6]) ? pack('H*', $row->[6]) : undef - }; - } - } - - $self->{external_crypt_mode} = Crypt::Mode::CBC->new( - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_cipher}, - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_padding} - ); -} - -sub set_signal_handlers { - my ($self) = @_; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; - $SIG{CHLD} = \&class_handle_CHLD; - $handlers{CHLD}->{$self} = sub { $self->handle_CHLD() }; - $SIG{__DIE__} = \&class_handle_DIE; - $handlers{DIE}->{$self} = sub { $self->handle_DIE($_[0]) }; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub class_handle_CHLD { - foreach (keys %{$handlers{CHLD}}) { - &{$handlers{CHLD}->{$_}}(); - } -} - -sub class_handle_DIE { - my ($msg) = @_; - - foreach (keys %{$handlers{DIE}}) { - &{$handlers{DIE}->{$_}}($msg); - } -} - -sub handle_TERM { - my ($self) = @_; - $self->{logger}->writeLogInfo("[core] $$ Receiving order to stop..."); - - $self->{stop} = 1; -} - -sub handle_HUP { - my $self = shift; - $self->{logger}->writeLogInfo("[core] $$ Receiving order to reload..."); - # TODO -} - -sub handle_CHLD { - my $self = shift; - my $child_pid; - - while (($child_pid = waitpid(-1, &WNOHANG)) > 0) { - $self->{logger}->writeLogDebug("[core] Received SIGCLD signal (pid: $child_pid)"); - $self->{return_child}->{$child_pid} = time(); - } - - $SIG{CHLD} = \&class_handle_CHLD; -} - -sub handle_DIE { - my $self = shift; - my $msg = shift; - - $self->{logger}->writeLogError("[core] Receiving DIE: $msg"); -} - -sub unload_module { - my ($self, %options) = @_; - - foreach my $event (keys %{$self->{modules_events}}) { - if ($self->{modules_events}->{$event}->{module}->{package} eq $options{package}) { - delete $self->{modules_events}->{$event}; - } - } - - delete $self->{modules_register}->{ $options{package} }; - foreach (keys %{$self->{modules_id}}) { - if ($self->{modules_id}->{$_} eq $options{package}) { - delete $self->{modules_id}->{$_}; - last; - } - } - $self->{logger}->writeLogInfo("[core] Module '" . $options{package} . "' is unloaded"); -} - -sub load_module { - my ($self, %options) = @_; - - if (!defined($options{config_module}->{name}) || $options{config_module}->{name} eq '') { - $self->{logger}->writeLogError('[core] No module name'); - return 0; - } - if (!defined($options{config_module}->{package}) || $options{config_module}->{package} eq '') { - $self->{logger}->writeLogError('[core] No package name'); - return 0; - } - if (defined($self->{modules_register}->{ $options{config_module}->{package} })) { - $self->{logger}->writeLogError("[core] Package '$options{config_module}->{package}' already loaded"); - return 0; - } - - return 0 if (!defined($options{config_module}->{enable}) || $options{config_module}->{enable} eq 'false'); - $self->{logger}->writeLogInfo("[core] Module '" . $options{config_module}->{name} . "' is loading"); - - my $package = $options{config_module}->{package}; - (my $file = "$package.pm") =~ s{::}{/}g; - eval { - local $SIG{__DIE__} = 'IGNORE'; - require $file; - }; - if ($@) { - $self->{logger}->writeLogInfo("[core] Module '" . $options{config_module}->{name} . "' cannot be loaded: " . $@); - return 0; - } - $self->{modules_register}->{$package} = {}; - - foreach my $method_name (('register', 'routing', 'kill', 'kill_internal', 'gently', 'check', 'init', 'broadcast')) { - unless ($self->{modules_register}->{$package}->{$method_name} = $package->can($method_name)) { - delete $self->{modules_register}->{$package}; - $self->{logger}->writeLogError("[core] No function '$method_name' for module '" . $options{config_module}->{name} . "'"); - return 0; - } - } - - my ($loaded, $namespace, $name, $events) = $self->{modules_register}->{$package}->{register}->( - config => $options{config_module}, - config_core => $self->{config}->{configuration}->{gorgone}, - config_db_centreon => $self->{config}->{configuration}->{centreon}->{database}->{db_configuration}, - config_db_centstorage => $self->{config}->{configuration}->{centreon}->{database}->{db_realtime}, - logger => $self->{logger} - ); - if ($loaded == 0) { - delete $self->{modules_register}->{$package}; - $self->{logger}->writeLogError("[core] Module '" . $options{config_module}->{name} . "' cannot be loaded"); - return 0; - } - - $self->{modules_id}->{$name} = $package; - - foreach my $event (@$events) { - $self->{modules_events}->{$event->{event}} = { - module => { - namespace => $namespace, - name => $name, - package => $package - } - }; - $self->{api_endpoints}->{$event->{method} . '_/' . $namespace . '/' . $name . $event->{uri}} = $event->{event} if defined($event->{uri}); - } - - $self->{logger}->writeLogInfo("[core] Module '" . $options{config_module}->{name} . "' is loaded"); - return 1; -} - -sub load_modules { - my ($self) = @_; - return if (!defined($self->{config}->{configuration}->{gorgone}->{modules})); - - foreach my $module (@{$self->{config}->{configuration}->{gorgone}->{modules}}) { - $self->load_module(config_module => $module); - } - - # force to load module dbclean - $self->load_module(config_module => { name => 'dbcleaner', package => 'gorgone::modules::core::dbcleaner::hooks', enable => 'true' }); - - # Load internal functions - foreach my $method_name (('addlistener', 'putlog', 'getlog', 'kill', 'ping', - 'getthumbprint', 'constatus', 'setcoreid', 'synclogs', 'loadmodule', 'unloadmodule', 'information', 'setmodulekey')) { - unless ($self->{internal_register}->{$method_name} = gorgone::standard::library->can($method_name)) { - $self->{logger}->writeLogError("[core] No function '$method_name'"); - exit(1); - } - } -} - -sub broadcast_core_key { - my ($self, %options) = @_; - - my ($rv, $key) = gorgone::standard::library::generate_symkey( - keysize => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_keysize} - ); - - my $message = '[BCASTCOREKEY] [] [] { "key": "' . unpack('H*', $key). '"}'; - my $frame = gorgone::class::frame->new(); - $frame->setFrame(\$message); - - $self->message_run( - { - frame => $frame, - router_type => 'internal' - } - ); -} - -sub decrypt_internal_message { - my ($self, %options) = @_; - - if ($self->{internal_crypt}->{enabled} == 1) { - my $id = pack('H*', $options{identity}); - my $keys; - if (defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_identity_keys}->{$id})) { - $keys = [ $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_identity_keys}->{$id}->{key} ]; - } else { - $keys = [ $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key} ]; - push @$keys, $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_oldkey} - if (defined($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_oldkey})); - } - foreach my $key (@$keys) { - if ($options{frame}->decrypt({ cipher => $self->{cipher}, key => $key, iv => $self->{internal_crypt}->{iv} }) == 0) { - return 0; - } - } - - $self->{logger}->writeLogError("[core] decrypt issue ($id): " . $options{frame}->getLastError()); - return 1; - } - - return 0; -} - -sub send_internal_response { - my ($self, %options) = @_; - - my $response_type = defined($options{response_type}) ? $options{response_type} : 'ACK'; - my $data = gorgone::standard::library::json_encode(data => { code => $options{code}, data => $options{data} }); - # We add 'target' for 'PONG', 'SYNCLOGS'. Like that 'gorgone-proxy can get it - my $message = '[' . $response_type . '] [' . (defined($options{token}) ? $options{token} : '') . '] ' . ($response_type =~ /^PONG|SYNCLOGS$/ ? '[] ' : '') . $data; - - if ($self->{internal_crypt}->{enabled} == 1) { - try { - $message = $self->{cipher}->encrypt( - $message, - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key}, - $self->{internal_crypt}->{iv} - ); - } catch { - $self->{logger}->writeLogError("[core] encrypt issue: $_"); - return undef; - }; - - $message = MIME::Base64::encode_base64($message, ''); - } - - $self->{internal_socket}->send(pack('H*', $options{identity}), ZMQ_DONTWAIT | ZMQ_SNDMORE); - $self->{internal_socket}->send($message, ZMQ_DONTWAIT); -} - -sub send_internal_message { - my ($self, %options) = @_; - - my $message = $options{message}; - if (!defined($message)) { - $message = gorgone::standard::library::build_protocol(%options); - } - - if ($self->{internal_crypt}->{enabled} == 1) { - try { - $message = $self->{cipher}->encrypt( - $message, - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key}, - $self->{internal_crypt}->{iv} - ); - } catch { - $self->{logger}->writeLogError("[core] encrypt issue: $_"); - return undef; - }; - - $message = MIME::Base64::encode_base64($message, ''); - } - - $self->{internal_socket}->send($options{identity}, ZMQ_DONTWAIT | ZMQ_SNDMORE); - $self->{internal_socket}->send($message, ZMQ_DONTWAIT); -} - -sub broadcast_run { - my ($self, %options) = @_; - - my $data = $options{frame}->decodeData(); - return if (!defined($data)); - - if ($options{action} eq 'BCASTLOGGER') { - if (defined($data->{content}->{severity}) && $data->{content}->{severity} ne '') { - if ($data->{content}->{severity} eq 'default') { - $self->{logger}->set_default_severity(); - } else { - $self->{logger}->severity($data->{content}->{severity}); - } - } - } - - foreach (keys %{$self->{modules_register}}) { - $self->{modules_register}->{$_}->{broadcast}->( - gorgone => $self, - dbh => $self->{db_gorgone}, - action => $options{action}, - logger => $self->{logger}, - frame => $options{frame}, - token => $options{token} - ); - } - - if ($options{action} eq 'BCASTCOREKEY') { - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key_ctime} = time(); - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_oldkey} = $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key}; - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key} = pack('H*', $data->{key}); - } -} - -sub message_run { - my ($self, $options) = (shift, shift); - - if ($self->{logger}->is_debug()) { - my $frame_ref = $options->{frame}->getFrame(); - $self->{logger}->writeLogDebug('[core] Message received ' . $options->{router_type} . ' - ' . $$frame_ref); - } - if ($options->{frame}->parse({ releaseFrame => 1 }) != 0) { - return (undef, 1, { message => 'request not well formatted' }); - } - my ($action, $token, $target) = ($options->{frame}->getAction(), $options->{frame}->getToken(), $options->{frame}->getTarget()); - - # Check if not myself ;) - if (defined($target) && ($target eq '' || (defined($self->{id}) && $target eq $self->{id}))) { - $target = undef; - } - - if (!defined($token) || $token eq '') { - $token = gorgone::standard::library::generate_token(); - } - - if ($action !~ /^(?:ADDLISTENER|PUTLOG|GETLOG|KILL|PING|CONSTATUS|SETCOREID|SETMODULEKEY|SYNCLOGS|LOADMODULE|UNLOADMODULE|INFORMATION|GETTHUMBPRINT|BCAST.*)$/ && - !defined($target) && !defined($self->{modules_events}->{$action})) { - gorgone::standard::library::add_history({ - dbh => $self->{db_gorgone}, - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { error => "unknown_action", message => "action '$action' is unknown" }, - json_encode => 1 - }); - return (undef, 1, { error => "unknown_action", message => "action '$action' is unknown" }); - } - - $self->{counters}->{ $options->{router_type} }->{lc($action)} = 0 if (!defined($self->{counters}->{ $options->{router_type} }->{lc($action)})); - $self->{counters}->{ $options->{router_type} }->{lc($action)}++; - $self->{counters}->{total}++; - $self->{counters}->{ $options->{router_type} }->{total}++; - - if ($self->{stop} == 1) { - gorgone::standard::library::add_history({ - dbh => $self->{db_gorgone}, - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { message => 'gorgone is stopping/restarting. Cannot proceed request.' }, - json_encode => 1 - }); - return ($token, 1, { message => 'gorgone is stopping/restarting. Cannot proceed request.' }); - } - - # Check Routing - if (defined($target)) { - if (!defined($self->{modules_id}->{ $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{proxy_name} }) || - !defined($self->{modules_register}->{ $self->{modules_id}->{ $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{proxy_name} } })) { - gorgone::standard::library::add_history({ - dbh => $self->{db_gorgone}, - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { error => "no_proxy", message => 'no proxy configured. cannot manage target.' }, - json_encode => 1 - }); - return ($token, 1, { error => "no_proxy", message => 'no proxy configured. cannot manage target.' }); - } - - $self->{counters}->{proxy}->{lc($action)} = 0 if (!defined($self->{counters}->{proxy}->{lc($action)})); - $self->{counters}->{proxy}->{lc($action)}++; - $self->{counters}->{proxy}->{total}++; - - $self->{modules_register}->{ $self->{modules_id}->{ $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{proxy_name} } }->{routing}->( - gorgone => $self, - dbh => $self->{db_gorgone}, - logger => $self->{logger}, - action => $action, - token => $token, - target => $target, - frame => $options->{frame}, - hostname => $self->{hostname} - ); - return ($token, 0); - } - - if ($action =~ /^(?:ADDLISTENER|PUTLOG|GETLOG|KILL|PING|CONSTATUS|SETCOREID|SETMODULEKEY|SYNCLOGS|LOADMODULE|UNLOADMODULE|INFORMATION|GETTHUMBPRINT)$/) { - my ($code, $response, $response_type) = $self->{internal_register}->{lc($action)}->( - gorgone => $self, - gorgone_config => $self->{config}->{configuration}->{gorgone}, - identity => $options->{identity}, - router_type => $options->{router_type}, - id => $self->{id}, - frame => $options->{frame}, - token => $token, - logger => $self->{logger} - ); - - if ($action =~ /^(?:CONSTATUS|INFORMATION|GETTHUMBPRINT)$/) { - gorgone::standard::library::add_history({ - dbh => $self->{db_gorgone}, - code => $code, - token => $token, - data => $response, - json_encode => 1 - }); - } - - return ($token, $code, $response, $response_type); - } elsif ($action =~ /^BCAST(.*)$/) { - return (undef, 1, { message => "action '$action' is not known" }) if ($1 !~ /^(?:LOGGER|COREKEY)$/); - $self->broadcast_run( - action => $action, - frame => $options->{frame}, - token => $token - ); - } else { - $self->{modules_register}->{ $self->{modules_events}->{$action}->{module}->{package} }->{routing}->( - gorgone => $self, - dbh => $self->{db_gorgone}, - logger => $self->{logger}, - action => $action, - token => $token, - target => $target, - frame => $options->{frame}, - hostname => $self->{hostname} - ); - } - - return ($token, 0); -} - -sub router_internal_event { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($identity, $frame) = gorgone::standard::library::zmq_read_message( - socket => $self->{internal_socket}, - logger => $self->{logger} - ); - - next if (!defined($identity)); - - next if ($self->decrypt_internal_message(identity => $identity, frame => $frame)); - - my ($token, $code, $response, $response_type) = $self->message_run( - { - frame => $frame, - identity => $identity, - router_type => 'internal' - } - ); - - $self->send_internal_response( - identity => $identity, - response_type => $response_type, - data => $response, - code => $code, - token => $token - ); - } -} - -sub is_handshake_done { - my ($self, %options) = @_; - - if (defined($self->{identity_infos}->{ $options{identity} })) { - return (1, $self->{identity_infos}->{ $options{identity} }); - } - - return 0; -} - -sub check_external_rotate_keys { - my ($self, %options) = @_; - - my $time = time(); - my ($rv, $key, $iv); - foreach my $id (keys %{$self->{identity_infos}}) { - if ($self->{identity_infos}->{$id}->{mtime} < ($time - 86400)) { - $self->{logger}->writeLogDebug('[core] clean external key for ' . $id); - delete $self->{identity_infos}->{$id}; - next; - } - next if ($self->{identity_infos}->{$id}->{ctime} > ($time - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_rotation})); - - $self->{logger}->writeLogDebug('[core] rotate external key for ' . pack('H*', $id)); - - ($rv, $key) = gorgone::standard::library::generate_symkey( - keysize => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_keysize} - ); - ($rv, $iv) = gorgone::standard::library::generate_symkey(keysize => 16); - $rv = gorgone::standard::library::update_identity_attrs( - dbh => $self->{db_gorgone}, - identity => $id, - ctime => $time, - oldkey => unpack('H*', $self->{identity_infos}->{$id}->{key}), - oldiv => unpack('H*', $self->{identity_infos}->{$id}->{iv}), - key => unpack('H*', $key), - iv => unpack('H*', $iv) - ); - next if ($rv == -1); - - my $message = gorgone::standard::library::json_encode( - data => { - hostname => $self->{hostname}, - cipher => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_cipher}, - padding => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_padding}, - key => unpack('H*', $key), - iv => unpack('H*', $iv) - } - ); - - $self->external_core_response( - message => '[KEY] ' . $message, - identity => $id, - cipher_infos => { - key => $self->{identity_infos}->{$id}->{key}, - iv => $self->{identity_infos}->{$id}->{iv} - } - ); - - $self->{identity_infos}->{$id}->{ctime} = $time; - $self->{identity_infos}->{$id}->{oldkey} = $self->{identity_infos}->{$id}->{key}; - $self->{identity_infos}->{$id}->{oldiv} = $self->{identity_infos}->{$id}->{iv}; - $self->{identity_infos}->{$id}->{key} = $key; - $self->{identity_infos}->{$id}->{iv} = $iv; - } -} - -sub external_decrypt_message { - my ($self, %options) = @_; - - my $message = $options{frame}->getFrame(); - - my $crypt = MIME::Base64::decode_base64($$message); - - my $keys = [ { key => $options{cipher_infos}->{key}, iv => $options{cipher_infos}->{iv} } ]; - if (defined($options{cipher_infos}->{oldkey})) { - push @$keys, { key => $options{cipher_infos}->{oldkey}, iv => $options{cipher_infos}->{oldiv} } - } - foreach my $key (@$keys) { - my $plaintext; - try { - $plaintext = $self->{external_crypt_mode}->decrypt($crypt, $key->{key}, $key->{iv}); - }; - if (defined($plaintext) && $plaintext =~ /^\[[A-Za-z0-9_\-]+?\]/) { - $options{frame}->setFrame(\$plaintext); - return 0; - } - } - - $self->{logger}->writeLogError("[core] external decrypt issue: " . ($_ ? $_ : 'no message')); - return -1; -} - -sub external_core_response { - my ($self, %options) = @_; - - my $message = $options{message}; - if (!defined($message)) { - my $response_type = defined($options{response_type}) ? $options{response_type} : 'ACK'; - my $data = gorgone::standard::library::json_encode(data => { code => $options{code}, data => $options{data} }); - # We add 'target' for 'PONG', 'SYNCLOGS'. Like that 'gorgone-proxy can get it - $message = '[' . $response_type . '] [' . (defined($options{token}) ? $options{token} : '') . '] ' . ($response_type =~ /^PONG|SYNCLOGS$/ ? '[] ' : '') . $data; - } - - if (defined($options{cipher_infos})) { - try { - $message = $self->{external_crypt_mode}->encrypt( - $message, - $options{cipher_infos}->{key}, - $options{cipher_infos}->{iv} - ); - } catch { - $self->{logger}->writeLogError("[core] external_core_response encrypt issue: $_"); - return undef; - }; - - $message = MIME::Base64::encode_base64($message, ''); - } - - $self->{external_socket}->send(pack('H*', $options{identity}), ZMQ_DONTWAIT|ZMQ_SNDMORE); - $self->{external_socket}->send($message, ZMQ_DONTWAIT); - $self->router_external_event(); -} - -sub external_core_key_response { - my ($self, %options) = @_; - - my $data = gorgone::standard::library::json_encode( - data => { - hostname => $self->{hostname}, - cipher => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_cipher}, - padding => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_padding}, - key => unpack('H*', $options{key}), - iv => unpack('H*', $options{iv}) - } - ); - return -1 if (!defined($data)); - - my $crypttext; - try { - $crypttext = $options{client_pubkey}->encrypt("[KEY] " . $data, 'v1.5'); - } catch { - $self->{logger}->writeLogError("[core] core key response encrypt issue: $_"); - return -1; - }; - - $self->{external_socket}->send(pack('H*', $options{identity}), ZMQ_DONTWAIT | ZMQ_SNDMORE); - $self->{external_socket}->send(MIME::Base64::encode_base64($crypttext, ''), ZMQ_DONTWAIT); - $self->router_external_event(); - return 0; -} - -sub handshake { - my ($self, %options) = @_; - - my ($rv, $cipher_infos); - my $first_message = $options{frame}->getFrame(); - - # Test if it asks for the pubkey - if ($$first_message =~ /^\s*\[GETPUBKEY\]/) { - gorgone::standard::library::zmq_core_pubkey_response( - socket => $self->{external_socket}, - identity => $options{identity}, - pubkey => $self->{server_pubkey} - ); - $self->router_external_event(); - return 1; - } - - ($rv, $cipher_infos) = $self->is_handshake_done(identity => $options{identity}); - - if ($rv == 1) { - my $response; - - ($rv) = $self->external_decrypt_message( - frame => $options{frame}, - cipher_infos => $cipher_infos - ); - - my $message = $options{frame}->getFrame(); - if ($rv == 0 && $$message =~ /^(?:[\[a-zA-Z-_]+?\]\s+\[.*?\]|[\[a-zA-Z-_]+?\]\s*$)/) { - $self->{identity_infos}->{ $options{identity} }->{mtime} = time(); - gorgone::standard::library::update_identity_mtime(dbh => $self->{db_gorgone}, identity => $options{identity}); - return (0, $cipher_infos); - } - - # Maybe he want to redo a handshake - $rv = 0; - } - - if ($rv == 0) { - my ($client_pubkey, $key, $iv); - - # We try to uncrypt - ($rv, $client_pubkey) = gorgone::standard::library::is_client_can_connect( - privkey => $self->{server_privkey}, - message => $$first_message, - logger => $self->{logger}, - authorized_clients => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{authorized_clients} - ); - if ($rv == -1) { - $self->external_core_response( - identity => $options{identity}, - code => GORGONE_ACTION_FINISH_KO, - data => { message => 'handshake issue' } - ); - return -1; - } - ($rv, $key) = gorgone::standard::library::generate_symkey( - keysize => $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_keysize} - ); - ($rv, $iv) = gorgone::standard::library::generate_symkey(keysize => 16); - - if (gorgone::standard::library::add_identity(dbh => $self->{db_gorgone}, identity => $options{identity}, key => $key, iv => $iv) == -1) { - $self->external_core_response( - identity => $options{identity}, - code => GORGONE_ACTION_FINISH_KO, - data => { message => 'handshake issue' } - ); - } - - $self->{identity_infos}->{ $options{identity} } = { - ctime => time(), - mtime => time(), - key => $key, - oldkey => undef, - iv => $iv, - oldiv => undef - }; - - $rv = $self->external_core_key_response( - identity => $options{identity}, - client_pubkey => $client_pubkey, - key => $key, - iv => $iv - ); - if ($rv == -1) { - $self->external_core_response( - identity => $options{identity}, - code => GORGONE_ACTION_FINISH_KO, - data => { message => 'handshake issue' } - ); - } - } - - return -1; -} - -sub send_message_parent { - my (%options) = @_; - - if ($options{router_type} eq 'internal') { - $gorgone->send_internal_response( - identity => $options{identity}, - response_type => $options{response_type}, - data => $options{data}, - code => $options{code}, - token => $options{token} - ); - } - if ($options{router_type} eq 'external') { - my ($rv, $cipher_infos) = $gorgone->is_handshake_done(identity => $options{identity}); - return if ($rv == 0); - $gorgone->external_core_response( - cipher_infos => $cipher_infos, - identity => $options{identity}, - response_type => $options{response_type}, - token => $options{token}, - code => $options{code}, - data => $options{data} - ); - } -} - -sub router_external_event { - my ($self, %options) = @_; - - while ($self->{external_socket}->has_pollin()) { - my ($identity, $frame) = gorgone::standard::library::zmq_read_message( - socket => $self->{external_socket}, - logger => $self->{logger} - ); - next if (!defined($identity)); - - my ($rv, $cipher_infos) = $self->handshake( - identity => $identity, - frame => $frame - ); - if ($rv == 0) { - my ($token, $code, $response, $response_type) = $self->message_run( - { - frame => $frame, - identity => $identity, - router_type => 'external' - } - ); - $self->external_core_response( - identity => $identity, - cipher_infos => $cipher_infos, - response_type => $response_type, - token => $token, - code => $code, - data => $response - ); - } - } -} - -sub waiting_ready_pool { - my (%options) = @_; - - my $name = $gorgone->{modules_id}->{$gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{proxy_name}}; - my $method = $name->can('is_all_proxy_ready'); - - if ($method->() > 0) { - return 1; - } - - my $iteration = 10; - while ($iteration > 0) { - my $watcher_timer = $gorgone->{loop}->timer(1, 0, \&stop_ev); - $gorgone->{loop}->run(); - $iteration--; - if ($method->() > 0) { - return 1; - } - } - - return 0; -} - -sub stop_ev { - $gorgone->{loop}->break(); - $gorgone->check_exit_modules(); -} - -sub waiting_ready { - my (%options) = @_; - - if (${$options{ready}} == 1) { - return 1; - } - - my $iteration = 10; - while ($iteration > 0) { - my $watcher_timer = $gorgone->{loop}->timer(1, 0, \&stop_ev); - $gorgone->{loop}->run(); - if (${$options{ready}} == 1) { - return 1; - } - $iteration--; - } - - return 0; -} - -sub quit { - my ($self, %options) = @_; - - $self->{logger}->writeLogInfo("[core] Quit main process"); - - if ($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_type} eq 'ipc') { - unlink($self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_path}); - } - - $self->{internal_socket}->close(); - if (defined($self->{external_socket})) { - $self->{external_socket}->close(); - } - - exit(0); -} - -sub check_exit_modules { - my ($self, %options) = @_; - - my $current_time = time(); - - # check key rotate - if ($self->{internal_crypt}->{enabled} == 1 && - ($current_time - $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_core_key_ctime}) > $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_rotation}) { - $self->broadcast_core_key(); - } - if (defined($self->{external_socket})) { - $self->check_external_rotate_keys(); - } - - my $count = 0; - if (time() - $self->{cb_timer_check} > 15 || $self->{stop} == 1) { - if ($self->{stop} == 1 && (!defined($self->{sigterm_last_time}) || ($current_time - $self->{sigterm_last_time}) >= 10)) { - $self->{sigterm_start_time} = time() if (!defined($self->{sigterm_start_time})); - $self->{sigterm_last_time} = time(); - foreach my $name (keys %{$self->{modules_register}}) { - $self->{modules_register}->{$name}->{gently}->(logger => $gorgone->{logger}); - } - } - - foreach my $name (keys %{$self->{modules_register}}) { - my ($count_module, $keepalive) = $self->{modules_register}->{$name}->{check}->( - gorgone => $self, - logger => $self->{logger}, - dead_childs => $self->{return_child}, - dbh => $self->{db_gorgone}, - api_endpoints => $self->{api_endpoints} - ); - - $count += $count_module; - if ($count_module == 0 && (!defined($keepalive) || $keepalive == 0)) { - $self->unload_module(package => $name); - } - } - - $self->{cb_timer_check} = time(); - # We can clean old return_child. - foreach my $pid (keys %{$self->{return_child}}) { - if (($self->{cb_timer_check} - $self->{return_child}->{$pid}) > 300) { - delete $self->{return_child}->{$pid}; - } - } - } - - if ($self->{stop} == 1) { - # No childs - if ($count == 0) { - $self->quit(); - } - - # Send KILL - if (time() - $self->{sigterm_start_time} > $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{timeout}) { - foreach my $name (keys %{$self->{modules_register}}) { - $self->{modules_register}->{$name}->{kill_internal}->(logger => $gorgone->{logger}); - } - $self->quit(); - } - } -} - -sub periodic_exec { - $gorgone->check_exit_modules(); - $gorgone->{listener}->check(); - - $gorgone->router_internal_event(); - - if (defined($gorgone->{external_socket})) { - $gorgone->router_external_event(); - } -} - -sub run { - $gorgone = shift; - - $gorgone->SUPER::run(); - $gorgone->{logger}->redirect_output(); - - $gorgone->{logger}->writeLogInfo("[core] Gorgoned started"); - $gorgone->{logger}->writeLogInfo("[core] PID $$"); - - if (gorgone::standard::library::add_history({ - dbh => $gorgone->{db_gorgone}, - code => GORGONE_STARTED, - data => { message => 'gorgoned is starting...' }, - json_encode => 1}) == -1 - ) { - $gorgone->{logger}->writeLogInfo("[core] Cannot write in history. We quit!!"); - exit(1); - } - - { - local $SIG{__DIE__}; - $gorgone->{zmq_context} = ZMQ::FFI->new(); - } - - $gorgone->{internal_socket} = gorgone::standard::library::create_com( - context => $gorgone->{zmq_context}, - type => $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_type}, - path => $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_path}, - zmq_type => 'ZMQ_ROUTER', - name => 'router-internal', - zmq_router_handover => $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_zmq_router_handover}, - logger => $gorgone->{logger} - ); - - if (defined($gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_type}) && $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_type} ne '') { - if ($gorgone->{keys_loaded}) { - $gorgone->init_external_informations(); - - $gorgone->{external_socket} = gorgone::standard::library::create_com( - context => $gorgone->{zmq_context}, - type => $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_type}, - path => $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_path}, - zmq_type => 'ZMQ_ROUTER', - zmq_router_handover => $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_zmq_router_handover}, - zmq_tcp_keepalive => $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_zmq_tcp_keepalive}, - zmq_ipv6 => $gorgone->{config}->{configuration}->{gorgone}->{gorgonecore}->{ipv6}, - name => 'router-external', - logger => $gorgone->{logger} - ); - } else { - $gorgone->{logger}->writeLogError("[core] Cannot create external com: no keys loaded"); - } - } - - # init all modules - foreach my $name (keys %{$gorgone->{modules_register}}) { - $gorgone->{logger}->writeLogDebug("[core] Call init function from module '$name'"); - $gorgone->{modules_register}->{$name}->{init}->( - gorgone => $gorgone, - id => $gorgone->{id}, - logger => $gorgone->{logger}, - poll => $gorgone->{poll}, - external_socket => $gorgone->{external_socket}, - internal_socket => $gorgone->{internal_socket}, - dbh => $gorgone->{db_gorgone}, - api_endpoints => $gorgone->{api_endpoints} - ); - } - - $gorgone->{listener} = gorgone::class::listener->new( - gorgone => $gorgone, - logger => $gorgone->{logger} - ); - $gorgone::standard::library::listener = $gorgone->{listener}; - - $gorgone->{logger}->writeLogInfo("[core] Server accepting clients"); - $gorgone->{cb_timer_check} = time(); - - $gorgone->{loop} = new EV::Loop(); - $gorgone->{watcher_timer} = $gorgone->{loop}->timer(5, 5, \&periodic_exec); - - $gorgone->{watcher_io_internal} = $gorgone->{loop}->io($gorgone->{internal_socket}->get_fd(), EV::READ, sub { $gorgone->router_internal_event() }); - - if (defined($gorgone->{external_socket})) { - $gorgone->{watcher_io_external} = $gorgone->{loop}->io($gorgone->{external_socket}->get_fd(), EV::READ, sub { $gorgone->router_external_event() }); - } - - $gorgone->{loop}->run(); -} - -1; - -__END__ diff --git a/centreon-gorgone/gorgone/class/db.pm b/centreon-gorgone/gorgone/class/db.pm deleted file mode 100644 index 847678411f..0000000000 --- a/centreon-gorgone/gorgone/class/db.pm +++ /dev/null @@ -1,388 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::db; - -use strict; -use warnings; -use DBI; - -sub new { - my ($class, %options) = @_; - my %defaults = ( - logger => undef, - db => undef, - dsn => undef, - host => "localhost", - user => undef, - password => undef, - port => 3306, - force => 0, - type => "mysql" - ); - my $self = {%defaults, %options}; - $self->{type} = 'mysql' if (!defined($self->{type})); - - # strip double-quotes - if (defined($self->{dsn})) { - $self->{dsn} =~ s/^\s*"//; - $self->{dsn} =~ s/"\s*$//; - } - - $self->{die} = defined($options{die}) ? 1 : 0; - $self->{instance} = undef; - $self->{transaction_begin} = 0; - bless $self, $class; - return $self; -} - -# Getter/Setter DB name -sub type { - my $self = shift; - if (@_) { - $self->{type} = shift; - } - return $self->{type}; -} - -sub getInstance { - my ($self) = @_; - - return $self->{instance}; -} - -# Getter/Setter DB name -sub db { - my $self = shift; - if (@_) { - $self->{db} = shift; - } - return $self->{db}; -} - -sub sameParams { - my ($self, %options) = @_; - - my $params = ''; - if (defined($self->{dsn})) { - $params = $self->{dsn}; - } else { - $params = $self->{host} . ':' . $self->{port} . ':' . $self->{db}; - } - $params .= ':' . $self->{user} . ':' . $self->{password}; - - my $paramsNew = ''; - if (defined($options{dsn})) { - $paramsNew = $options{dsn}; - } else { - $paramsNew = $options{host} . ':' . $options{port} . ':' . $options{db}; - } - $params .= ':' . $options{user} . ':' . $options{password}; - - return ($paramsNew eq $params) ? 1 : 0; -} - -# Getter/Setter DB host -sub host { - my $self = shift; - if (@_) { - $self->{host} = shift; - } - return $self->{host}; -} - -# Getter/Setter DB port -sub port { - my $self = shift; - if (@_) { - $self->{port} = shift; - } - return $self->{port}; -} - -# Getter/Setter DB user -sub user { - my $self = shift; - if (@_) { - $self->{user} = shift; - } - return $self->{user}; -} - -# Getter/Setter DB force -# force 2 should'nt be used with transaction -sub force { - my $self = shift; - if (@_) { - $self->{force} = shift; - } - return $self->{force}; -} - -# Getter/Setter DB password -sub password { - my $self = shift; - if (@_) { - $self->{password} = shift; - } - return $self->{password}; -} - -sub last_insert_id { - my $self = shift; - return $self->{instance}->last_insert_id(undef, undef, undef, undef); -} - -sub set_inactive_destroy { - my $self = shift; - - if (defined($self->{instance})) { - $self->{instance}->{InactiveDestroy} = 1; - } -} - -sub transaction_mode { - my ($self, $mode) = @_; - - my $status; - if (!defined($self->{instance})) { - $status = $self->connect(); - return -1 if ($status == -1); - } - - if ($mode) { - $status = $self->{instance}->begin_work(); - if (!$status) { - $self->error($self->{instance}->errstr, 'begin work'); - return -1; - } - $self->{transaction_begin} = 1; - } else { - $self->{transaction_begin} = 0; - $self->{instance}->{AutoCommit} = 1; - } - - return 0; -} - -sub commit { - my ($self) = @_; - - # Commit only if autocommit isn't enabled - if ($self->{instance}->{AutoCommit} != 1) { - if (!defined($self->{instance})) { - $self->{transaction_begin} = 0; - return -1; - } - - my $status = $self->{instance}->commit(); - $self->{transaction_begin} = 0; - - if (!$status) { - $self->error($self->{instance}->errstr, 'commit'); - return -1; - } - } - - return 0; -} - -sub rollback { - my ($self) = @_; - - $self->{instance}->rollback() if (defined($self->{instance})); - $self->{transaction_begin} = 0; -} - -sub kill { - my $self = shift; - - if (defined($self->{instance})) { - $self->{logger}->writeLogInfo("KILL QUERY\n"); - my $rv = $self->{instance}->do("KILL QUERY " . $self->{instance}->{'mysql_thread_id'}); - if (!$rv) { - my ($package, $filename, $line) = caller; - $self->{logger}->writeLogError("MySQL error : " . $self->{instance}->errstr . " (caller: $package:$filename:$line)"); - } - } -} - -# Connection initializer -sub connect() { - my $self = shift; - my ($status, $count) = (0, 0); - - while (1) { - $self->{port} = 3306 if (!defined($self->{port}) && $self->{type} eq 'mysql'); - if (defined($self->{dsn})) { - $self->{instance} = DBI->connect( - "DBI:".$self->{dsn}, $self->{user}, $self->{password}, - { - RaiseError => 0, - PrintError => 0, - AutoCommit => 1, - mysql_enable_utf8 => 1 - } - ); - } elsif ($self->{type} =~ /SQLite/i) { - $self->{instance} = DBI->connect( - "DBI:".$self->{type} - .":".$self->{db}, - $self->{user}, - $self->{password}, - { RaiseError => 0, PrintError => 0, AutoCommit => 1, sqlite_unicode => 1 } - ); - } else { - $self->{instance} = DBI->connect( - "DBI:".$self->{type} - .":".$self->{db} - .":".$self->{host} - .":".$self->{port}, - $self->{user}, - $self->{password}, - { - RaiseError => 0, - PrintError => 0, - AutoCommit => 1, - mysql_enable_utf8 => 1 - } - ); - } - if (defined($self->{instance})) { - last; - } - - my ($package, $filename, $line) = caller; - $self->{logger}->writeLogError("MySQL error : cannot connect to database '" . - (defined($self->{db}) ? $self->{db} : $self->{dsn}) . "': " . $DBI::errstr . " (caller: $package:$filename:$line) (try: $count)" - ); - if ($self->{force} == 0 || ($self->{force} == 2 && $count == 1)) { - $self->{lastError} = "MySQL error : cannot connect to database '" . - (defined($self->{db}) ? $self->{db} : $self->{dsn}) . "': " . $DBI::errstr; - $status = -1; - last; - } - sleep(1); - $count++; - } - - return $status; -} - -# Destroy connection -sub disconnect { - my $self = shift; - my $instance = $self->{instance}; - if (defined($instance)) { - $instance->disconnect; - $self->{instance} = undef; - } -} - -sub do { - my ($self, $query) = @_; - - if (!defined($self->{instance})) { - if ($self->connect() == -1) { - $self->{logger}->writeLogError("Cannot connect to database"); - return -1; - } - } - my $numrows = $self->{instance}->do($query); - die $self->{instance}->errstr if !defined $numrows; - return $numrows; -} - -sub error { - my ($self, $error, $query) = @_; - my ($package, $filename, $line) = caller 1; - - chomp($query); - $self->{lastError} = "SQL error: $error (caller: $package:$filename:$line) -Query: $query -"; - $self->{logger}->writeLogError($error); - if ($self->{transaction_begin} == 1) { - $self->rollback(); - } - $self->disconnect(); - $self->{instance} = undef; -} - -sub prepare { - my ($self, $query) = @_; - - return $self->query({ query => $query, prepare_only => 1 }); -} - -sub query { - my ($self) = shift; - my ($status, $count) = (0, -1); - my $statement_handle; - - while (1) { - if (!defined($self->{instance})) { - $status = $self->connect(); - if ($status == -1) { - last; - } - } - - $count++; - $statement_handle = $self->{instance}->prepare($_[0]->{query}); - if (!defined($statement_handle)) { - $self->error($self->{instance}->errstr, $_[0]->{query}); - $status = -1; - last if ($self->{force} == 0 || ($self->{force} == 2 && $count == 1)); - sleep(1); - next; - } - - if (defined($_[0]->{prepare_only})) { - return $statement_handle if ($self->{die} == 1); - return ($status, $statement_handle); - } - - my $rv; - if (defined($_[0]->{bind_values}) && scalar(@{$_[0]->{bind_values}}) > 0) { - $rv = $statement_handle->execute(@{$_[0]->{bind_values}}); - } else { - $rv = $statement_handle->execute(); - } - if (!$rv) { - $self->error($statement_handle->errstr, $_[0]->{query}); - $status = -1; - last if ($self->{force} == 0 || ($self->{force} == 2 && $count == 1)); - sleep(1); - next; - } - - last; - } - - if ($self->{die} == 1) { - die $self->{lastError} if ($status == -1); - return $statement_handle; - } - - return ($status, $statement_handle); -} - -1; diff --git a/centreon-gorgone/gorgone/class/fingerprint/backend/sql.pm b/centreon-gorgone/gorgone/class/fingerprint/backend/sql.pm deleted file mode 100644 index a36542cd7c..0000000000 --- a/centreon-gorgone/gorgone/class/fingerprint/backend/sql.pm +++ /dev/null @@ -1,85 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::fingerprint::backend::sql; - -use base qw(gorgone::class::db); - -use strict; -use warnings; - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new( - logger => $options{logger}, - type => defined($options{config}->{gorgone_db_type}) && $options{config}->{gorgone_db_type} ne '' ? - $options{config}->{gorgone_db_type} : $options{config_core}->{gorgone_db_type}, - db => defined($options{config}->{gorgone_db_name}) && $options{config}->{gorgone_db_name} ne '' ? - $options{config}->{gorgone_db_name} : $options{config_core}->{gorgone_db_name}, - host => defined($options{config}->{gorgone_db_host}) && $options{config}->{gorgone_db_host} ne '' ? - $options{config}->{gorgone_db_host} : $options{config_core}->{gorgone_db_host}, - port => defined($options{config}->{gorgone_db_port}) && $options{config}->{gorgone_db_port} ne '' ? - $options{config}->{gorgone_db_port} : $options{config_core}->{gorgone_db_port}, - user => defined($options{config}->{gorgone_db_user}) && $options{config}->{gorgone_db_user} ne '' ? - $options{config}->{gorgone_db_user} : $options{config_core}->{gorgone_db_user}, - password => defined($options{config}->{gorgone_db_password}) && $options{config}->{gorgone_db_password} ne '' ? - $options{config}->{gorgone_db_password} : $options{config_core}->{gorgone_db_password}, - force => 2 - ); - bless $self, $class; - - $self->{fingerprint_mode} = $options{config_core}->{fingerprint_mode}; - - return $self; -} - -sub check_fingerprint { - my ($self, %options) = @_; - - return 1 if ($self->{fingerprint_mode} eq 'always'); - - my ($status, $sth) = $self->query({ - query => "SELECT `id`, `fingerprint` FROM gorgone_target_fingerprint WHERE target = ? ORDER BY id ASC LIMIT 1", - bind_values => [$options{target}] - }); - return (0, "cannot get fingerprint for target '$options{target}'") if ($status == -1); - my $row = $sth->fetchrow_hashref(); - - if (!defined($row)) { - if ($self->{fingerprint_mode} eq 'strict') { - return (0, "no fingerprint found for target '" . $options{target} . "' [strict mode] [fingerprint: $options{fingerprint}]"); - } - ($status) = $self->query({ - query => "INSERT INTO gorgone_target_fingerprint (`target`, `fingerprint`) VALUES (?, ?)", - bind_values => [$options{target}, $options{fingerprint}] - }); - return (0, "cannot insert target '$options{target}' fingerprint") if ($status == -1); - return 1; - } - - if ($row->{fingerprint} ne $options{fingerprint}) { - return (0, "fingerprint changed for target '" . $options{target} . "' [id: $row->{id}] [old fingerprint: $row->{fingerprint}] [new fingerprint: $options{fingerprint}]"); - } - return 1; -} - -1; - -__END__ diff --git a/centreon-gorgone/gorgone/class/frame.pm b/centreon-gorgone/gorgone/class/frame.pm deleted file mode 100644 index 14688e2da2..0000000000 --- a/centreon-gorgone/gorgone/class/frame.pm +++ /dev/null @@ -1,190 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::frame; - -use strict; -use warnings; - -use JSON::XS; -use Try::Tiny; -use MIME::Base64; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - if (defined($options{rawData})) { - $self->setRawData($options{rawData}); - } - if (defined($options{data})) { - $self->setData($options{data}); - } - - return $self; -} - -sub setData { - my ($self) = shift; - - $self->{data} = $_[0]; -} - -sub setRawData { - my ($self) = shift; - - $self->{rawData} = $_[0]; -} - -sub setFrame { - my ($self) = shift; - - $self->{frame} = $_[0]; -} - -sub getFrame { - my ($self) = shift; - - return $self->{frame}; -} - -sub getLastError { - my ($self) = shift; - - return $self->{lastError}; -} - -sub decrypt { - my ($self, $options) = (shift, shift); - - my $plaintext; - try { - $plaintext = $options->{cipher}->decrypt(MIME::Base64::decode_base64(${$self->{frame}}), $options->{key}, $options->{iv}); - }; - if (defined($plaintext) && $plaintext =~ /^\[[A-Za-z0-9_\-]+?\]/) { - $self->{frame} = \$plaintext; - return 0; - } - - $self->{lastError} = $_ ? $_ : 'no message'; - return 1; -} - -sub parse { - my ($self, $options) = (shift, shift); - - if (${$self->{frame}} =~ /^\[(.+?)\]\s+\[(.*?)\]\s+\[(.*?)\]\s+/g) { - $self->{action} = $1; - $self->{token} = $2; - $self->{target} = $3; - - if (defined($options) && defined($options->{decode})) { - try { - $self->{data} = JSON::XS->new->decode(substr(${$self->{frame}}, pos(${$self->{frame}}))); - } catch { - $self->{lastError} = $_; - return 1; - } - } else { - $self->{rawData} = substr(${$self->{frame}}, pos(${$self->{frame}})); - } - - if (defined($options) && defined($options->{releaseFrame})) { - $self->{frame} = undef; - } - - return 0; - } - - return 1; -} - -sub getData { - my ($self) = shift; - - if (!defined($self->{data})) { - try { - $self->{data} = JSON::XS->new->decode($self->{rawData}); - } catch { - $self->{lastError} = $_; - return undef; - } - } - - return $self->{data}; -} - -sub decodeData { - my ($self) = shift; - - if (!defined($self->{data})) { - try { - $self->{data} = JSON::XS->new->decode($self->{rawData}); - } catch { - $self->{lastError} = $_; - return undef; - } - } - - return $self->{data}; -} - -sub getRawData { - my ($self) = shift; - - if (!defined($self->{rawData})) { - try { - $self->{rawData} = JSON::XS->new->encode($self->{data}); - } catch { - $self->{lastError} = $_; - return undef; - } - } - return \$self->{rawData}; -} - -sub getAction { - my ($self) = shift; - - return $self->{action}; -} - -sub getToken { - my ($self) = shift; - - return $self->{token}; -} - -sub getTarget { - my ($self) = shift; - - return $self->{target}; -} - -sub DESTROY { - my ($self) = shift; - - $self->{frame} = undef; - $self->{data} = undef; - $self->{rawData} = undef; -} - -1; diff --git a/centreon-gorgone/gorgone/class/http/backend/curl.pm b/centreon-gorgone/gorgone/class/http/backend/curl.pm deleted file mode 100644 index f2801bafd4..0000000000 --- a/centreon-gorgone/gorgone/class/http/backend/curl.pm +++ /dev/null @@ -1,450 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::http::backend::curl; - -use strict; -use warnings; -use URI; -use gorgone::standard::misc; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - $self->{logger} = $options{logger}; - - return $self; -} - -sub check_options { - my ($self, %options) = @_; - - if (gorgone::standard::misc::mymodule_load( - logger => $self->{logger}, module => 'Net::Curl::Easy', - error_msg => "Cannot load module 'Net::Curl::Easy'." - ) == 1) { - return 1; - } - if (gorgone::standard::misc::mymodule_load( - logger => $self->{logger}, module => 'gorgone::class::http::backend::curlconstants', - error_msg => "Cannot load module 'gorgone::class::http::backend::curlconstants'." - ) == 1) { - return 1; - } - $self->{constant_cb} = \&gorgone::class::http::backend::curlconstants::get_constant_value; - - if (!defined($options{request}->{curl_opt})) { - $options{request}->{curl_opt} = []; - } -} - -my $http_code_explained = { - 100 => 'Continue', - 101 => 'Switching Protocols', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 306 => '(Unused)', - 307 => 'Temporary Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 450 => 'Timeout reached', # custom code - 451 => 'Failed Connection Host', # custom code - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported' -}; - -sub cb_debug { - my ($easy, $type, $data, $uservar) = @_; - - chomp $data; - $data =~ s/\r//mg; - - my $msg = ''; - if ($type == $uservar->{constant_cb}->(name => 'CURLINFO_TEXT')) { - $msg = sprintf("== Info: %s", $data); - } - if ($type == $uservar->{constant_cb}->(name => 'CURLINFO_HEADER_OUT')) { - $msg = sprintf("=> Send header: %s", $data); - } - if ($type == $uservar->{constant_cb}->(name => 'CURLINFO_DATA_OUT')) { - $msg = sprintf("=> Send data: %s", $data); - } - if ($type == $uservar->{constant_cb}->(name => 'CURLINFO_SSL_DATA_OUT')) { - #$msg = sprintf("=> Send SSL data: %s", $data); - return 0; - } - if ($type == $uservar->{constant_cb}->(name => 'CURLINFO_HEADER_IN')) { - $msg = sprintf("=> Recv header: %s", $data); - } - if ($type == $uservar->{constant_cb}->(name => 'CURLINFO_DATA_IN')) { - $msg = sprintf("=> Recv data: %s", $data); - } - if ($type == $uservar->{constant_cb}->(name => 'CURLINFO_SSL_DATA_IN')) { - #$msg = sprintf("=> Recv SSL data: %s", $data); - return 0; - } - - $uservar->{logger}->writeLogDebug($msg); - return 0; -} - -sub curl_setopt { - my ($self, %options) = @_; - - eval { - $self->{curl_easy}->setopt($options{option}, $options{parameter}); - }; - if ($@) { - $self->{logger}->writeLogError("curl setopt error: '" . $@ . "'."); - } -} - -sub set_method { - my ($self, %options) = @_; - - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_CUSTOMREQUEST'), parameter => undef); - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_POSTFIELDS'), parameter => undef); - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_HTTPGET'), parameter => 1); - - if ($options{request}->{method} eq 'GET') { - return ; - } - - if ($options{content_type_forced} == 1) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_POSTFIELDS'), parameter => $options{request}->{query_form_post}) - if (defined($options{request}->{query_form_post}) && $options{request}->{query_form_post} ne ''); - } elsif (defined($options{request}->{post_params})) { - my $uri_post = URI->new(); - $uri_post->query_form($options{request}->{post_params}); - push @{$options{headers}}, 'Content-Type: application/x-www-form-urlencoded'; - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_POSTFIELDS'), parameter => $uri_post->query); - } - - if ($options{request}->{method} eq 'POST') { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_POST'), parameter => 1); - } - if ($options{request}->{method} eq 'PUT') { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_CUSTOMREQUEST'), parameter => $options{request}->{method}); - } - if ($options{request}->{method} eq 'DELETE') { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_CUSTOMREQUEST'), parameter => $options{request}->{method}); - } -} - -sub set_auth { - my ($self, %options) = @_; - - if (defined($options{request}->{credentials})) { - if (defined($options{request}->{basic})) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_HTTPAUTH'), parameter => $self->{constant_cb}->(name => 'CURLAUTH_BASIC')); - } elsif (defined($options{request}->{ntlmv2})) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_HTTPAUTH'), parameter => $self->{constant_cb}->(name => 'CURLAUTH_NTLM')); - } else { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_HTTPAUTH'), parameter => $self->{constant_cb}->(name => 'CURLAUTH_ANY')); - } - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_USERPWD'), parameter => $options{request}->{username} . ':' . $options{request}->{password}); - } - - if (defined($options{request}->{cert_file}) && $options{request}->{cert_file} ne '') { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_SSLCERT'), parameter => $options{request}->{cert_file}); - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_SSLKEY'), parameter => $options{request}->{key_file}); - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_KEYPASSWD'), parameter => $options{request}->{cert_pwd}); - } - - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_SSLCERTTYPE'), parameter => "PEM"); - if (defined($options{request}->{cert_pkcs12})) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_SSLCERTTYPE'), parameter => "P12"); - } -} - -sub set_proxy { - my ($self, %options) = @_; - - if (defined($options{request}->{proxyurl}) && $options{request}->{proxyurl} ne '') { - if ($options{request}->{proxyurl} =~ /^(?:http|https):\/\/(.*?):(.*?)@/) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_PROXYUSERNAME'), parameter => $1); - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_PROXYPASSWORD'), parameter => $2); - $options{request}->{proxyurl} =~ s/\/\/$1:$2@//; - } - - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_PROXY'), parameter => $options{request}->{proxyurl}); - } - - if (defined($options{request}->{proxypac}) && $options{request}->{proxypac} ne '') { - $self->{logger}->writeLogError('Unsupported proxypac option'); - } -} - -sub set_extra_curl_opt { - my ($self, %options) = @_; - - my $fields = { key => '', value => '' }; - foreach (@{$options{request}->{curl_opt}}) { - ($fields->{key}, $fields->{value}) = split /=>/; - foreach my $label ('key', 'value') { - $fields->{$label} = gorgone::standard::misc::trim($fields->{$label}); - if ($fields->{$label} =~ /^CURLOPT|CURL/) { - $fields->{$label} = $self->{constant_cb}->(name => $fields->{$label}); - } - } - - $self->curl_setopt(option => $fields->{key}, parameter => $fields->{value}); - } -} - -sub cb_get_header { - my ($easy, $header, $uservar) = @_; - - $header =~ s/[\r\n]//g; - if ($header =~ /^[\r\n]*$/) { - $uservar->{nheaders}++; - } else { - $uservar->{response_headers}->[$uservar->{nheaders}] = {} - if (!defined($uservar->{response_headers}->[$uservar->{nheaders}])); - if ($header =~ /^(\S(?:.*?))\s*:\s*(.*)/) { - my $header_name = lc($1); - $uservar->{response_headers}->[$uservar->{nheaders}]->{$header_name} = [] - if (!defined($uservar->{response_headers}->[$uservar->{nheaders}]->{$header_name})); - push @{$uservar->{response_headers}->[$uservar->{nheaders}]->{$header_name}}, $2; - } else { - $uservar->{response_headers}->[$uservar->{nheaders}]->{response_line} = $header; - } - } - - return length($_[1]); -} - -sub request { - my ($self, %options) = @_; - - if (!defined($self->{curl_easy})) { - $self->{curl_easy} = Net::Curl::Easy->new(); - } - - if ($self->{logger}->is_debug()) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_DEBUGFUNCTION'), parameter => \&cb_debug); - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_DEBUGDATA'), parameter => $self); - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_VERBOSE'), parameter => 1); - } - - if (defined($options{request}->{timeout})) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_TIMEOUT'), parameter => $options{request}->{timeout}); - } - if (defined($options{request}->{cookies_file})) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_COOKIEFILE'), parameter => $options{request}->{cookies_file}); - } - - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_FOLLOWLOCATION'), parameter => 1); - if (defined($options{request}->{no_follow})) { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_FOLLOWLOCATION'), parameter => 0); - } - - my $url; - if (defined($options{request}->{full_url})) { - $url = $options{request}->{full_url}; - } elsif (defined($options{request}->{port}) && $options{request}->{port} =~ /^[0-9]+$/) { - $url = $options{request}->{proto}. "://" . $options{request}->{hostname} . ':' . $options{request}->{port} . $options{request}->{url_path}; - } else { - $url = $options{request}->{proto}. "://" . $options{request}->{hostname} . $options{request}->{url_path}; - } - - if (defined($options{request}->{http_peer_addr}) && $options{request}->{http_peer_addr} ne '') { - $url =~ /^(?:http|https):\/\/(.*?)(\/|\:|$)/; - $self->{curl_easy}->setopt( - $self->{constant_cb}->(name => 'CURLOPT_RESOLVE'), - [$1 . ':' . $options{request}->{port_force} . ':' . $options{request}->{http_peer_addr}] - ); - } - - my $uri = URI->new($url); - if (defined($options{request}->{get_params})) { - $uri->query_form($options{request}->{get_params}); - } - - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_URL'), parameter => $uri); - - my $headers = []; - my $content_type_forced = 0; - foreach my $key (keys %{$options{request}->{headers}}) { - push @$headers, $key . ':' . $options{request}->{headers}->{$key}; - if ($key =~ /content-type/i) { - $content_type_forced = 1; - } - } - - $self->set_method(%options, content_type_forced => $content_type_forced, headers => $headers); - - if (scalar(@$headers) > 0) { - $self->{curl_easy}->setopt($self->{constant_cb}->(name => 'CURLOPT_HTTPHEADER'), $headers); - } - - if (defined($options{request}->{cacert_file}) && $options{request}->{cacert_file} ne '') { - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_CAINFO'), parameter => $options{request}->{cacert_file}); - } - - $self->set_auth(%options); - $self->set_proxy(%options); - $self->set_extra_curl_opt(%options); - - $self->{response_body} = ''; - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_FILE'), parameter => \$self->{response_body}); - $self->{nheaders} = 0; - $self->{response_headers} = [{}]; - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_HEADERDATA'), parameter => $self); - $self->curl_setopt(option => $self->{constant_cb}->(name => 'CURLOPT_HEADERFUNCTION'), parameter => \&cb_get_header); - - eval { - $SIG{__DIE__} = sub {}; - - $self->{curl_easy}->perform(); - }; - if ($@) { - my $err = $@; - if (ref($@) eq "Net::Curl::Easy::Code") { - my $num = $@; - if ($num == $self->{constant_cb}->(name => 'CURLE_OPERATION_TIMEDOUT')) { - $self->{response_code} = 450; - } elsif ($num == $self->{constant_cb}->(name => 'CURLE_COULDNT_CONNECT')) { - $self->{response_code} = 451; - } - } - - if (!defined($self->{response_code})) { - $self->{logger}->writeLogError('curl perform error : ' . $err); - } - - return 1; - } - - $self->{response_code} = $self->{curl_easy}->getinfo($self->{constant_cb}->(name => 'CURLINFO_RESPONSE_CODE')); - - return (0, $self->{response_body}); -} - -sub get_headers { - my ($self, %options) = @_; - - my $headers = ''; - foreach (keys %{$self->{response_headers}->[$options{nheader}]}) { - next if (/response_line/); - foreach my $value (@{$self->{response_headers}->[$options{nheader}]->{$_}}) { - $headers .= "$_: " . $value . "\n"; - } - } - - return $headers; -} - -sub get_first_header { - my ($self, %options) = @_; - - if (!defined($options{name})) { - return $self->get_headers(nheader => 0); - } - - return undef - if (!defined($self->{response_headers}->[0]->{ lc($options{name}) })); - return wantarray ? @{$self->{response_headers}->[0]->{ lc($options{name}) }} : $self->{response_headers}->[0]->{ lc($options{name}) }->[0]; -} - -sub get_header { - my ($self, %options) = @_; - - if (!defined($options{name})) { - return $self->get_headers(nheader => -1); - } - - return undef - if (!defined($self->{response_headers}->[-1]->{ lc($options{name}) })); - return wantarray ? @{$self->{response_headers}->[-1]->{ lc($options{name}) }} : $self->{response_headers}->[-1]->{ lc($options{name}) }->[0]; -} - -sub get_code { - my ($self, %options) = @_; - - return $self->{response_code}; -} - -sub get_message { - my ($self, %options) = @_; - - return $http_code_explained->{$self->{response_code}}; -} - -1; - -__END__ - -=head1 NAME - -HTTP Curl backend layer. - -=head1 SYNOPSIS - -HTTP Curl backend layer. - -=head1 BACKEND CURL OPTIONS - -=over 8 - -=item B<--curl-opt> - -Set CURL Options (--curl-opt="CURLOPT_SSL_VERIFYPEER => 0" --curl-opt="CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_1" ). - -=back - -=head1 DESCRIPTION - -B. - -=cut diff --git a/centreon-gorgone/gorgone/class/http/backend/curlconstants.pm b/centreon-gorgone/gorgone/class/http/backend/curlconstants.pm deleted file mode 100644 index 41045c38bf..0000000000 --- a/centreon-gorgone/gorgone/class/http/backend/curlconstants.pm +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::http::backend::curlconstants; - -use strict; -use warnings; -use Net::Curl::Easy qw(:constants); - -sub get_constant_value { - my (%options) = @_; - - return eval $options{name}; -} - -1; diff --git a/centreon-gorgone/gorgone/class/http/backend/lwp.pm b/centreon-gorgone/gorgone/class/http/backend/lwp.pm deleted file mode 100644 index f396a35093..0000000000 --- a/centreon-gorgone/gorgone/class/http/backend/lwp.pm +++ /dev/null @@ -1,299 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::http::backend::lwp; - -use strict; -use warnings; -use gorgone::class::http::backend::useragent; -use URI; -use IO::Socket::SSL; -use gorgone::standard::misc; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - $self->{logger} = $options{logger}; - $self->{ua} = undef; - $self->{debug_handlers} = 0; - - return $self; -} - -sub check_options { - my ($self, %options) = @_; - - $self->{ssl_context} = ''; - if (!defined($options{request}->{ssl_opt})) { - $options{request}->{ssl_opt} = []; - } - if (defined($options{request}->{ssl}) && $options{request}->{ssl} ne '') { - push @{$options{request}->{ssl_opt}}, 'SSL_version => ' . $options{request}->{ssl}; - } - if (defined($options{request}->{cert_file}) && !defined($options{request}->{cert_pkcs12})) { - push @{$options{request}->{ssl_opt}}, 'SSL_use_cert => 1'; - push @{$options{request}->{ssl_opt}}, 'SSL_cert_file => "' . $options{request}->{cert_file} . '"'; - push @{$options{request}->{ssl_opt}}, 'SSL_key_file => "' . $options{request}->{key_file} . '"' - if (defined($options{request}->{key_file})); - push @{$options{request}->{ssl_opt}}, 'SSL_ca_file => "' . $options{request}->{cacert_file} . '"' - if (defined($options{request}->{cacert_file})); - } - my $append = ''; - foreach (@{$options{request}->{ssl_opt}}) { - if ($_ ne '') { - $self->{ssl_context} .= $append . $_; - $append = ', '; - } - } -} - -sub set_proxy { - my ($self, %options) = @_; - - if (defined($options{request}->{proxypac}) && $options{request}->{proxypac} ne '') { - if (gorgone::standard::misc::mymodule_load( - logger => $self->{logger}, module => 'HTTP::ProxyPAC', - error_msg => "Cannot load module 'HTTP::ProxyPAC'." - ) == 1) { - return 1; - } - my ($pac, $pac_uri); - eval { - if ($options{request}->{proxypac} =~ /^(http|https):\/\//) { - $pac_uri = URI->new($options{request}->{proxypac}); - $pac = HTTP::ProxyPAC->new($pac_uri); - } else { - $pac = HTTP::ProxyPAC->new($options{request}->{proxypac}); - } - }; - if ($@) { - $self->{logger}->writeLogError('issue to load proxypac: ' . $@); - return 1; - } - my $res = $pac->find_proxy($options{url}); - if (defined($res->direct) && $res->direct != 1) { - my $proxy_uri = URI->new($res->proxy); - $proxy_uri->userinfo($pac_uri->userinfo) if (defined($pac_uri->userinfo)); - $self->{ua}->proxy(['http', 'https'], $proxy_uri->as_string); - } - } - if (defined($options{request}->{proxyurl}) && $options{request}->{proxyurl} ne '') { - $self->{ua}->proxy(['http', 'https'], $options{request}->{proxyurl}); - } -} - -sub request { - my ($self, %options) = @_; - - my $request_options = $options{request}; - if (!defined($self->{ua})) { - $self->{ua} = centreon::plugins::backend::http::useragent->new( - keep_alive => 1, protocols_allowed => ['http', 'https'], timeout => $request_options->{timeout}, - credentials => $request_options->{credentials}, username => $request_options->{username}, password => $request_options->{password}); - if (defined($request_options->{cookies_file})) { - if (gorgone::standard::misc::mymodule_load( - logger => $self->{logger}, module => 'HTTP::Cookies', - error_msg => "Cannot load module 'HTTP::Cookies'." - ) == 1) { - return 1; - } - $self->{ua}->cookie_jar(HTTP::Cookies->new(file => $request_options->{cookies_file}, - autosave => 1)); - } - } - - if ($self->{logger}->is_debug() && $self->{debug_handlers} == 0) { - $self->{debug_handlers} = 1; - $self->{ua}->add_handler("request_send", sub { - my ($response, $ua, $handler) = @_; - - $self->{logger}->writeLogDebug("======> request send"); - $self->{logger}->writeLogDebug($response->as_string); - return ; - }); - $self->{ua}->add_handler("response_done", sub { - my ($response, $ua, $handler) = @_; - - $self->{logger}->writeLogDebug("======> response done"); - $self->{logger}->writeLogDebug($response->as_string); - return ; - }); - } - - if (defined($request_options->{no_follow})) { - $self->{ua}->requests_redirectable(undef); - } else { - $self->{ua}->requests_redirectable([ 'GET', 'HEAD', 'POST' ]); - } - if (defined($request_options->{http_peer_addr})) { - push @LWP::Protocol::http::EXTRA_SOCK_OPTS, PeerAddr => $request_options->{http_peer_addr}; - } - - my ($req, $url); - if (defined($request_options->{full_url})) { - $url = $request_options->{full_url}; - } elsif (defined($request_options->{port}) && $request_options->{port} =~ /^[0-9]+$/) { - $url = $request_options->{proto}. "://" . $request_options->{hostname} . ':' . $request_options->{port} . $request_options->{url_path}; - } else { - $url = $request_options->{proto}. "://" . $request_options->{hostname} . $request_options->{url_path}; - } - - my $uri = URI->new($url); - if (defined($request_options->{get_params})) { - $uri->query_form($request_options->{get_params}); - } - $req = HTTP::Request->new($request_options->{method}, $uri); - - my $content_type_forced; - foreach my $key (keys %{$request_options->{headers}}) { - if ($key !~ /content-type/i) { - $req->header($key => $request_options->{headers}->{$key}); - } else { - $content_type_forced = $request_options->{headers}->{$key}; - } - } - - if ($request_options->{method} eq 'POST') { - if (defined($content_type_forced)) { - $req->content_type($content_type_forced); - $req->content($request_options->{query_form_post}); - } else { - my $uri_post = URI->new(); - if (defined($request_options->{post_params})) { - $uri_post->query_form($request_options->{post_params}); - } - $req->content_type('application/x-www-form-urlencoded'); - $req->content($uri_post->query); - } - } - - if (defined($request_options->{credentials}) && defined($request_options->{ntlmv2})) { - if (gorgone::standard::misc::mymodule_load( - logger => $self->{logger}, module => 'Authen::NTLM', - error_msg => "Cannot load module 'Authen::NTLM'." - ) == 1) { - return 1; - } - Authen::NTLM::ntlmv2(1); - } - - if (defined($request_options->{credentials}) && defined($request_options->{basic})) { - $req->authorization_basic($request_options->{username}, $request_options->{password}); - } - - $self->set_proxy(request => $request_options, url => $url); - - if (defined($request_options->{cert_pkcs12}) && $request_options->{cert_file} ne '' && $request_options->{cert_pwd} ne '') { - eval "use Net::SSL"; die $@ if $@; - $ENV{HTTPS_PKCS12_FILE} = $request_options->{cert_file}; - $ENV{HTTPS_PKCS12_PASSWORD} = $request_options->{cert_pwd}; - } - - if (defined($self->{ssl_context}) && $self->{ssl_context} ne '') { - my $context = new IO::Socket::SSL::SSL_Context(eval $self->{ssl_context}); - IO::Socket::SSL::set_default_context($context); - } - - $self->{response} = $self->{ua}->request($req); - - $self->{headers} = $self->{response}->headers(); - return (0, $self->{response}->content); -} - -sub get_headers { - my ($self, %options) = @_; - - my $headers = ''; - foreach ($options{response}->header_field_names()) { - $headers .= "$_: " . $options{response}->header($_) . "\n"; - } - - return $headers; -} - -sub get_first_header { - my ($self, %options) = @_; - - my @redirects = $self->{response}->redirects(); - if (!defined($options{name})) { - return $self->get_headers(response => defined($redirects[0]) ? $redirects[0] : $self->{response}); - } - - return - defined($redirects[0]) ? - $redirects[0]->headers()->header($options{name}) : - $self->{headers}->header($options{name}) - ; -} - -sub get_header { - my ($self, %options) = @_; - - if (!defined($options{name})) { - return $self->get_headers(response => $self->{response}); - } - return $self->{headers}->header($options{name}); -} - -sub get_code { - my ($self, %options) = @_; - - return $self->{response}->code(); -} - -sub get_message { - my ($self, %options) = @_; - - return $self->{response}->message(); -} - -1; - -__END__ - -=head1 NAME - -HTTP LWP backend layer. - -=head1 SYNOPSIS - -HTTP LWP backend layer. - -=head1 BACKEND LWP OPTIONS - -=over 8 - -=item B<--ssl-opt> - -Set SSL Options (--ssl-opt="SSL_version => TLSv1" --ssl-opt="SSL_verify_mode => SSL_VERIFY_NONE"). - -=item B<--ssl> - -Set SSL version (--ssl=TLSv1). - -=back - -=head1 DESCRIPTION - -B. - -=cut diff --git a/centreon-gorgone/gorgone/class/http/backend/useragent.pm b/centreon-gorgone/gorgone/class/http/backend/useragent.pm deleted file mode 100644 index e3c2d56b3e..0000000000 --- a/centreon-gorgone/gorgone/class/http/backend/useragent.pm +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::http::backend::useragent; - -use strict; -use warnings; -use base 'LWP::UserAgent'; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - $self = LWP::UserAgent::new(@_); - $self->agent('gorgone::class::http::backend::useragent'); - - $self->{credentials} = $options{credentials} if defined($options{credentials}); - $self->{username} = $options{username} if defined($options{username}); - $self->{password} = $options{password} if defined($options{password}); - - return $self; -} - -sub get_basic_credentials { - my($self, $realm, $uri, $proxy) = @_; - return if $proxy; - return $self->{username}, $self->{password} if $self->{credentials} and wantarray; - return $self->{username}.":".$self->{password} if $self->{credentials}; - return undef; -} - -1; diff --git a/centreon-gorgone/gorgone/class/http/http.pm b/centreon-gorgone/gorgone/class/http/http.pm deleted file mode 100644 index fc659354ed..0000000000 --- a/centreon-gorgone/gorgone/class/http/http.pm +++ /dev/null @@ -1,240 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::http::http; - -use strict; -use warnings; -use gorgone::standard::misc; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - $self->{logger} = $options{logger}; - $self->{options} = { - proto => 'http', - url_path => '/', - timeout => 5, - method => 'GET', - }; - - $self->{add_headers} = {}; - return $self; -} - -sub set_options { - my ($self, %options) = @_; - - $self->{options} = { %{$self->{options}} }; - foreach (keys %options) { - $self->{options}->{$_} = $options{$_} if (defined($options{$_})); - } -} - -sub add_header { - my ($self, %options) = @_; - - $self->{add_headers}->{$options{key}} = $options{value}; -} - -sub check_options { - my ($self, %options) = @_; - - $options{request}->{http_backend} = 'curl' - if (!defined($options{request}->{http_backend}) || $options{request}->{http_backend} eq ''); - $self->{http_backend} = $options{request}->{http_backend}; - if ($self->{http_backend} !~ /^\s*lwp|curl\s*$/i) { - $self->{logger}->writeLogError("Unsupported http backend specified '" . $self->{http_backend} . "'."); - return 1; - } - - if (!defined($self->{backend_lwp}) && !defined($self->{backend_curl})) { - if ($options{request}->{http_backend} eq 'lwp' && gorgone::standard::misc::mymodule_load( - logger => $options{logger}, module => 'gorgone::class::http::backend::lwp', - error_msg => "Cannot load module 'gorgone::class::http::backend::lwp'." - ) == 0) { - $self->{backend_lwp} = gorgone::class::http::backend::lwp->new(%options, logger => $self->{logger}); - } - - if ($options{request}->{http_backend} eq 'curl' && gorgone::standard::misc::mymodule_load( - logger => $options{logger}, module => 'gorgone::class::http::backend::curl', - error_msg => "Cannot load module 'gorgone::class::http::backend::curl'." - ) == 0) { - $self->{backend_curl} = gorgone::class::http::backend::curl->new(%options, logger => $self->{logger}); - } - } - - if (($options{request}->{proto} ne 'http') && ($options{request}->{proto} ne 'https')) { - $self->{logger}->writeLogError("Unsupported protocol specified '" . $self->{option_results}->{proto} . "'."); - return 1; - } - if (!defined($options{request}->{hostname})) { - $self->{logger}->writeLogError("Please set the hostname option"); - return 1; - } - if ((defined($options{request}->{credentials})) && (!defined($options{request}->{username}) || !defined($options{request}->{password}))) { - $self->{logger}->writeLogError("You need to set --username= and --password= options when --credentials is used"); - return 1; - } - if ((defined($options{request}->{cert_pkcs12})) && (!defined($options{request}->{cert_file}) && !defined($options{request}->{cert_pwd}))) { - $self->{logger}->writeLogError("You need to set --cert-file= and --cert-pwd= options when --pkcs12 is used"); - return 1; - } - - $options{request}->{port_force} = $self->get_port(); - - $options{request}->{headers} = {}; - if (defined($options{request}->{header})) { - foreach (@{$options{request}->{header}}) { - if (/^(.*?):(.*)/) { - $options{request}->{headers}->{$1} = $2; - } - } - } - foreach (keys %{$self->{add_headers}}) { - $options{request}->{headers}->{$_} = $self->{add_headers}->{$_}; - } - - foreach my $method (('get', 'post')) { - if (defined($options{request}->{$method . '_param'})) { - $options{request}->{$method . '_params'} = {}; - foreach (@{$options{request}->{$method . '_param'}}) { - if (/^([^=]+)={0,1}(.*)$/) { - my $key = $1; - my $value = defined($2) ? $2 : 1; - if (defined($options{request}->{$method . '_params'}->{$key})) { - if (ref($options{request}->{$method . '_params'}->{$key}) ne 'ARRAY') { - $options{request}->{$method . '_params'}->{$key} = [ $options{request}->{$method . '_params'}->{$key} ]; - } - push @{$options{request}->{$method . '_params'}->{$key}}, $value; - } else { - $options{request}->{$method . '_params'}->{$key} = $value; - } - } - } - } - } - - $self->{'backend_' . $self->{http_backend}}->check_options(%options); - return 0; -} - -sub get_port { - my ($self, %options) = @_; - - my $port = ''; - if (defined($self->{options}->{port}) && $self->{options}->{port} ne '') { - $port = $self->{options}->{port}; - } else { - $port = 80 if ($self->{options}->{proto} eq 'http'); - $port = 443 if ($self->{options}->{proto} eq 'https'); - } - - return $port; -} - -sub get_port_request { - my ($self, %options) = @_; - - my $port = ''; - if (defined($self->{options}->{port}) && $self->{options}->{port} ne '') { - $port = $self->{options}->{port}; - } - return $port; -} - -sub request { - my ($self, %options) = @_; - - my $request_options = { %{$self->{options}} }; - foreach (keys %options) { - $request_options->{$_} = $options{$_} if (defined($options{$_})); - } - return 1 if ($self->check_options(request => $request_options)); - - return $self->{'backend_' . $self->{http_backend}}->request(request => $request_options); -} - -sub get_first_header { - my ($self, %options) = @_; - - return $self->{'backend_' . $self->{http_backend}}->get_first_header(%options); -} - -sub get_header { - my ($self, %options) = @_; - - return $self->{'backend_' . $self->{http_backend}}->get_header(%options); -} - -sub get_code { - my ($self, %options) = @_; - - return $self->{'backend_' . $self->{http_backend}}->get_code(); -} - -sub get_message { - my ($self, %options) = @_; - - return $self->{'backend_' . $self->{http_backend}}->get_message(); -} - -1; - -__END__ - -=head1 NAME - -HTTP abstraction layer. - -=head1 SYNOPSIS - -HTTP abstraction layer for lwp and curl backends - -=head1 HTTP GLOBAL OPTIONS - -=over 8 - -=item B<--http-peer-addr> - -Set the address you want to connect (Useful if hostname is only a vhost. no ip resolve) - -=item B<--proxyurl> - -Proxy URL - -=item B<--proxypac> - -Proxy pac file (can be an url or local file) - -=item B<--http-backend> - -Set the backend used (Default: 'lwp') -For curl: --http-backend=curl - -=back - -=head1 DESCRIPTION - -B. - -=cut diff --git a/centreon-gorgone/gorgone/class/listener.pm b/centreon-gorgone/gorgone/class/listener.pm deleted file mode 100644 index 61d5421001..0000000000 --- a/centreon-gorgone/gorgone/class/listener.pm +++ /dev/null @@ -1,126 +0,0 @@ -# -# Copyright 2020 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::listener; - -use strict; -use warnings; -use gorgone::standard::constants qw(:all); -use gorgone::standard::library; -use gorgone::class::frame; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - $self->{logger} = $options{logger}; - $self->{gorgone_core} = $options{gorgone}; - $self->{tokens} = {}; - - return $self; -} - -sub event_log { - my ($self) = shift; - - return if (!defined($self->{tokens}->{ $_[0]->{token}})); - - # we want to avoid loop - my $events = $self->{tokens}->{ $_[0]->{token} }; - if ($_[0]->{code} == GORGONE_ACTION_FINISH_KO || $_[0]->{code} == GORGONE_ACTION_FINISH_OK) { - delete $self->{tokens}->{ $_[0]->{token} }; - } - - foreach (keys %{$events->{events}}) { - $self->{logger}->writeLogDebug("[listener] trigger event '$_[0]->{token}'"); - - my $message = '[' . $_ . '] [' . $_[0]->{token} . '] [] { "code": ' . $_[0]->{code} . ', "data": ' . ${$_[0]->{data}} . ' }'; - my $frame = gorgone::class::frame->new(); - $frame->setFrame(\$message); - - $self->{gorgone_core}->message_run({ frame => $frame, router_type => 'internal' }); - } -} - -sub add_listener { - my ($self, %options) = @_; - - $self->{logger}->writeLogDebug("[listener] add token '$options{token}'"); - # an issue can happen if the event is unknown (recursive loop) - if (!defined($self->{tokens}->{$options{token}})) { - my ($log_pace, $timeout) = (30, 600); - $log_pace = $1 if (defined($options{log_pace}) && $options{log_pace} =~ /(\d+)/); - $timeout = $1 if (defined($options{timeout}) && $options{timeout} =~ /(\d+)/); - $self->{tokens}->{$options{token}} = { - target => $options{target}, - log_pace => $log_pace, - timeout => $timeout, - events => { $options{event} => $options{identity} }, - getlog_last => -1, - created => time() - }; - } else { - $self->{tokens}->{$options{token}}->{events}->{$options{event}} = $options{identity}; - } - - $self->check_getlog_token(token => $options{token}); -} - -sub check_getlog_token { - my ($self, %options) = @_; - - if (defined($self->{tokens}->{$options{token}}->{target}) && - $self->{tokens}->{$options{token}}->{target}) { - - return if (defined($self->{gorgone_core}->{id}) && $self->{gorgone_core}->{id} == $self->{tokens}->{$options{token}}->{target}); - - if ((time() - $self->{tokens}->{$options{token}}->{log_pace}) > $self->{tokens}->{$options{token}}->{getlog_last}) { - my $message = "[GETLOG] [] [$self->{tokens}->{$options{token}}->{target}] {}"; - my $frame = gorgone::class::frame->new(); - $frame->setFrame(\$message); - - $self->{gorgone_core}->message_run({ frame => $frame, router_type => 'internal' }); - - $self->{tokens}->{$options{token}}->{getlog_last} = time(); - } - } -} - -sub check { - my ($self, %options) = @_; - - foreach my $token (keys %{$self->{tokens}}) { - if (time() - $self->{tokens}->{$token}->{created} > $self->{tokens}->{$token}->{timeout}) { - $self->{logger}->writeLogDebug("[listener] delete token '$token': timeout"); - gorgone::standard::library::add_history({ - dbh => $self->{gorgone_core}->{db_gorgone}, - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => '{ "message": "listener token ' . $token . ' timeout reached" }' - }); - delete $self->{tokens}->{$token}; - next; - } - $self->check_getlog_token(token => $token); - } -} - -1; diff --git a/centreon-gorgone/gorgone/class/lock.pm b/centreon-gorgone/gorgone/class/lock.pm deleted file mode 100644 index 6b84e07423..0000000000 --- a/centreon-gorgone/gorgone/class/lock.pm +++ /dev/null @@ -1,167 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::lock; - -use strict; -use warnings; - -sub new { - my ($class, $name, %options) = @_; - my %defaults = (name => $name, pid => $$, timeout => 10); - my $self = {%defaults, %options}; - - bless $self, $class; - return $self; -} - -sub is_set { - die "Not implemented"; -} - -sub set { - my $self = shift; - - for (my $i = 0; $self->is_set() && $i < $self->{timeout}; $i++) { - sleep 1; - } - die "Failed to set lock for $self->{name}" if $self->is_set(); -} - -package gorgone::class::lock::file; - -use base qw(gorgone::class::lock); - -sub new { - my $class = shift; - my $self = $class->SUPER::new(@_); - - if (!defined $self->{storagedir}) { - die "Can't build lock, required arguments not provided"; - } - bless $self, $class; - $self->{pidfile} = "$self->{storagedir}/$self->{name}.lock"; - return $self; -} - -sub is_set { - return -e shift->{pidfile}; -} - -sub set { - my $self = shift; - - $self->SUPER::set(); - open LOCK, ">", $self->{pidfile}; - print LOCK $self->{pid}; - close LOCK; -} - -sub DESTROY { - my $self = shift; - - if (defined $self->{pidfile} && -e $self->{pidfile}) { - unlink $self->{pidfile}; - } -} - -package gorgone::class::lock::sql; - -use base qw(gorgone::class::lock); - -sub new { - my $class = shift; - my $self = $class->SUPER::new(@_); - - if (!defined $self->{dbc}) { - die "Can't build lock, required arguments not provided"; - } - bless $self, $class; - $self->{launch_time} = time(); - return $self; -} - -sub is_set { - my $self = shift; - my ($status, $sth) = $self->{dbc}->query({ - query => "SELECT id,running,pid,time_launch FROM cron_operation WHERE name LIKE '$self->{name}'" - }); - - return 1 if ($status == -1); - my $data = $sth->fetchrow_hashref(); - - if (!defined $data->{id}) { - $self->{not_created_yet} = 1; - $self->{previous_launch_time} = 0; - return 0; - } - $self->{id} = $data->{id}; - $data->{pid} = -1 if (!defined($data->{pid})); - $self->{pid} = $data->{pid}; - $self->{previous_launch_time} = $data->{time_launch}; - if (defined $data->{running} && $data->{running} == 1) { - my $line = `ps -ef | grep -v grep | grep $self->{pid} | grep $self->{name}`; - return 0 if !length $line; - return 1; - } - return 0; -} - -sub set { - my $self = shift; - my $status; - - $self->SUPER::set(); - if (defined $self->{not_created_yet}) { - $status = $self->{dbc}->do(<<"EOQ"); -INSERT INTO cron_operation -(name, system, activate) -VALUES ('$self->{name}', '1', '1') -EOQ - goto error if $status == -1; - $self->{id} = $self->{dbc}->last_insert_id(); - return; - } - $status = $self->{dbc}->do(<<"EOQ"); -UPDATE cron_operation -SET running = '1', time_launch = '$self->{launch_time}', pid = '$self->{pid}' -WHERE id = '$self->{id}' -EOQ - goto error if $status == -1; - return; - - error: - die "Failed to set lock for $self->{name}"; -} - -sub DESTROY { - my $self = shift; - - if (defined $self->{dbc}) { - my $exectime = time() - $self->{launch_time}; - $self->{dbc}->do(<<"EOQ"); -UPDATE cron_operation -SET running = '0', last_execution_time = '$exectime', pid = '-1' -WHERE id = '$self->{id}' -EOQ - } -} - -1; diff --git a/centreon-gorgone/gorgone/class/logger.pm b/centreon-gorgone/gorgone/class/logger.pm deleted file mode 100644 index 90b1385981..0000000000 --- a/centreon-gorgone/gorgone/class/logger.pm +++ /dev/null @@ -1,256 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::logger; - -=head1 NOM - -gorgone::class::logger - Simple logging module - -=head1 SYNOPSIS - - #!/usr/bin/perl -w - - use strict; - use warnings; - - use centreon::polling; - - my $logger = new gorgone::class::logger(); - - $logger->writeLogInfo("information"); - -=head1 DESCRIPTION - -This module offers a simple interface to write log messages to various output: - -* standard output -* file -* syslog - -=cut - -use strict; -use warnings; -use Sys::Syslog qw(:standard :macros); -use IO::Handle; -use Encode; - -my %severities = ( - 1 => LOG_INFO, - 2 => LOG_ERR, - 4 => LOG_DEBUG -); - -sub new { - my $class = shift; - - my $self = bless - { - file => 0, - filehandler => undef, - # 0 = nothing, 1 = critical, 3 = info, 7 = debug - severity => 3, - old_severity => 3, - # 0 = stdout, 1 = file, 2 = syslog - log_mode => 0, - # Output pid of current process - withpid => 0, - # syslog - log_facility => undef, - log_option => LOG_PID, - }, $class; - return $self; -} - -sub file_mode($$) { - my ($self, $file) = @_; - - if (defined($self->{filehandler})) { - $self->{filehandler}->close(); - } - if (open($self->{filehandler}, ">>", $file)){ - $self->{log_mode} = 1; - $self->{filehandler}->autoflush(1); - $self->{file_name} = $file; - return 1; - } - $self->{filehandler} = undef; - print STDERR "Cannot open file $file: $!\n"; - return 0; -} - -sub is_file_mode { - my $self = shift; - - if ($self->{log_mode} == 1) { - return 1; - } - return 0; -} - -sub is_debug { - my $self = shift; - - if (($self->{severity} & 4) == 0) { - return 0; - } - return 1; -} - -sub syslog_mode($$$) { - my ($self, $logopt, $facility) = @_; - - $self->{log_mode} = 2; - openlog($0, $logopt, $facility); - return 1; -} - -# For daemons -sub redirect_output { - my $self = shift; - - if ($self->is_file_mode()) { - open my $lfh, '>>', $self->{file_name}; - open STDOUT, '>&', $lfh; - open STDERR, '>&', $lfh; - } -} - -sub flush_output { - my ($self, %options) = @_; - - $| = 1 if (defined($options{enabled})); -} - -sub force_default_severity { - my ($self, %options) = @_; - - $self->{old_severity} = defined($options{severity}) ? $options{severity} : $self->{severity}; -} - -sub set_default_severity { - my $self = shift; - - $self->{severity} = $self->{old_severity}; -} - -# Getter/Setter Log severity -sub severity { - my $self = shift; - if (@_) { - my $save_severity = $self->{severity}; - if ($_[0] =~ /^[012347]$/) { - $self->{severity} = $_[0]; - } elsif ($_[0] eq 'none') { - $self->{severity} = 0; - } elsif ($_[0] eq 'error') { - $self->{severity} = 1; - } elsif ($_[0] eq 'info') { - $self->{severity} = 3; - } elsif ($_[0] eq 'debug') { - $self->{severity} = 7; - } else { - $self->writeLogError('Wrong severity value set.'); - return -1; - } - $self->{old_severity} = $save_severity; - } - return $self->{severity}; -} - -sub withpid { - my $self = shift; - if (@_) { - $self->{withpid} = $_[0]; - } - return $self->{withpid}; -} - -sub get_date { - my $self = shift; - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time()); - return sprintf( - '%04d-%02d-%02d %02d:%02d:%02d', - $year+1900, $mon+1, $mday, $hour, $min, $sec - ); -} - -sub writeLog { - my ($self) = shift; - - my $withdate = (defined $_[0]->{withdate}) ? $_[0]->{withdate} : 1; - my $withseverity = (defined $_[0]->{withseverity}) ? $_[0]->{withseverity} : 1; - - if (($self->{severity} & $_[0]->{severity}) == 0) { - return; - } - - if (length($_[0]->{message}) > 20000) { - $_[0]->{message} = substr($_[0]->{message}, 0, 20000) . '...'; - } - if ($self->{log_mode} == 2) { - syslog($severities{$_[0]->{severity}}, $_[0]->{message}); - return; - } - - $_[0]->{message} = (($self->{withpid} == 1) ? "$$ - $_[0]->{message} " : $_[0]->{message}); - $_[0]->{message} = ($withseverity) - ? $_[0]->{severity_str} . " - $_[0]->{message}" : $_[0]->{message}; - $_[0]->{message} = ($withdate) - ? $self->get_date . " - $_[0]->{message}" : $_[0]->{message}; - - chomp($_[0]->{message}); - if ($self->{log_mode} == 0) { - print "$_[0]->{message}\n"; - } elsif ($self->{log_mode} == 1) { - if (defined $self->{filehandler}) { - print { $self->{filehandler} } "$_[0]->{message}\n"; - } - } -} - -sub writeLogDebug { - my ($self) = shift; - - $self->writeLog({ severity => 4, severity_str => 'DEBUG', message => $_[0] }); -} - -sub writeLogInfo { - my ($self) = shift; - - $self->writeLog({ severity => 2, severity_str => 'INFO', message => $_[0] }); -} - -sub writeLogError { - my ($self) = shift; - - $self->writeLog({ severity => 1, severity_str => 'ERROR', message => $_[0] }); -} - -sub DESTROY { - my $self = shift; - - if (defined $self->{filehandler}) { - $self->{filehandler}->close(); - } -} - -1; diff --git a/centreon-gorgone/gorgone/class/module.pm b/centreon-gorgone/gorgone/class/module.pm deleted file mode 100644 index f80b525dae..0000000000 --- a/centreon-gorgone/gorgone/class/module.pm +++ /dev/null @@ -1,401 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::module; - -use strict; -use warnings; - -use gorgone::standard::constants qw(:all); -use gorgone::standard::library; -use gorgone::standard::misc; -use gorgone::class::tpapi; -use ZMQ::FFI qw(ZMQ_DONTWAIT); -use JSON::XS; -use Crypt::Mode::CBC; -use Try::Tiny; -use EV; -use MIME::Base64; - -my %handlers = (DIE => {}); - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - { - local $SIG{__DIE__}; - $self->{zmq_context} = ZMQ::FFI->new(); - } - - $self->{internal_socket} = undef; - $self->{module_id} = $options{module_id}; - $self->{container_id} = $options{container_id}; - $self->{container} = ''; - $self->{container} = ' container ' . $self->{container_id} . ':' if (defined($self->{container_id})); - - $self->{core_id} = $options{core_id}; - $self->{logger} = $options{logger}; - $self->{config} = $options{config}; - $self->{exit_timeout} = (defined($options{config}->{exit_timeout}) && $options{config}->{exit_timeout} =~ /(\d+)/) ? $1 : 30; - $self->{config_core} = $options{config_core}; - $self->{config_db_centreon} = $options{config_db_centreon}; - $self->{config_db_centstorage} = $options{config_db_centstorage}; - $self->{stop} = 0; - $self->{fork} = 0; - - $self->{loop} = new EV::Loop(); - - $self->{internal_crypt} = { enabled => 0 }; - if ($self->get_core_config(name => 'internal_com_crypt') == 1) { - $self->{cipher} = Crypt::Mode::CBC->new( - $self->get_core_config(name => 'internal_com_cipher'), - $self->get_core_config(name => 'internal_com_padding') - ); - - $self->{internal_crypt} = { - enabled => 1, - rotation => $self->get_core_config(name => 'internal_com_rotation'), - cipher => $self->get_core_config(name => 'internal_com_cipher'), - padding => $self->get_core_config(name => 'internal_com_padding'), - iv => $self->get_core_config(name => 'internal_com_iv'), - core_keys => [$self->get_core_config(name => 'internal_com_core_key'), $self->get_core_config(name => 'internal_com_core_oldkey')], - identity_keys => $self->get_core_config(name => 'internal_com_identity_keys') - }; - } - - $self->{tpapi} = gorgone::class::tpapi->new(); - $self->{tpapi}->load_configuration(configuration => $options{config_core}->{tpapi}); - - $SIG{__DIE__} = \&class_handle_DIE; - $handlers{DIE}->{$self} = sub { $self->handle_DIE($_[0]) }; - - return $self; -} - -sub class_handle_DIE { - my ($msg) = @_; - - foreach (keys %{$handlers{DIE}}) { - &{$handlers{DIE}->{$_}}($msg); - } -} - -sub handle_DIE { - my ($self, $msg) = @_; - - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} Receiving DIE: $msg"); -} - -sub generate_token { - my ($self, %options) = @_; - - return gorgone::standard::library::generate_token(length => $options{length}); -} - -sub set_fork { - my ($self, %options) = @_; - - $self->{fork} = 1; -} - -sub event { - my ($self, %options) = @_; - - my $socket = defined($options{socket}) ? $options{socket} : $self->{internal_socket}; - while ($socket->has_pollin()) { - my ($message) = $self->read_message(); - next if (!defined($message)); - - $self->{logger}->writeLogDebug("[$self->{module_id}]$self->{container} Event: $message"); - if ($message =~ /^\[(.*?)\]/) { - if ((my $method = $self->can('action_' . lc($1)))) { - $message =~ /^\[(.*?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)$/m; - my ($action, $token) = ($1, $2); - my ($rv, $data) = $self->json_decode(argument => $3, token => $token); - next if ($rv); - - $method->($self, token => $token, data => $data); - } - } - } -} - -sub get_core_config { - my ($self, %options) = @_; - - return $self->{config_core}->{gorgonecore} if (!defined($options{name})); - - return $self->{config_core}->{gorgonecore}->{ $options{name} }; -} - -sub read_message { - my ($self, %options) = @_; - - my ($rv, $message) = gorgone::standard::library::zmq_dealer_read_message( - socket => defined($options{socket}) ? $options{socket} : $self->{internal_socket}, - frame => $options{frame} - ); - return (undef, 1) if ($rv); - if ($self->{internal_crypt}->{enabled} == 0) { - if (defined($options{frame})) { - return (undef, 0); - } - return ($message, 0); - } - - foreach my $key (@{$self->{internal_crypt}->{core_keys}}) { - next if (!defined($key)); - - if (defined($options{frame})) { - if ($options{frame}->decrypt({ cipher => $self->{cipher}, key => $key, iv => $self->{internal_crypt}->{iv} }) == 0) { - return (undef, 0); - } - } else { - my $plaintext; - try { - $plaintext = $self->{cipher}->decrypt(MIME::Base64::decode_base64($message), $key, $self->{internal_crypt}->{iv}); - }; - if (defined($plaintext) && $plaintext =~ /^\[[A-Za-z_\-]+?\]/) { - $message = undef; - return ($plaintext, 0); - } - } - } - - if (defined($options{frame})) { - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} decrypt issue: " . $options{frame}->getLastError()); - } else { - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} decrypt issue: " . ($_ ? $_ : 'no message')); - } - return (undef, 1); -} - -sub renew_internal_key { - my ($self, %options) = @_; - - my $message = gorgone::standard::library::build_protocol( - action => 'SETMODULEKEY', - data => { key => unpack('H*', $options{key}) }, - json_encode => 1 - ); - try { - $message = $self->{cipher}->encrypt($message, $options{encrypt_key}, $self->{internal_crypt}->{iv}); - } catch { - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} encrypt issue: $_"); - return -1; - }; - - return (0, $message); -} - -sub send_internal_action { - my ($self, $options) = (shift, shift); - - if (!defined($options->{message})) { - $options->{message} = gorgone::standard::library::build_protocol( - token => $options->{token}, - action => $options->{action}, - target => $options->{target}, - data => $options->{data}, - json_encode => defined($options->{data_noencode}) ? undef : 1 - ); - } - $self->{logger}->writeLogDebug("[$self->{module_id}]$self->{container} internal message: $options->{message}"); - - my $socket = defined($options->{socket}) ? $options->{socket} : $self->{internal_socket}; - my $message_key; - if ($self->{internal_crypt}->{enabled} == 1) { - my $identity = gorgone::standard::library::zmq_get_routing_id(socket => $socket); - - my $key = $self->{internal_crypt}->{core_keys}->[0]; - if ($self->{fork} == 0) { - if (!defined($self->{internal_crypt}->{identity_keys}->{$identity}) || - (time() - $self->{internal_crypt}->{identity_keys}->{$identity}->{ctime}) > ($self->{internal_crypt}->{rotation})) { - my ($rv, $genkey) = gorgone::standard::library::generate_symkey( - keysize => $self->get_core_config(name => 'internal_com_keysize') - ); - - ($rv, $message_key) = $self->renew_internal_key( - key => $genkey, - encrypt_key => defined($self->{internal_crypt}->{identity_keys}->{$identity}) ? - $self->{internal_crypt}->{identity_keys}->{$identity}->{key} : $self->{internal_crypt}->{core_keys}->[0] - ); - return undef if ($rv == -1); - - $self->{internal_crypt}->{identity_keys}->{$identity} = { - key => $genkey, - ctime => time() - }; - } - - $key = $self->{internal_crypt}->{identity_keys}->{$identity}->{key}; - } - - try { - $options->{message} = $self->{cipher}->encrypt($options->{message}, $key, $self->{internal_crypt}->{iv}); - } catch { - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} encrypt issue: $_"); - return undef; - }; - - $options->{message} = MIME::Base64::encode_base64($options->{message}, ''); - } - - $socket->send(MIME::Base64::encode_base64($message_key, ''), ZMQ_DONTWAIT) if (defined($message_key)); - $socket->send($options->{message}, ZMQ_DONTWAIT); - if ($socket->has_error) { - $self->{logger}->writeLogError( - "[$self->{module_id}]$self->{container} Cannot send message: " . $socket->last_strerror - ); - } - $self->event(socket => $socket); -} - -sub send_log_msg_error { - my ($self, %options) = @_; - - return if (!defined($options{token})); - - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} -$options{subname}- $options{number} $options{message}"); - $self->send_internal_action({ - socket => (defined($options{socket})) ? $options{socket} : $self->{internal_socket}, - action => 'PUTLOG', - token => $options{token}, - data => { code => GORGONE_ACTION_FINISH_KO, etime => time(), instant => $options{instant}, token => $options{token}, data => { message => $options{message} } }, - json_encode => 1 - }); -} - -sub send_log { - my ($self, %options) = @_; - - return if (!defined($options{token})); - - return if (defined($options{logging}) && $options{logging} =~ /^(?:false|0)$/); - - $self->send_internal_action({ - socket => (defined($options{socket})) ? $options{socket} : $self->{internal_socket}, - action => 'PUTLOG', - token => $options{token}, - data => { code => $options{code}, etime => time(), instant => $options{instant}, token => $options{token}, data => $options{data} }, - json_encode => 1 - }); -} - -sub json_encode { - my ($self, %options) = @_; - - my $encoded_arguments; - try { - $encoded_arguments = JSON::XS->new->encode($options{argument}); - } catch { - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} $options{method} - cannot encode json: $_"); - return 1; - }; - - return (0, $encoded_arguments); -} - -sub json_decode { - my ($self, %options) = @_; - - my $decoded_arguments; - try { - $decoded_arguments = JSON::XS->new->decode($options{argument}); - } catch { - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} $options{method} - cannot decode json: $_"); - if (defined($options{token})) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'cannot decode json' } - ); - } - return 1; - }; - - return (0, $decoded_arguments); -} - -sub execute_shell_cmd { - my ($self, %options) = @_; - - my $timeout = defined($options{timeout}) && $options{timeout} =~ /(\d+)/ ? $1 : 30; - my ($lerror, $stdout, $exit_code) = gorgone::standard::misc::backtick( - command => $options{cmd}, - logger => $self->{logger}, - timeout => $timeout, - wait_exit => 1, - ); - if ($lerror == -1 || ($exit_code >> 8) != 0) { - $self->{logger}->writeLogError("[$self->{module_id}]$self->{container} command execution issue $options{cmd} : " . $stdout); - return -1; - } - - return 0; -} - -sub change_macros { - my ($self, %options) = @_; - - $options{template} =~ s/%\{(.*?)\}/$options{macros}->{$1}/g; - if (defined($options{escape})) { - $options{template} =~ s/([\Q$options{escape}\E])/\\$1/g; - } - return $options{template}; -} - -sub action_bcastlogger { - my ($self, %options) = @_; - - my $data = $options{data}; - if (defined($options{frame})) { - $data = $options{frame}->decodeData(); - } - - if (defined($data->{content}->{severity}) && $data->{content}->{severity} ne '') { - if ($data->{content}->{severity} eq 'default') { - $self->{logger}->set_default_severity(); - } else { - $self->{logger}->severity($data->{content}->{severity}); - } - } -} - -sub action_bcastcorekey { - my ($self, %options) = @_; - - return if ($self->{internal_crypt}->{enabled} == 0); - - my $data = $options{data}; - if (defined($options{frame})) { - $data = $options{frame}->decodeData(); - } - - if (defined($data->{key})) { - $self->{logger}->writeLogDebug("[$self->{module_id}]$self->{container} core key changed"); - $self->{internal_crypt}->{core_keys}->[1] = $self->{internal_crypt}->{core_keys}->[0]; - $self->{internal_crypt}->{core_keys}->[0] = pack('H*', $data->{key}); - } -} - -1; diff --git a/centreon-gorgone/gorgone/class/script.pm b/centreon-gorgone/gorgone/class/script.pm deleted file mode 100644 index a589110179..0000000000 --- a/centreon-gorgone/gorgone/class/script.pm +++ /dev/null @@ -1,264 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::script; - -use strict; -use warnings; -use FindBin; -use Getopt::Long; -use Pod::Usage; -use gorgone::class::logger; -use gorgone::class::db; -use gorgone::class::lock; -use YAML::XS; -use Hash::Merge; -Hash::Merge::set_behavior('RIGHT_PRECEDENT'); -$YAML::XS::Boolean = 'JSON::PP'; -$YAML::XS::LoadBlessed = 1; - -$SIG{__DIE__} = sub { - my $error = shift; - print "Error: $error"; - exit 1; -}; - -sub new { - my ($class, $name, %options) = @_; - my %defaults = ( - log_file => undef, - centreon_db_conn => 0, - centstorage_db_conn => 0, - severity => 'info', - noroot => 0 - ); - my $self = {%defaults, %options}; - - bless $self, $class; - $self->{name} = $name; - $self->{logger} = gorgone::class::logger->new(); - $self->{options} = { - 'config=s' => \$self->{config_file}, - 'logfile=s' => \$self->{log_file}, - 'severity=s' => \$self->{severity}, - 'flushoutput' => \$self->{flushoutput}, - 'help|?' => \$self->{help}, - 'version' => \$self->{version} - }; - return $self; -} - -sub init { - my $self = shift; - - if (defined $self->{log_file}) { - $self->{logger}->file_mode($self->{log_file}); - } - $self->{logger}->flush_output(enabled => $self->{flushoutput}); - $self->{logger}->severity($self->{severity}); - $self->{logger}->force_default_severity(); - - if ($self->{noroot} == 1) { - # Stop exec if root - if ($< == 0) { - $self->{logger}->writeLogError("Can't execute script as root."); - die('Quit'); - } - } - - if ($self->{centreon_db_conn}) { - $self->{cdb} = gorgone::class::db->new( - db => $self->{centreon_config}->{centreon_db}, - host => $self->{centreon_config}->{db_host}, - user => $self->{centreon_config}->{db_user}, - password => $self->{centreon_config}->{db_passwd}, - logger => $self->{logger} - ); - $self->{lock} = gorgone::class::lock::sql->new($self->{name}, dbc => $self->{cdb}); - $self->{lock}->set(); - } - if ($self->{centstorage_db_conn}) { - $self->{csdb} = gorgone::class::db->new( - db => $self->{centreon_config}->{centstorage_db}, - host => $self->{centreon_config}->{db_host}, - user => $self->{centreon_config}->{db_user}, - password => $self->{centreon_config}->{db_passwd}, - logger => $self->{logger} - ); - } -} - -sub DESTROY { - my $self = shift; - - if (defined $self->{cdb}) { - $self->{cdb}->disconnect(); - } - if (defined $self->{csdb}) { - $self->{csdb}->disconnect(); - } -} - -sub add_options { - my ($self, %options) = @_; - - $self->{options} = {%{$self->{options}}, %options}; -} - -sub parse_options { - my $self = shift; - - Getopt::Long::Configure('bundling'); - die "Command line error" if (!GetOptions(%{$self->{options}})); - pod2usage(-exitval => 1, -input => $FindBin::Bin . "/" . $FindBin::Script) if ($self->{help}); - if ($self->{version}) { - print "version: " . $self->get_version() . "\n"; - exit(0); - } -} - -sub run { - my $self = shift; - - $self->parse_options(); - $self->init(); -} - -sub yaml_get_include { - my ($self, %options) = @_; - - my @all_files = (); - my @dirs = split(/,/, $options{include}); - foreach my $dir (@dirs) { - next if ($dir eq ''); - my $dirname = File::Basename::dirname($dir); - $dirname = $options{current_dir} . '/' . $dirname if ($dirname !~ /^\//); - my $match_files = File::Basename::basename($dir); - $match_files =~ s/\*/\\E.*\\Q/g; - $match_files = '\Q' . $match_files . '\E'; - - my @sorted_files = (); - my $DIR; - if (!opendir($DIR, $dirname)) { - $self->{logger}->writeLogError("config - cannot opendir '$dirname' error: $!"); - return (); - } - - while (readdir($DIR)) { - if (-f "$dirname/$_" && eval "/^$match_files\$/") { - push @sorted_files, "$dirname/$_"; - } - } - closedir($DIR); - @sorted_files = sort { $a cmp $b } @sorted_files; - push @all_files, @sorted_files; - } - - return @all_files; -} - -sub yaml_parse_config { - my ($self, %options) = @_; - - if (ref(${$options{config}}) eq 'HASH') { - foreach (keys %{${$options{config}}}) { - my $ariane = $options{ariane} . $_ . '##'; - if (defined($options{filter}) && eval "$options{filter}") { - delete ${$options{config}}->{$_}; - next; - } - $self->yaml_parse_config( - config => \${$options{config}}->{$_}, - current_dir => $options{current_dir}, - filter => $options{filter}, - ariane => $ariane - ); - } - } elsif (ref(${$options{config}}) eq 'ARRAY') { - my $size = @{${$options{config}}}; - my $ariane = $options{ariane} . 'ARRAY##'; - for (my $i = 0; $i < $size; $i++) { - if (defined($options{filter}) && eval "$options{filter}") { - ${$options{config}} = undef; - last; - } - $self->yaml_parse_config( - config => \${$options{config}}->[$i], - current_dir => $options{current_dir}, - filter => $options{filter}, - ariane => $ariane - ); - } - } elsif (ref(${$options{config}}) eq 'include') { - my @files = $self->yaml_get_include( - include => ${${$options{config}}}, - current_dir => $options{current_dir}, - filter => $options{filter} - ); - ${$options{config}} = undef; - foreach (@files) { - if (! -r $_) { - $self->{logger}->writeLogError("config - cannot read file '$_'"); - next; - } - my $config = $self->yaml_load_config(file => $_, filter => $options{filter}, ariane => $options{ariane}); - next if (!defined($config)); - if (ref($config) eq 'ARRAY') { - ${$options{config}} = [] if (ref(${$options{config}}) ne 'ARRAY'); - push @{${$options{config}}}, @$config; - } elsif (ref($config) eq 'HASH') { - ${$options{config}} = {} if (ref(${$options{config}}) ne 'HASH'); - ${$options{config}} = Hash::Merge::merge(${$options{config}}, $config); - } else { - ${$options{config}} = $config; - } - } - } elsif (ref(${$options{config}}) eq 'JSON::PP::Boolean') { - if (${${$options{config}}}) { - ${$options{config}} = 'true'; - } else { - ${$options{config}} = 'false'; - } - } -} - -sub yaml_load_config { - my ($self, %options) = @_; - - my $config; - eval { - $config = YAML::XS::LoadFile($options{file}); - }; - if ($@) { - $self->{logger}->writeLogError("config - yaml load file '$options{file}' error: $@"); - return undef; - } - - my $current_dir = File::Basename::dirname($options{file}); - $self->yaml_parse_config( - config => \$config, - current_dir => $current_dir, - filter => $options{filter}, - ariane => defined($options{ariane}) ? $options{ariane} : '' - ); - return $config; -} - -1; diff --git a/centreon-gorgone/gorgone/class/sqlquery.pm b/centreon-gorgone/gorgone/class/sqlquery.pm deleted file mode 100644 index e9a8467591..0000000000 --- a/centreon-gorgone/gorgone/class/sqlquery.pm +++ /dev/null @@ -1,155 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::sqlquery; - -use strict; -use warnings; - -sub new { - my ($class, %options) = @_; - my $self = {}; - $self->{logger} = $options{logger}; - $self->{db_centreon} = $options{db_centreon}; - - bless $self, $class; - return $self; -} - -sub builder { - my ($self, %options) = @_; - - my $where = defined($options{where}) ? ' WHERE ' . $options{where} : ''; - my $extra_suffix = defined($options{extra_suffix}) ? $options{extra_suffix} : ''; - my $request = $options{request} . " " . join(', ', @{$options{fields}}) . - ' FROM ' . join(', ', @{$options{tables}}) . $where . $extra_suffix; - return $request; -} - -sub do { - my ($self, %options) = @_; - my $mode = defined($options{mode}) ? $options{mode} : 0; - - my ($status, $sth) = $self->{db_centreon}->query({ query => $options{request}, bind_values => $options{bind_values} }); - if ($status == -1) { - return (-1, undef); - } - if ($mode == 0) { - return ($status, $sth); - } elsif ($mode == 1) { - my $result = $sth->fetchall_hashref($options{keys}); - if (!defined($result)) { - $self->{logger}->writeLogError("[core] Cannot fetch database data: " . $sth->errstr . " [request = $options{request}]"); - return (-1, undef); - } - return ($status, $result); - } - my $result = $sth->fetchall_arrayref(); - if (!defined($result)) { - $self->{logger}->writeLogError("[core] Cannot fetch database data: " . $sth->errstr . " [request = $options{request}]"); - return (-1, undef); - } - return ($status, $result); -} - -sub custom_execute { - my ($self, %options) = @_; - - return $self->do(%options); -} - -sub execute { - my ($self, %options) = @_; - - my $request = $self->builder(%options); - return $self->do(request => $request, %options); -} - -sub transaction_query_multi { - my ($self, %options) = @_; - - my ($status, $sth); - - $status = $self->transaction_mode(1); - return -1 if ($status == -1); - - ($status, $sth) = $self->{db_centreon}->query({ query => $options{request}, prepare_only => 1 }); - if ($status == -1) { - $self->rollback(); - return -1; - } - - if (defined($options{bind_values}) && scalar(@{$options{bind_values}}) > 0) { - $sth->execute(@{$options{bind_values}}); - } else { - $sth->execute(); - } - do { - if ($sth->err) { - $self->rollback(); - $self->{db_centreon}->error($sth->errstr, $options{request}); - return -1; - } - } while ($sth->more_results); - - $status = $self->commit(); - return -1 if ($status == -1); - - return 0; -} - -sub transaction_query { - my ($self, %options) = @_; - my $status; - - $status = $self->transaction_mode(1); - return -1 if ($status == -1); - - ($status) = $self->do(request => $options{request}); - if ($status == -1) { - $self->rollback(); - return -1; - } - - $status = $self->commit(); - return -1 if ($status == -1); - - return 0; -} - -sub transaction_mode { - my ($self) = @_; - - return $self->{db_centreon}->transaction_mode($_[1]); -}; - -sub commit { - my ($self, %options) = @_; - - return $self->{db_centreon}->commit(); -} - -sub rollback { - my ($self, %options) = @_; - - return $self->{db_centreon}->rollback(); -} - -1; diff --git a/centreon-gorgone/gorgone/class/tpapi.pm b/centreon-gorgone/gorgone/class/tpapi.pm deleted file mode 100644 index 27b6697e84..0000000000 --- a/centreon-gorgone/gorgone/class/tpapi.pm +++ /dev/null @@ -1,55 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::tpapi; - -use strict; -use warnings; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - $self->{configs} = {}; - - return $self; -} - -sub get_configuration { - my ($self, %options) = @_; - - return $self->{configs}->{ $options{name} }; -} - -sub load_configuration { - my ($self, %options) = @_; - - $self->{configs} = {}; - return if (!defined($options{configuration})); - - foreach my $config (@{$options{configuration}}) { - next if (!defined($config->{name})); - - $self->{configs}->{ $config->{name} } = $config; - } -} - -1; diff --git a/centreon-gorgone/gorgone/class/tpapi/centreonv2.pm b/centreon-gorgone/gorgone/class/tpapi/centreonv2.pm deleted file mode 100644 index 9bd5d84a24..0000000000 --- a/centreon-gorgone/gorgone/class/tpapi/centreonv2.pm +++ /dev/null @@ -1,286 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::tpapi::centreonv2; - -use strict; -use warnings; -use gorgone::class::http::http; -use JSON::XS; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - $self->{is_error} = 1; - $self->{error} = 'configuration missing'; - $self->{is_logged} = 0; - - return $self; -} - -sub json_decode { - my ($self, %options) = @_; - - my $decoded; - eval { - $decoded = JSON::XS->new->decode($options{content}); - }; - if ($@) { - $self->{is_error} = 1; - $self->{error} = "cannot decode json response: $@"; - return undef; - } - - return $decoded; -} - -sub error { - my ($self, %options) = @_; - - return $self->{error}; -} - -sub set_configuration { - my ($self, %options) = @_; - - if (!defined($options{config})) { - return 1; - } - - foreach (('base_url', 'username', 'password')) { - if (!defined($options{config}->{$_}) || - $options{config}->{$_} eq '') { - $self->{error} = $_ . ' configuration missing'; - return 1; - } - - $self->{$_} = $options{config}->{$_}; - } - - $self->{base_url} =~ s/\/$//; - - $self->{http_backend} = defined($options{config}->{backend}) ? $options{config}->{backend} : 'curl'; - - $self->{curl_opts} = ['CURLOPT_SSL_VERIFYPEER => 0', 'CURLOPT_POSTREDIR => CURL_REDIR_POST_ALL']; - my $curl_opts = []; - if (defined($options{config}->{curlopts})) { - foreach (keys %{$options{config}->{curlopts}}) { - push @{$curl_opts}, $_ . ' => ' . $options{config}->{curlopts}->{$_}; - } - } - if (scalar(@$curl_opts) > 0) { - $self->{curl_opts} = $curl_opts; - } - - $self->{http} = gorgone::class::http::http->new(logger => $options{logger}); - $self->{is_error} = 0; - return 0; -} - -sub authenticate { - my ($self, %options) = @_; - - my $json_request = { - security => { - credentials => { - login => $self->{username}, - password => $self->{password} - } - } - }; - my $encoded; - eval { - $encoded = encode_json($json_request); - }; - if ($@) { - $self->{is_error} = 1; - $self->{error} = "cannot encode json request: $@"; - return undef; - } - - my ($code, $content) = $self->{http}->request( - http_backend => $self->{http_backend}, - method => 'POST', - hostname => '', - full_url => $self->{base_url} . '/login', - query_form_post => $encoded, - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => $self->{curl_opts}, - warning_status => '', - unknown_status => '', - critical_status => '' - ); - if ($code) { - $self->{is_error} = 1; - $self->{error} = 'http request error'; - return undef; - } - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{is_error} = 1; - $self->{error} = "Login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"; - return undef; - } - - my $decoded = $self->json_decode(content => $content); - return if (!defined($decoded)); - - my $token = defined($decoded->{security}->{token}) ? $decoded->{security}->{token} : undef; - if (!defined($token)) { - $self->{is_error} = 1; - $self->{error} = 'authenticate issue - cannot get token'; - return undef; - } - - $self->{token} = $token; - $self->{is_logged} = 1; -} - -sub request { - my ($self, %options) = @_; - - if (!defined($self->{base_url})) { - $self->{is_error} = 1; - $self->{error} = 'configuration missing'; - return 1; - } - - $self->{is_error} = 0; - if ($self->{is_logged} == 0) { - $self->authenticate(); - } - - return 1 if ($self->{is_logged} == 0); - - # TODO: manage it properly - my $get_param = ['page=1', 'limit=10000']; - if (defined($options{get_param})) { - push @$get_param, @{$options{get_param}}; - } - - my ($code, $content) = $self->{http}->request( - http_backend => $self->{http_backend}, - method => $options{method}, - hostname => '', - full_url => $self->{base_url} . $options{endpoint}, - query_form_post => $options{query_form_post}, - get_param => $get_param, - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - 'X-AUTH-TOKEN: ' . $self->{token} - ], - curl_opt => $self->{curl_opts}, - warning_status => '', - unknown_status => '', - critical_status => '' - ); - - my $decoded = $self->json_decode(content => $content); - - # code 403 means forbidden (token not good maybe) - if ($self->{http}->get_code() == 403) { - $self->{token} = undef; - $self->{is_logged} = 0; - $self->{is_error} = 1; - $self->{error} = 'token forbidden'; - $self->{error} = $decoded->{message} if (defined($decoded) && defined($decoded->{message})); - return 1; - } - - if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { - $self->{is_error} = 1; - my $message = $self->{http}->get_message(); - $message = $decoded->{message} if (defined($decoded) && defined($decoded->{message})); - $self->{error} = "request error [code: '" . $self->{http}->get_code() . "'] [message: '" . $message . "']"; - return 1; - } - - return 1 if (!defined($decoded)); - - return (0, $decoded); -} - -sub get_token { - my ($self, %options) = @_; - - return $self->{token}; -} - -sub get_monitoring_hosts { - my ($self, %options) = @_; - - my $endpoint = '/monitoring/hosts'; - $endpoint .= '/' . $options{host_id} if (defined($options{host_id})); - - my $get_param; - if (defined($options{search})) { - $get_param = ['search=' . $options{search}]; - } - - return $self->request( - method => 'GET', - endpoint => $endpoint, - get_param => $get_param - ); -} - - -sub get_platform_versions { - my ($self, %options) = @_; - - return $self->request( - method => 'GET', - endpoint => '/platform/versions' - ); -} - -sub get_scheduling_jobs { - my ($self, %options) = @_; - - my $get_param; - if (defined($options{search})) { - $get_param = ['search=' . $options{search}]; - } - - my $endpoint = '/auto-discovery/scheduling/jobs'; - return $self->request( - method => 'GET', - endpoint => $endpoint, - get_param => $get_param - ); -} - -sub DESTROY { - my ($self) = @_; - - if ($self->{is_logged} == 1) { - $self->request( - method => 'GET', - endpoint => '/logout' - ); - } -} - -1; diff --git a/centreon-gorgone/gorgone/class/tpapi/clapi.pm b/centreon-gorgone/gorgone/class/tpapi/clapi.pm deleted file mode 100644 index d7c1810be8..0000000000 --- a/centreon-gorgone/gorgone/class/tpapi/clapi.pm +++ /dev/null @@ -1,104 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::class::tpapi::clapi; - -use strict; -use warnings; - -sub new { - my ($class, %options) = @_; - my $self = {}; - bless $self, $class; - - $self->{is_error} = 1; - $self->{error} = 'configuration missing'; - $self->{username} = undef; - $self->{password} = undef; - - return $self; -} - -sub error { - my ($self, %options) = @_; - - return $self->{error}; -} - -sub get_username { - my ($self, %options) = @_; - - if ($self->{is_error} == 1) { - return undef; - } - - return $self->{username}; -} - -sub get_password { - my ($self, %options) = @_; - - if ($self->{is_error} == 1) { - return undef; - } - - if (defined($options{protected}) && $options{protected} == 1) { - my $password = $self->{password}; - $password =~ s/\$/\\\$/g; - $password =~ s/"/\\"/g; - return $password; - } - - return $self->{password}; -} - -sub set_configuration { - my ($self, %options) = @_; - - if (!defined($options{config}) || - !defined($options{config}->{username}) || - $options{config}->{username} eq '') { - $self->{error} = 'username configuration missing'; - return 1; - } - - if (!defined($options{config}->{password}) || - $options{config}->{password} eq '') { - $self->{error} = 'password configuration missing'; - return 1; - } - - $self->{is_error} = 0; - $self->{username} = $options{config}->{username}; - $self->{password} = $options{config}->{password}; - return 0; -} - -sub get_applycfg_command { - my ($self, %options) = @_; - - if ($self->{is_error} == 1) { - return undef; - } - - return 'centreon -u "' . $self->{username} . '" -p "' . $self->get_password(protected => 1) . '" -a APPLYCFG -v ' . $options{poller_id}; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/anomalydetection/class.pm b/centreon-gorgone/gorgone/modules/centreon/anomalydetection/class.pm deleted file mode 100644 index c1ea2649b1..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/anomalydetection/class.pm +++ /dev/null @@ -1,681 +0,0 @@ -# -# Copyright 2020 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::anomalydetection::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::sqlquery; -use gorgone::class::http::http; -use JSON::XS; -use IO::Compress::Bzip2; -use MIME::Base64; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{resync_time} = (defined($options{config}->{resync_time}) && $options{config}->{resync_time} =~ /(\d+)/) ? $1 : 600; - $connector->{thresholds_sync_time} = (defined($options{config}->{thresholds_sync_time}) && $options{config}->{thresholds_sync_time} =~ /(\d+)/) ? $1 : 28800; - $connector->{last_resync_time} = -1; - $connector->{saas_token} = undef; - $connector->{saas_url} = undef; - $connector->{proxy_url} = undef; # format http://[username:password@]server:port - $connector->{centreon_metrics} = {}; - $connector->{unregister_metrics_centreon} = {}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[anomalydetection] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub http_check_error { - my ($self, %options) = @_; - - if ($options{status} == 1) { - $self->{logger}->writeLogError("[anomalydetection] -class- $options{endpoint} issue"); - return 1; - } - - my $code = $self->{http}->get_code(); - if ($code !~ /$options{http_code_continue}/) { - $self->{logger}->writeLogError("[anomalydetection] -class- $options{endpoint} issue - " . $self->{http}->get_message()); - return 1; - } - - return 0; -} - -sub get_localhost_poller { - my ($self, %options) = @_; - - my $instance; - foreach (keys %{$self->{pollers}}) { - if ($self->{pollers}->{$_}->{localhost} == 1) { - $instance = $_; - last; - } - } - - return $instance; -} - -sub get_poller { - my ($self, %options) = @_; - - return $self->{pollers}->{$options{instance}}; -} - -sub write_file { - my ($self, %options) = @_; - - my $fh; - if (!open($fh, '>', $options{file})) { - $self->{logger}->writeLogError("[anomalydetection] -class- cannot open file '" . $options{file} . "': $!"); - return 1; - } - print $fh $options{content}; - close($fh); - return 0; -} - -sub saas_api_request { - my ($self, %options) = @_; - - my ($status, $payload); - if (defined($options{payload})) { - ($status, $payload) = $self->json_encode(argument => $options{payload}); - return 1 if ($status == 1); - } - my $accept = defined $options{accept} ? $options{accept} : '*/*'; - - ($status, my $response) = $self->{http}->request( - method => $options{method}, hostname => '', - full_url => $self->{saas_url} . $options{endpoint}, - query_form_post => $payload, - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - 'Accept: ' . $accept, - 'x-api-key: ' . $self->{saas_token} - ], - proxyurl => $self->{proxy_url}, - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0'] - ); - return 1 if ($self->http_check_error(status => $status, endpoint => $options{endpoint}, http_code_continue => $options{http_code_continue}) == 1); - - ($status, my $result) = $self->json_decode(argument => $response); - return 1 if ($status == 1); - - return (0, $result); -} - -sub connection_informations { - my ($self, %options) = @_; - - my ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => "select `key`, `value` from options WHERE `key` IN ('saas_url', 'saas_token', 'proxy_url', 'proxy_port', 'proxy_user', 'proxy_password')", - mode => 2 - ); - if ($status == -1) { - $self->{logger}->writeLogError('[anomalydetection] -class- cannot get connection informations'); - return 1; - } - - $self->{$_->[0]} = $_->[1] foreach (@$datas); - - if (!defined($self->{saas_url}) || $self->{saas_url} eq '') { - $self->{logger}->writeLogInfo('[anomalydetection] -class- database: saas_url is not defined'); - return 1; - } - $self->{saas_url} =~ s/\/$//g; - - if (!defined($self->{saas_token}) || $self->{saas_token} eq '') { - $self->{logger}->writeLogInfo('[anomalydetection] -class- database: saas_token is not defined'); - return 1; - } - - if (defined($self->{proxy_url})) { - if ($self->{proxy_url} eq '') { - $self->{proxy_url} = undef; - return 0; - } - - $self->{proxy_url} = $self->{proxy_user} . ':' . $self->{proxy_password} . '@' . $self->{proxy_url} - if (defined($self->{proxy_user}) && $self->{proxy_user} ne '' && - defined($self->{proxy_password}) && $self->{proxy_password} ne ''); - $self->{proxy_url} = $self->{proxy_url} . ':' . $self->{proxy_port} - if (defined($self->{proxy_port}) && $self->{proxy_port} =~ /(\d+)/); - $self->{proxy_url} = 'http://' . $self->{proxy_url}; - } - - return 0; -} - -sub get_centreon_anomaly_metrics { - my ($self, %options) = @_; - - my ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => - 'SELECT nagios_server_id, cfg_dir, centreonbroker_cfg_path, localhost, ' . - 'engine_start_command, engine_stop_command, engine_restart_command, engine_reload_command, ' . - 'broker_reload_command ' . - 'FROM cfg_nagios ' . - 'JOIN nagios_server ' . - 'WHERE id = nagios_server_id', - mode => 1, - keys => 'nagios_server_id' - ); - if ($status == -1) { - $self->{logger}->writeLogError('[anomalydetection] cannot get configuration for pollers'); - return 1; - } - $self->{pollers} = $datas; - - ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => ' - SELECT mas.*, hsr.host_host_id as host_id, nhr.nagios_server_id as instance_id - FROM mod_anomaly_service mas - LEFT JOIN (host_service_relation hsr, ns_host_relation nhr) ON - (mas.service_id = hsr.service_service_id AND hsr.host_host_id = nhr.host_host_id) - ', - keys => 'id', - mode => 1 - ); - if ($status == -1) { - $self->{logger}->writeLogError('[anomalydetection] -class- database: cannot get metrics from centreon'); - return 1; - } - - $self->{centreon_metrics} = $datas; - - return 0; -} - -sub save_centreon_previous_register { - my ($self, %options) = @_; - - my ($query, $query_append) = ('', ''); - my @bind_values = (); - foreach (keys %{$self->{unregister_metrics_centreon}}) { - $query .= $query_append . - 'UPDATE mod_anomaly_service SET' . - ' saas_model_id = ?,' . - ' saas_metric_id = ?,' . - ' saas_creation_date = ?, ' . - ' saas_update_date = ?' . - ' WHERE `id` = ?'; - $query_append = ';'; - push @bind_values, $self->{unregister_metrics_centreon}->{$_}->{saas_model_id}, $self->{unregister_metrics_centreon}->{$_}->{saas_metric_id}, - $self->{unregister_metrics_centreon}->{$_}->{creation_date}, $self->{unregister_metrics_centreon}->{$_}->{creation_date}, $_; - } - - if ($query ne '') { - my $status = $self->{class_object_centreon}->transaction_query_multi(request => $query, bind_values => \@bind_values); - if ($status == -1) { - $self->{logger}->writeLogError('[anomalydetection] -class- database: cannot save centreon previous register'); - return 1; - } - - foreach (keys %{$self->{unregister_metrics_centreon}}) { - $self->{centreon_metrics}->{$_}->{saas_creation_date} = $self->{unregister_metrics_centreon}->{$_}->{creation_date}; - $self->{centreon_metrics}->{$_}->{saas_update_date} = $self->{unregister_metrics_centreon}->{$_}->{creation_date}; - $self->{centreon_metrics}->{$_}->{saas_model_id} = $self->{unregister_metrics_centreon}->{$_}->{saas_model_id}; - $self->{centreon_metrics}->{$_}->{saas_metric_id} = $self->{unregister_metrics_centreon}->{$_}->{saas_metric_id}; - } - } - - $self->{unregister_metrics_centreon} = {}; - return 0; -} - -sub saas_register_metrics { - my ($self, %options) = @_; - - my $register_centreon_metrics = {}; - my ($query, $query_append) = ('', ''); - my @bind_values = (); - - $self->{generate_metrics_lua} = 0; - foreach (keys %{$self->{centreon_metrics}}) { - # saas_creation_date is set when we need to register it - next if (defined($self->{centreon_metrics}->{$_}->{saas_creation_date})); - next if ($self->{centreon_metrics}->{$_}->{saas_to_delete} == 1); - - my $payload = { - metrics => [ - { - name => $self->{centreon_metrics}->{$_}->{metric_name}, - labels => { - host_id => "" . $self->{centreon_metrics}->{$_}->{host_id}, - service_id => "" . $self->{centreon_metrics}->{$_}->{service_id} - }, - preprocessingOptions => { - bucketize => { - bucketizeFunction => 'mean', - period => 300 - } - } - } - ], - algorithm => { - type => $self->{centreon_metrics}->{$_}->{ml_model_name}, - options => { - period => '30d' - } - } - }; - - my ($status, $result) = $self->saas_api_request( - endpoint => '/machinelearning', - method => 'POST', - payload => $payload, - http_code_continue => '^2' - ); - return 1 if ($status); - - $self->{logger}->writeLogDebug( - "[anomalydetection] -class- saas: metric '$self->{centreon_metrics}->{$_}->{host_id}/$self->{centreon_metrics}->{$_}->{service_id}/$self->{centreon_metrics}->{$_}->{metric_name}' registered" - ); - - # { - # "metrics": [ - # { - # "name": "system_load1", - # "labels": { "hostname":"srvi-monitoring" }, - # "preprocessingOptions": { - # "bucketize": { - # "bucketizeFunction": "mean", "period": 300 - # } - # }, - # "id": "e255db55-008b-48cd-8dfe-34cf60babd01" - # } - # ], - # "algorithm": { - # "type": "h2o", - # "options": { "period":"180d" } - # }, - # "id":"257fc68d-3248-4c92-92a1-43c0c63d5e5e" - # } - - $self->{generate_metrics_lua} = 1; - $register_centreon_metrics->{$_} = { - saas_creation_date => time(), - saas_model_id => $result->{id}, - saas_metric_id => $result->{metrics}->[0]->{id} - }; - - $query .= $query_append . - 'UPDATE mod_anomaly_service SET' . - ' saas_model_id = ?,' . - ' saas_metric_id = ?,' . - ' saas_creation_date = ?,' . - ' saas_update_date = ?' . - ' WHERE `id` = ?'; - $query_append = ';'; - push @bind_values, $register_centreon_metrics->{$_}->{saas_model_id}, $register_centreon_metrics->{$_}->{saas_metric_id}, - $register_centreon_metrics->{$_}->{saas_creation_date}, $register_centreon_metrics->{$_}->{saas_creation_date}, $_; - } - - return 0 if ($query eq ''); - - my $status = $self->{class_object_centreon}->transaction_query_multi(request => $query, bind_values => \@bind_values); - if ($status == -1) { - $self->{unregister_metrics_centreon} = $register_centreon_metrics; - $self->{logger}->writeLogError('[anomalydetection] -class- database: cannot update centreon register'); - return 1; - } - - foreach (keys %$register_centreon_metrics) { - $self->{centreon_metrics}->{$_}->{saas_creation_date} = $register_centreon_metrics->{$_}->{saas_creation_date}; - $self->{centreon_metrics}->{$_}->{saas_update_date} = $register_centreon_metrics->{$_}->{saas_creation_date}; - $self->{centreon_metrics}->{$_}->{saas_metric_id} = $register_centreon_metrics->{$_}->{saas_metric_id}; - $self->{centreon_metrics}->{$_}->{saas_model_id} = $register_centreon_metrics->{$_}->{saas_model_id}; - } - - return 0; -} - -sub saas_delete_metrics { - my ($self, %options) = @_; - - my $delete_ids = []; - foreach (keys %{$self->{centreon_metrics}}) { - next if ($self->{centreon_metrics}->{$_}->{saas_to_delete} == 0); - - if (defined($self->{centreon_metrics}->{$_}->{saas_model_id})) { - my ($status, $result) = $self->saas_api_request( - endpoint => '/machinelearning/' . $self->{centreon_metrics}->{$_}->{saas_model_id}, - method => 'DELETE', - http_code_continue => '^(?:2|404)' - ); - next if ($status); - - $self->{logger}->writeLogDebug( - "[anomalydetection] -class- saas: metric '$self->{centreon_metrics}->{$_}->{service_id}/$self->{centreon_metrics}->{$_}->{metric_name}' deleted" - ); - - next if (!defined($result->{message}) || - $result->{message} !~ /machine learning request id is not found/i); - } - - push @$delete_ids, $_; - } - - return 0 if (scalar(@$delete_ids) <= 0); - - my $status = $self->{class_object_centreon}->transaction_query( - request => 'DELETE FROM mod_anomaly_service WHERE id IN (' . join(', ', @$delete_ids) . ')' - ); - if ($status == -1) { - $self->{logger}->writeLogError('[anomalydetection] -class- database: cannot delete centreon saas'); - return 1; - } - - return 0; -} - -sub generate_lua_filter_file { - my ($self, %options) = @_; - - my $data = { filters => { } }; - foreach (values %{$self->{centreon_metrics}}) { - next if ($_->{saas_to_delete} == 1); - next if (!defined($_->{saas_creation_date})); - next if (!defined($_->{host_id})); - - $data->{filters}->{ $_->{host_id} } = {} - if (!defined($data->{filters}->{ $_->{host_id} })); - $data->{filters}->{ $_->{host_id} }->{ $_->{service_id} } = {} - if (!defined($data->{filters}->{ $_->{host_id} }->{ $_->{service_id} })); - $data->{filters}->{ $_->{host_id} }->{ $_->{service_id} }->{ $_->{metric_name} } = 1; - } - - my ($status, $content) = $self->json_encode(argument => $data); - if ($status == 1) { - $self->{logger}->writeLogError('[anomalydetection] -class- cannot encode lua filter file'); - return 1; - } - - my $instance = $self->get_localhost_poller(); - if ($status == 1) { - $self->{logger}->writeLogError('[anomalydetection] -class- cannot find localhost poller'); - return 1; - } - - my $poller = $self->get_poller(instance => $instance); - my $file = $poller->{centreonbroker_cfg_path} . '/anomaly-detection-filters.json'; - if (! -w $poller->{centreonbroker_cfg_path}) { - $self->{logger}->writeLogError("[anomalydetection] -class- cannot write file '" . $file . "'"); - return 1; - } - - return 1 if ($self->write_file(file => $file, content => $content)); - - $self->{logger}->writeLogDebug('[anomalydetection] -class- reload centreon-broker'); - - $self->send_internal_action({ - action => 'COMMAND', - token => $options{token}, - data => { - content => [ { command => 'sudo ' . $poller->{broker_reload_command} } ] - } - }); - - return 0; -} - -sub saas_get_predicts { - my ($self, %options) = @_; - - my ($query, $query_append, $status) = ('', ''); - my $engine_reload = {}; - foreach (keys %{$self->{centreon_metrics}}) { - next if ($self->{centreon_metrics}->{$_}->{saas_to_delete} == 1); - #next if (!defined($self->{centreon_metrics}->{$_}->{thresholds_file}) || - # $self->{centreon_metrics}->{$_}->{thresholds_file} eq ''); - next if (!defined($self->{centreon_metrics}->{$_}->{saas_update_date}) || - $self->{centreon_metrics}->{$_}->{saas_update_date} > time() - $self->{thresholds_sync_time}); - - ($status, my $result) = $self->saas_api_request( - endpoint => '/machinelearning/' . $self->{centreon_metrics}->{$_}->{saas_model_id} . '/predicts', - method => 'GET', - http_code_continue => '^2', - accept => 'application/vnd.centreon.v2+json' - ); - next if ($status); - - $self->{logger}->writeLogDebug( - "[anomalydetection] -class- saas: get predict metric '$self->{centreon_metrics}->{$_}->{host_id}/$self->{centreon_metrics}->{$_}->{service_id}/$self->{centreon_metrics}->{$_}->{metric_name}'" - ); - - next if (!defined($result->[0]) || !defined($result->[0]->{predict})); - - my $data = [ - { - host_id => $self->{centreon_metrics}->{$_}->{host_id}, - service_id => $self->{centreon_metrics}->{$_}->{service_id}, - metric_name => $self->{centreon_metrics}->{$_}->{metric_name}, - predict => $result->[0]->{predict} - } - ]; - ($status, my $content) = $self->json_encode(argument => $data); - next if ($status == 1); - - my $encoded_content; - if (!IO::Compress::Bzip2::bzip2(\$content, \$encoded_content)) { - $self->{logger}->writeLogError('[anomalydetection] -class- cannot compress content: ' . $IO::Compress::Bzip2::Bzip2Error); - next; - } - - $encoded_content = MIME::Base64::encode_base64($encoded_content, ''); - - my $poller = $self->get_poller(instance => $self->{centreon_metrics}->{$_}->{instance_id}); - $self->send_internal_action({ - action => 'COMMAND', - target => $self->{centreon_metrics}->{$_}->{instance_id}, - token => $options{token}, - data => { - content => [ { command => 'mkdir -p ' . $poller->{cfg_dir} . '/anomaly/' . '; echo -n ' . $encoded_content . ' | base64 -d | bzcat -d > "' . $poller->{cfg_dir} . '/anomaly/' . $_ . '.json"' } ] - } - }); - - $engine_reload->{ $self->{centreon_metrics}->{$_}->{instance_id} } = [] if (!defined($engine_reload->{ $self->{centreon_metrics}->{$_}->{instance_id} })); - push @{$engine_reload->{ $self->{centreon_metrics}->{$_}->{instance_id} }}, $poller->{cfg_dir} . '/anomaly/' . $_ . '.json'; - - $query .= $query_append . - 'UPDATE mod_anomaly_service SET' . - ' saas_update_date = ' . time() . - ' WHERE `id` = ' . $_; - $query_append = ';'; - } - - return 0 if ($query eq ''); - - foreach my $instance_id (keys %$engine_reload) { - $self->{logger}->writeLogDebug('[anomalydetection] -class- send engine threshold files external command ' . $instance_id); - my $contents = []; - foreach (@{$engine_reload->{$instance_id}}) { - push @$contents, { - target => $instance_id, - command => 'EXTERNALCMD', - param => '[' . time() . '] NEW_THRESHOLDS_FILE;' . $_ - }; - } - - $self->send_internal_action({ - action => 'CENTREONCOMMAND', - token => $options{token}, - data => { - content => $contents - } - }); - } - - $status = $self->{class_object_centreon}->transaction_query_multi(request => $query); - if ($status == -1) { - $self->{logger}->writeLogError('[anomalydetection] -class- database: cannot update predicts'); - return 1; - } - - return 0; -} - -sub action_saaspredict { - my ($self, %options) = @_; - - $self->{logger}->writeLogDebug('[anomalydetection] -class - start saaspredict'); - $options{token} = $self->generate_token() if (!defined($options{token})); - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action saaspredict proceed' }); - - $self->saas_get_predicts(token => $options{token}); - - $self->{logger}->writeLogDebug('[anomalydetection] -class- finish saaspredict'); - $self->send_log(code => GORGONE_ACTION_FINISH_OK, token => $options{token}, data => { message => 'action saaspredict finished' }); - return 0; -} - -sub action_saasregister { - my ($self, %options) = @_; - - $self->{logger}->writeLogDebug('[anomalydetection] -class- start saasregister'); - $options{token} = $self->generate_token() if (!defined($options{token})); - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action saasregister proceed' }); - - if ($self->connection_informations()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get connection informations' }); - return 1; - } - - if ($self->save_centreon_previous_register()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot save previous register' }); - return 1; - } - - if ($self->get_centreon_anomaly_metrics()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get metrics from centreon' }); - return 1; - } - - if ($self->saas_register_metrics()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get declare metrics in saas' }); - return 1; - } - - if ($self->{generate_metrics_lua} == 1) { - $self->generate_lua_filter_file(token => $options{token}); - } - - if ($self->saas_delete_metrics()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot delete metrics in saas' }); - return 1; - } - - $self->{logger}->writeLogDebug('[anomalydetection] -class- finish saasregister'); - $self->send_log(code => GORGONE_ACTION_FINISH_OK, token => $options{token}, data => { message => 'action saasregister finished' }); - return 0; -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[anomalydetection] -class- $$ has quit"); - exit(0); - } - - if (time() - $connector->{resync_time} > $connector->{last_resync_time}) { - $connector->{last_resync_time} = time(); - $connector->action_saasregister(); - $connector->action_saaspredict(); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{db_centreon} = gorgone::class::db->new( - dsn => $self->{config_db_centreon}->{dsn} . ';mysql_multi_statements=1', - user => $self->{config_db_centreon}->{username}, - password => $self->{config_db_centreon}->{password}, - force => 2, - logger => $self->{logger} - ); - - $self->{class_object_centreon} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centreon}); - $self->{http} = gorgone::class::http::http->new(logger => $self->{logger}); - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-anomalydetection', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'CENTREONADREADY', - data => {} - }); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/anomalydetection/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/anomalydetection/hooks.pm deleted file mode 100644 index 479287383c..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/anomalydetection/hooks.pm +++ /dev/null @@ -1,158 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::anomalydetection::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::centreon::anomalydetection::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'anomalydetection'; -use constant EVENTS => [ - { event => 'CENTREONADREADY' } -]; - -my $config_core; -my $config; -my ($config_db_centreon, $config_db_centstorage); -my $process = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centreon = $options{config_db_centreon}; - $config_db_centstorage = $options{config_db_centstorage}; - $config->{resync_time} = defined($config->{resync_time}) && $config->{resync_time} =~ /(\d+)/ ? $1 : 600; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'CENTREONADREADY') { - $process->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$process->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-anomalydetection: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-anomalydetection', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($process->{running}) && $process->{running} == 1) { - $options{logger}->writeLogDebug("[anomalydetection] Send TERM signal $process->{pid}"); - CORE::kill('TERM', $process->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($process->{running} == 1) { - $options{logger}->writeLogDebug("[anomalydetection] Send KILL signal for pool"); - CORE::kill('KILL', $process->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($process->{pid}) || $process->{pid} != $pid); - - $process = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($process->{running}) && $process->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[anomalydetection] Create module 'anomalydetection' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-anomalydetection'; - my $module = gorgone::modules::centreon::anomalydetection::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - config_db_centreon => $config_db_centreon, - config_db_centstorage => $config_db_centstorage - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[anomalydetection] PID $child_pid (gorgone-anomalydetection)"); - $process = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/class.pm b/centreon-gorgone/gorgone/modules/centreon/audit/class.pm deleted file mode 100644 index b579299e72..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/class.pm +++ /dev/null @@ -1,372 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use gorgone::class::sqlquery; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -my @sampling_modules = ( - 'system::cpu', - 'system::diskio' -); -my @metrics_modules = ( - 'centreon::database', - 'centreon::packages', - 'centreon::pluginpacks', - 'centreon::realtime', - 'centreon::rrd', - 'system::cpu', - 'system::disk', - 'system::diskio', - 'system::load', - 'system::memory', - 'system::os' -); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{audit_tokens} = {}; - $connector->{sampling} = {}; - $connector->{sampling_modules} = {}; - $connector->{metrics_modules} = {}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[audit] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub load_modules { - my ($self, %options) = @_; - - foreach (@sampling_modules) { - my $mod_name = 'gorgone::modules::centreon::audit::sampling::' . $_; - my $ret = gorgone::standard::misc::mymodule_load( - logger => $self->{logger}, - module => $mod_name, - error_msg => "Cannot load sampling module '$_'" - ); - next if ($ret == 1); - $self->{sampling_modules}->{$_} = $mod_name->can('sample'); - } - - foreach (@metrics_modules) { - my $mod_name = 'gorgone::modules::centreon::audit::metrics::' . $_; - my $ret = gorgone::standard::misc::mymodule_load( - logger => $self->{logger}, - module => $mod_name, - error_msg => "Cannot load metrics module '$_'" - ); - next if ($ret == 1); - $self->{metrics_modules}->{$_} = $mod_name->can('metrics'); - } -} - -sub action_centreonauditnode { - my ($self, %options) = @_; - - $self->{logger}->writeLogDebug('[audit] action node starting'); - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action node starting' }); - - my $metrics = {}; - foreach my $name (keys %{$self->{metrics_modules}}) { - my $result = $self->{metrics_modules}->{$name}->( - os => $self->{os}, - centreon_sqlquery => $self->{centreon_sqlquery}, - centstorage_sqlquery => $self->{centstorage_sqlquery}, - sampling => $self->{sampling}, - params => $options{data}->{content}, - logger => $self->{logger} - ); - next if (!defined($result)); - $metrics->{$name} = $result; - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { - message => 'action node finished', - metrics => $metrics - } - ); - $self->{logger}->writeLogDebug('[audit] action node finished'); -} - -sub action_centreonauditnodelistener { - my ($self, %options) = @_; - - return 0 if (!defined($options{token}) || $options{token} !~ /^audit-(.*?)-(.*)$/); - my ($audit_token, $audit_node) = ($1, $2); - - return 0 if (!defined($self->{audit_tokens}->{ $audit_token }) || !defined($self->{audit_tokens}->{ $audit_token }->{nodes}->{ $audit_node })); - - if ($options{data}->{code} == GORGONE_ACTION_FINISH_KO) { - $self->{logger}->writeLogError("[audit] audit node listener - node '" . $audit_node . "' error"); - $self->{audit_tokens}->{ $audit_token }->{nodes}->{ $audit_node }->{status_code} = 2; - $self->{audit_tokens}->{ $audit_token }->{nodes}->{ $audit_node }->{status_message} = $options{data}->{data}->{message}; - } elsif ($options{data}->{code} == GORGONE_ACTION_FINISH_OK) { - $self->{logger}->writeLogDebug("[audit] audit node listener - node '" . $audit_node . "' ok"); - $self->{audit_tokens}->{ $audit_token }->{nodes}->{ $audit_node }->{status_code} = 0; - $self->{audit_tokens}->{ $audit_token }->{nodes}->{ $audit_node }->{status_message} = 'ok'; - $self->{audit_tokens}->{ $audit_token }->{nodes}->{ $audit_node }->{metrics} = $options{data}->{data}->{metrics}; - } else { - return 0; - } - $self->{audit_tokens}->{ $audit_token }->{done_nodes}++; - - if ($self->{audit_tokens}->{ $audit_token }->{done_nodes} == $self->{audit_tokens}->{ $audit_token }->{count_nodes}) { - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $audit_token, - instant => 1, - data => { - message => 'finished', - audit => $self->{audit_tokens}->{ $audit_token } - } - ); - delete $self->{audit_tokens}->{ $audit_token }; - return 1; - } - - my $progress = $self->{audit_tokens}->{ $audit_token }->{done_nodes} * 100 / $self->{audit_tokens}->{ $audit_token }->{count_nodes}; - my $div = int(int($progress) / 5); - if (int($progress) % 3 == 0) { - $self->send_log( - code => GORGONE_MODULE_CENTREON_AUDIT_PROGRESS, - token => $audit_token, - instant => 1, - data => { - message => 'current progress', - complete => sprintf('%.2f', $progress) - } - ); - } - - return 1; -} - -sub action_centreonauditschedule { - my ($self, %options) = @_; - - $self->{logger}->writeLogDebug('[audit] starting schedule action'); - $options{token} = $self->generate_token() if (!defined($options{token})); - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action schedule proceed' }); - - my $params = {}; - - my ($status, $datas) = $self->{centstorage_sqlquery}->custom_execute( - request => 'SELECT RRDdatabase_path, RRDdatabase_status_path FROM config', - mode => 2 - ); - if ($status == -1) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot find centstorage config' }); - $self->{logger}->writeLogError('[audit] Cannot find centstorage configuration'); - return 1; - } - $params->{rrd_metrics_path} = $datas->[0]->[0]; - $params->{rrd_status_path} = $datas->[0]->[1]; - - ($status, $datas) = $self->{centreon_sqlquery}->custom_execute( - request => "SELECT id, name FROM nagios_server WHERE ns_activate = '1'", - mode => 2 - ); - if ($status == -1) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot find nodes configuration' }); - $self->{logger}->writeLogError('[audit] Cannot find nodes configuration'); - return 1; - } - - $self->{audit_tokens}->{ $options{token} } = { - started => time(), - count_nodes => 0, - done_nodes => 0, - nodes => {} - }; - foreach (@$datas) { - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgone-audit', - event => 'CENTREONAUDITNODELISTENER', - token => 'audit-' . $options{token} . '-' . $_->[0], - timeout => 300 - } - ] - }); - $self->send_internal_action({ - action => 'CENTREONAUDITNODE', - target => $_->[0], - token => 'audit-' . $options{token} . '-' . $_->[0], - data => { - instant => 1, - content => $params - } - }); - - $self->{audit_tokens}->{ $options{token} }->{nodes}->{$_->[0]} = { - name => $_->[1], - status_code => 1, - status_message => 'wip' - }; - $self->{audit_tokens}->{ $options{token} }->{count_nodes}++; - } - - return 0; -} - -sub sampling { - my ($self, %options) = @_; - - return if (defined($self->{sampling_last}) && (time() - $self->{sampling_last}) < 60); - $self->{logger}->writeLogDebug('[audit] sampling starting'); - foreach (keys %{$self->{sampling_modules}}) { - $self->{sampling_modules}->{$_}->(sampling => $self->{sampling}); - } - - $self->{sampling_last} = time(); -} - -sub get_system { - my ($self, %options) = @_; - - $self->{os} = 'unknown'; - - my ($rv, $message, $content) = gorgone::standard::misc::slurp(file => '/etc/os-release'); - if ($rv && $content =~ /^ID="(.*?)"/mi) { - $self->{os} = $1; - return ; - } - - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => 'lsb_release -a', - timeout => 5, - wait_exit => 1, - redirect_stderr => 1, - logger => $options{logger} - ); - if ($error == 0 && $stdout =~ /^Description:\s+(.*)$/mi) { - $self->{os} = $1; - } -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[audit] $$ has quit"); - exit(0); - } - - $connector->sampling(); -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-audit', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'CENTREONAUDITREADY', - data => {} - }); - - if (defined($self->{config_db_centreon})) { - $self->{db_centreon} = gorgone::class::db->new( - dsn => $self->{config_db_centreon}->{dsn}, - user => $self->{config_db_centreon}->{username}, - password => $self->{config_db_centreon}->{password}, - force => 0, - logger => $self->{logger} - ); - $self->{centreon_sqlquery} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centreon}); - } - - if (defined($self->{config_db_centstorage})) { - $self->{db_centstorage} = gorgone::class::db->new( - dsn => $self->{config_db_centstorage}->{dsn}, - user => $self->{config_db_centstorage}->{username}, - password => $self->{config_db_centstorage}->{password}, - force => 0, - logger => $self->{logger} - ); - $self->{centstorage_sqlquery} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centstorage}); - } - - $self->load_modules(); - $self->get_system(); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/audit/hooks.pm deleted file mode 100644 index b95de9dedd..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/hooks.pm +++ /dev/null @@ -1,161 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::centreon::audit::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'audit'; -use constant EVENTS => [ - { event => 'CENTREONAUDITSCHEDULE', uri => '/schedule', method => 'POST' }, - { event => 'CENTREONAUDITNODE', uri => '/node', method => 'POST' }, - { event => 'CENTREONAUDITNODELISTENER' }, - { event => 'CENTREONAUDITREADY' } -]; - -my $config_core; -my $config; -my $audit = {}; -my $stop = 0; -my ($config_db_centreon, $config_db_centstorage); - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centstorage = $options{config_db_centstorage}; - $config_db_centreon = $options{config_db_centreon}; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'CENTREONAUDITREADY') { - $audit->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$audit->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-audit: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-audit', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($audit->{running}) && $audit->{running} == 1) { - $options{logger}->writeLogDebug("[audit] Send TERM signal $audit->{pid}"); - CORE::kill('TERM', $audit->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($audit->{running} == 1) { - $options{logger}->writeLogDebug("[audit] Send KILL signal for child"); - CORE::kill('KILL', $audit->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($audit->{pid}) || $audit->{pid} != $pid); - - $audit = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($audit->{running}) && $audit->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[audit] Create module 'audit' process"); - - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-audit'; - my $module = gorgone::modules::centreon::audit::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - config_db_centreon => $config_db_centreon, - config_db_centstorage => $config_db_centstorage - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[audit] PID $child_pid (gorgone-audit)"); - $audit = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/database.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/database.pm deleted file mode 100644 index de32ac931a..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/database.pm +++ /dev/null @@ -1,110 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::centreon::database; - -use warnings; -use strict; - -sub metrics { - my (%options) = @_; - - return undef if (!defined($options{centstorage_sqlquery})); - - my $metrics = { - status_code => 0, - status_message => 'ok', - space_free_bytes => 0, - space_used_bytes => 0, - databases => {} - }; - - my ($status, $datas) = $options{centstorage_sqlquery}->custom_execute( - request => q{show variables like 'innodb_file_per_table'}, - mode => 2 - ); - if ($status == -1 || !defined($datas->[0])) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot get innodb_file_per_table configuration'; - return $metrics; - } - my $innodb_per_table = 0; - $innodb_per_table = 1 if ($datas->[0]->[1] =~ /on/i); - - ($status, $datas) = $options{centstorage_sqlquery}->custom_execute( - request => q{SELECT table_schema, table_name, engine, data_free, data_length+index_length as data_used, (DATA_FREE / (DATA_LENGTH+INDEX_LENGTH)) as TAUX_FRAG FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND engine IN ('InnoDB', 'MyISAM')}, - mode => 2 - ); - if ($status == -1 || !defined($datas->[0])) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot get schema information'; - return $metrics; - } - - my $innodb_ibdata_done = 0; - foreach my $row (@$datas) { - if (!defined($metrics->{databases}->{ $row->[0] })) { - $metrics->{databases}->{ $row->[0] } = { - space_free_bytes => 0, - space_used_bytes => 0, - tables => {} - }; - } - - $metrics->{databases}->{ $row->[0] }->{tables}->{ $row->[1] } = {}; - - # For a table located in the shared tablespace, this is the free space of the shared tablespace. - if ($row->[2] !~ /innodb/i || $innodb_per_table == 1) { - $metrics->{space_free_bytes} += $row->[3]; - $metrics->{databases}->{ $row->[0] }->{space_free_bytes} += $row->[3]; - $metrics->{databases}->{ $row->[0] }->{tables}->{ $row->[1] }->{space_free_bytes} = $row->[3]; - $metrics->{databases}->{ $row->[0] }->{tables}->{ $row->[1] }->{frag} = $row->[5]; - } elsif ($innodb_ibdata_done == 0) { - $metrics->{space_free_bytes} += $row->[3]; - $innodb_ibdata_done = 1; - } - $metrics->{space_used_bytes} += $row->[4]; - $metrics->{databases}->{ $row->[0] }->{space_used_bytes} += $row->[4]; - $metrics->{databases}->{ $row->[0] }->{tables}->{ $row->[1] }->{space_used_bytes} = $row->[4]; - $metrics->{databases}->{ $row->[0] }->{tables}->{ $row->[1] }->{engine} = $row->[2]; - } - - my $rm_table_size = 10 * 1024 * 1024; - - $metrics->{space_free_human} = join('', gorgone::standard::misc::scale(value => $metrics->{space_free_bytes}, format => '%.2f')); - $metrics->{space_used_human} = join('', gorgone::standard::misc::scale(value => $metrics->{space_used_bytes}, format => '%.2f')); - foreach my $db (keys %{$metrics->{databases}}) { - $metrics->{databases}->{$db}->{space_used_human} = join('', gorgone::standard::misc::scale(value => $metrics->{databases}->{$db}->{space_used_bytes}, format => '%.2f')); - $metrics->{databases}->{$db}->{space_free_human} = join('', gorgone::standard::misc::scale(value => $metrics->{databases}->{$db}->{space_free_bytes}, format => '%.2f')); - foreach my $table (keys %{$metrics->{databases}->{$db}->{tables}}) { - if ($metrics->{databases}->{$db}->{tables}->{$table}->{space_used_bytes} < $rm_table_size) { - delete $metrics->{databases}->{$db}->{tables}->{$table}; - next; - } - $metrics->{databases}->{$db}->{tables}->{$table}->{space_free_human} = join('', gorgone::standard::misc::scale(value => $metrics->{databases}->{$db}->{tables}->{$table}->{space_free_bytes}, format => '%.2f')) - if (defined($metrics->{databases}->{$db}->{tables}->{$table}->{space_free_bytes})); - $metrics->{databases}->{$db}->{tables}->{$table}->{space_used_human} = join('', gorgone::standard::misc::scale(value => $metrics->{databases}->{$db}->{tables}->{$table}->{space_used_bytes}, format => '%.2f')); - } - } - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/packages.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/packages.pm deleted file mode 100644 index a8bacc1939..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/packages.pm +++ /dev/null @@ -1,94 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::centreon::packages; - -use warnings; -use strict; -use gorgone::standard::misc; - -sub dpkg_list { - my (%options) = @_; - - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => "dpkg-query -W -f='\${binary:Package}\\t\${Version}\\n' 'centreon*'", - timeout => 30, - wait_exit => 1, - redirect_stderr => 1, - logger => $options{logger} - ); - if ($error != 0 || $return_code != 0) { - $options{metrics}->{status_code} = 1; - $options{metrics}->{status_message} = $stdout; - return ; - } - - foreach (split(/\n/, $stdout)) { - my ($name, $version) = split(/\t/); - push @{$options{metrics}->{list}}, [$name, $version]; - } -} - -sub rpm_list { - my (%options) = @_; - - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => 'rpm -qa --queryformat "%{NAME}\t%{RPMTAG_VERSION}-%{RPMTAG_RELEASE}\n" | grep centreon', - timeout => 30, - wait_exit => 1, - redirect_stderr => 1, - logger => $options{logger} - ); - if ($error != 0 || $return_code != 0) { - $options{metrics}->{status_code} = 1; - $options{metrics}->{status_message} = $stdout; - return ; - } - - foreach (split(/\n/, $stdout)) { - my ($name, $version) = split(/\t/); - push @{$options{metrics}->{list}}, [$name, $version]; - } -} - -sub metrics { - my (%options) = @_; - - my $metrics = { - status_code => 0, - status_message => 'ok', - list => [] - }; - - if ($options{os} =~ /Debian|Ubuntu/i) { - dpkg_list(metrics => $metrics); - } elsif ($options{os} =~ /CentOS|Redhat|rhel|almalinux|rocky/i) { - rpm_list(metrics => $metrics); - } elsif ($options{os} eq 'ol' || $options{os} =~ /Oracle Linux/i) { - rpm_list(metrics => $metrics); - } else { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'unsupported os'; - } - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/pluginpacks.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/pluginpacks.pm deleted file mode 100644 index fa790e2022..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/pluginpacks.pm +++ /dev/null @@ -1,53 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::centreon::pluginpacks; - -use warnings; -use strict; - -sub metrics { - my (%options) = @_; - - return undef if (!defined($options{centreon_sqlquery})); - - my $metrics = { - status_code => 0, - status_message => 'ok', - installed => [] - }; - - my ($status, $datas) = $options{centreon_sqlquery}->custom_execute( - request => "SELECT slug, version FROM mod_ppm_pluginpack", - mode => 2 - ); - if ($status == -1) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot get plugin-packs installed'; - return $metrics; - } - foreach (@$datas) { - push @{$metrics->{installed}}, { slug => $_->[0], version => $_->[1] }; - } - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/realtime.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/realtime.pm deleted file mode 100644 index 41567275d2..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/realtime.pm +++ /dev/null @@ -1,99 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::centreon::realtime; - -use warnings; -use strict; - -sub metrics { - my (%options) = @_; - - return undef if (!defined($options{centstorage_sqlquery})); - - my $metrics = { - status_code => 0, - status_message => 'ok', - hosts_count => 0, - services_count => 0, - hostgroups_count => 0, - servicegroups_count => 0, - acl_count => 0 - }; - - my ($status, $datas) = $options{centstorage_sqlquery}->custom_execute( - request => "SELECT count(*) FROM instances, hosts, services WHERE instances.running = '1' AND hosts.instance_id = instances.instance_id AND hosts.enabled = '1' AND services.host_id = hosts.host_id AND services.enabled = '1'", - mode => 2 - ); - if ($status == -1 || !defined($datas->[0])) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot get number of services'; - return $metrics; - } - $metrics->{services_count} = $datas->[0]->[0]; - - ($status, $datas) = $options{centstorage_sqlquery}->custom_execute( - request => "SELECT count(*) FROM instances, hosts WHERE instances.running = '1' AND hosts.instance_id = instances.instance_id AND hosts.enabled = '1'", - mode => 2 - ); - if ($status == -1 || !defined($datas->[0])) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot get number of hosts'; - return $metrics; - } - $metrics->{hosts_count} = $datas->[0]->[0]; - - ($status, $datas) = $options{centstorage_sqlquery}->custom_execute( - request => 'SELECT count(*) FROM hostgroups', - mode => 2 - ); - if ($status == -1 || !defined($datas->[0])) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot get number of hostgroups'; - return $metrics; - } - $metrics->{hostgroups_count} = $datas->[0]->[0]; - - ($status, $datas) = $options{centstorage_sqlquery}->custom_execute( - request => 'SELECT count(*) FROM servicegroups', - mode => 2 - ); - if ($status == -1 || !defined($datas->[0])) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot get number of servicegroups'; - return $metrics; - } - $metrics->{servicegroups_count} = $datas->[0]->[0]; - - ($status, $datas) = $options{centstorage_sqlquery}->custom_execute( - request => 'SELECT count(*) FROM centreon_acl', - mode => 2 - ); - if ($status == -1 || !defined($datas->[0])) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot get number of acl'; - return $metrics; - } - $metrics->{acl_count} = $datas->[0]->[0]; - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/rrd.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/rrd.pm deleted file mode 100644 index c2c961b190..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/centreon/rrd.pm +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::centreon::rrd; - -use warnings; -use strict; -use gorgone::standard::misc; - -sub metrics { - my (%options) = @_; - - return undef if (!defined($options{params}->{rrd_metrics_path})); - return undef if (! -d $options{params}->{rrd_metrics_path}); - - my $metrics = { - status_code => 0, - status_message => 'ok', - rrd_metrics_count => 0, - rrd_status_count => 0, - rrd_metrics_bytes => 0, - rrd_status_bytes => 0, - rrd_metrics_outdated => 0, - rrd_status_outdated => 0 - }; - - my $outdated_time = time() - (180 * 86400); - my $dh; - foreach my $type (('metrics', 'status')) { - if (!opendir($dh, $options{params}->{'rrd_' . $type . '_path'})) { - $metrics->{status_code} = 1; - $metrics->{status_message} = "Could not open directoy for reading: $!"; - next; - } - while (my $file = readdir($dh)) { - next if ($file !~ /\.rrd/); - $metrics->{'rrd_' . $type . '_count'}++; - my @attrs = stat($options{params}->{'rrd_' . $type . '_path'} . '/' . $file); - $metrics->{'rrd_' . $type . '_bytes'} += $attrs[7] if (defined($attrs[7])); - $metrics->{'rrd_' . $type . '_outdated'}++ if ($attrs[9] < $outdated_time); - } - closedir($dh); - } - - $metrics->{rrd_metrics_human} = join('', gorgone::standard::misc::scale(value => $metrics->{rrd_metrics_bytes}, format => '%.2f')); - $metrics->{rrd_status_human} = join('', gorgone::standard::misc::scale(value => $metrics->{rrd_status_bytes}, format => '%.2f')); - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/cpu.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/cpu.pm deleted file mode 100644 index ea8fad5bc0..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/cpu.pm +++ /dev/null @@ -1,62 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::system::cpu; - -use warnings; -use strict; - -sub metrics { - my (%options) = @_; - - my $metrics = { - status_code => 0, - status_message => 'ok', - num_cpu => 0 - }; - if ($options{sampling}->{cpu}->{status_code} != 0) { - $metrics->{status_code} = $options{sampling}->{cpu}->{status_code}; - $metrics->{status_message} = $options{sampling}->{cpu}->{status_message}; - return $metrics; - } - - $metrics->{num_cpu} = $options{sampling}->{cpu}->{num_cpu}; - foreach (([1, '1min'], [4, '5min'], [14, '15min'], [59, '60min'])) { - $metrics->{ 'avg_used_' . $_->[1] } = 'n/a'; - $metrics->{ 'avg_iowait_' . $_->[1] } = 'n/a'; - next if (!defined($options{sampling}->{cpu}->{values}->[ $_->[0] ])); - $metrics->{ 'avg_used_' . $_->[1] } = sprintf( - '%.2f', - 100 - ( - 100 * ($options{sampling}->{cpu}->{values}->[0]->[1] - $options{sampling}->{cpu}->{values}->[ $_->[0] ]->[1]) - / ($options{sampling}->{cpu}->{values}->[0]->[0] - $options{sampling}->{cpu}->{values}->[ $_->[0] ]->[0]) - ) - ); - $metrics->{ 'avg_iowait_' . $_->[1] } = sprintf( - '%.2f', - 100 * ($options{sampling}->{cpu}->{values}->[0]->[2] - $options{sampling}->{cpu}->{values}->[ $_->[0] ]->[2]) - / ($options{sampling}->{cpu}->{values}->[0]->[0] - $options{sampling}->{cpu}->{values}->[ $_->[0] ]->[0]) - ); - } - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/disk.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/disk.pm deleted file mode 100644 index ad9a59433d..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/disk.pm +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::system::disk; - -use warnings; -use strict; -use gorgone::standard::misc; - -sub metrics { - my (%options) = @_; - - my $metrics = { - status_code => 0, - status_message => 'ok', - partitions => {} - }; - - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => 'df -P -k -T', - timeout => 5, - wait_exit => 1, - redirect_stderr => 1, - logger => $options{logger} - ); - if ($error != 0) { - $metrics->{status_code} = 1; - $metrics->{status_message} = $stdout; - return $metrics; - } - - foreach my $line (split(/\n/, $stdout)) { - next if ($line !~ /^(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(.*)/); - $metrics->{partitions}->{$7} = { - mount => $7, - filesystem => $1, - type => $2, - space_size_bytes => $3 * 1024, - space_size_human => join('', gorgone::standard::misc::scale(value => $3 * 1024, format => '%.2f')), - space_used_bytes => $4 * 1024, - space_used_human => join('', gorgone::standard::misc::scale(value => $4 * 1024, format => '%.2f')), - space_free_bytes => $5 * 1024, - space_free_human => join('', gorgone::standard::misc::scale(value => $5 * 1024, format => '%.2f')), - inodes_used_percent => $6 - }; - } - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/diskio.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/diskio.pm deleted file mode 100644 index 387d41dea6..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/diskio.pm +++ /dev/null @@ -1,75 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::system::diskio; - -use warnings; -use strict; - -sub metrics { - my (%options) = @_; - - my $metrics = { - status_code => 0, - status_message => 'ok', - partitions => {} - }; - if ($options{sampling}->{diskio}->{status_code} != 0) { - $metrics->{status_code} = $options{sampling}->{diskio}->{status_code}; - $metrics->{status_message} = $options{sampling}->{diskio}->{status_message}; - return $metrics; - } - - foreach my $partname (keys %{$options{sampling}->{diskio}->{partitions}}) { - $metrics->{partitions}->{$partname} = {}; - foreach (([1, '1min'], [4, '5min'], [14, '15min'], [59, '60min'])) { - $metrics->{partitions}->{$partname}->{ 'read_iops_' . $_->[1] . '_bytes' } = 'n/a'; - $metrics->{partitions}->{$partname}->{ 'write_iops_' . $_->[1] . '_bytes' } = 'n/a'; - $metrics->{partitions}->{$partname}->{ 'read_time_' . $_->[1] . '_ms' } = 'n/a'; - $metrics->{partitions}->{$partname}->{ 'write_time_' . $_->[1] . '_ms' } = 'n/a'; - next if (!defined($options{sampling}->{diskio}->{partitions}->{$partname}->[ $_->[0] ])); - - $metrics->{partitions}->{$partname}->{ 'read_iops_' . $_->[1] . '_bytes' } = sprintf( - '%.2f', - ($options{sampling}->{diskio}->{partitions}->{$partname}->[0]->[1] - $options{sampling}->{diskio}->{partitions}->{$partname}->[ $_->[0] ]->[1]) - / ($options{sampling}->{diskio}->{partitions}->{$partname}->[0]->[0] - $options{sampling}->{diskio}->{partitions}->{$partname}->[ $_->[0] ]->[0]) - ); - $metrics->{partitions}->{$partname}->{ 'read_iops_' . $_->[1] . '_human' } = join('', gorgone::standard::misc::scale(value => $metrics->{partitions}->{$partname}->{ 'read_iops_' . $_->[1] . '_bytes' }, format => '%.2f')); - - $metrics->{partitions}->{$partname}->{ 'write_iops_' . $_->[1] . '_bytes' } = sprintf( - '%.2f', - ($options{sampling}->{diskio}->{partitions}->{$partname}->[0]->[2] - $options{sampling}->{diskio}->{partitions}->{$partname}->[ $_->[0] ]->[2]) - / ($options{sampling}->{diskio}->{partitions}->{$partname}->[0]->[0] - $options{sampling}->{diskio}->{partitions}->{$partname}->[ $_->[0] ]->[0]) - ); - $metrics->{partitions}->{$partname}->{ 'write_iops_' . $_->[1] . '_human' } = join('', gorgone::standard::misc::scale(value => $metrics->{partitions}->{$partname}->{ 'write_iops_' . $_->[1] . '_bytes' }, format => '%.2f')); - - $metrics->{partitions}->{$partname}->{ 'read_time_' . $_->[1] . '_ms' } = sprintf( - '%s', ($options{sampling}->{diskio}->{partitions}->{$partname}->[0]->[3] - $options{sampling}->{diskio}->{partitions}->{$partname}->[ $_->[0] ]->[3]) - ); - $metrics->{partitions}->{$partname}->{ 'write_time_' . $_->[1] . '_ms' } = sprintf( - '%s', ($options{sampling}->{diskio}->{partitions}->{$partname}->[0]->[4] - $options{sampling}->{diskio}->{partitions}->{$partname}->[ $_->[0] ]->[4]) - ); - } - } - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/load.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/load.pm deleted file mode 100644 index eb4dba4a5b..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/load.pm +++ /dev/null @@ -1,53 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::system::load; - -use warnings; -use strict; -use gorgone::standard::misc; - -sub metrics { - my (%options) = @_; - - my $metrics = { - status_code => 0, - status_message => 'ok' - }; - my ($ret, $message, $buffer) = gorgone::standard::misc::slurp(file => '/proc/loadavg'); - if ($ret == 0) { - $metrics->{status_code} = 1; - $metrics->{status_message} = $message; - return $metrics; - } - - if ($buffer !~ /^([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)/mi) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot find load information'; - return $metrics; - } - - $metrics->{load1m} = $1; - $metrics->{load5m} = $2; - $metrics->{load15m} = $3; - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/memory.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/memory.pm deleted file mode 100644 index 98f5a734ea..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/memory.pm +++ /dev/null @@ -1,70 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::system::memory; - -use warnings; -use strict; -use gorgone::standard::misc; - -sub metrics { - my (%options) = @_; - - my $metrics = { - status_code => 0, - status_message => 'ok', - ram_total_bytes => 0, - ram_available_bytes => 0, - swap_total_bytes => 0, - swap_free_bytes => 0 - }; - my ($ret, $message, $buffer) = gorgone::standard::misc::slurp(file => '/proc/meminfo'); - if ($ret == 0) { - $metrics->{status_code} = 1; - $metrics->{status_message} = $message; - return $metrics; - } - - if ($buffer !~ /^MemTotal:\s+(\d+)/mi) { - $metrics->{status_code} = 1; - $metrics->{status_message} = 'cannot find memory information'; - return $metrics; - } - - $metrics->{ram_total_bytes} = $1 * 1024; - $metrics->{ram_total_human} = join('', gorgone::standard::misc::scale(value => $metrics->{ram_total_bytes}, format => '%.2f')); - - if ($buffer =~ /^MemAvailable:\s+(\d+)/mi) { - $metrics->{ram_available_bytes} = $1 * 1024; - $metrics->{ram_available_human} = join('', gorgone::standard::misc::scale(value => $metrics->{ram_available_bytes}, format => '%.2f')); - } - if ($buffer =~ /^SwapTotal:\s+(\d+)/mi) { - $metrics->{swap_total_bytes} = $1 * 1024; - $metrics->{swap_total_human} = join('', gorgone::standard::misc::scale(value => $metrics->{swap_total_bytes}, format => '%.2f')); - } - if ($buffer =~ /^SwapFree:\s+(\d+)/mi) { - $metrics->{swap_free_bytes} = $1 * 1024; - $metrics->{swap_free_human} = join('', gorgone::standard::misc::scale(value => $metrics->{swap_free_bytes}, format => '%.2f')); - } - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/os.pm b/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/os.pm deleted file mode 100644 index 1bd0d4a5b1..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/metrics/system/os.pm +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::metrics::system::os; - -use warnings; -use strict; - -sub metrics { - my (%options) = @_; - - my $metrics = { - kernel => { - status_code => 0, - status_message => 'ok', - value => 'n/a' - } - }; - - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => 'uname -a', - timeout => 5, - wait_exit => 1, - redirect_stderr => 1, - logger => $options{logger} - ); - if ($error != 0) { - $metrics->{kernel}->{status_code} = 1; - $metrics->{kernel}->{status_message} = $stdout; - } else { - $metrics->{kernel}->{value} = $stdout; - } - - $metrics->{os}->{value} = $options{os}; - - return $metrics; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/sampling/system/cpu.pm b/centreon-gorgone/gorgone/modules/centreon/audit/sampling/system/cpu.pm deleted file mode 100644 index 3dd99e412b..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/sampling/system/cpu.pm +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::sampling::system::cpu; - -use warnings; -use strict; -use gorgone::standard::misc; - -sub sample { - my (%options) = @_; - - if (!defined($options{sampling}->{cpu})) { - $options{sampling}->{cpu} = { - status_code => 0, - status_message => 'ok', - round => 0, - values => [] - }; - } - - $options{sampling}->{cpu}->{round}++; - my ($ret, $message, $buffer) = gorgone::standard::misc::slurp(file => '/proc/stat'); - if ($ret == 0) { - $options{sampling}->{cpu}->{status_code} = 1; - $options{sampling}->{cpu}->{status_message} = $message; - return ; - } - - if ($buffer !~ /^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) { - $options{sampling}->{cpu}->{status_code} = 1; - $options{sampling}->{cpu}->{status_message} = 'cannot find cpu information'; - return ; - } - - $options{sampling}->{cpu}->{num_cpu} = 0; - while ($buffer =~ /^cpu(\d+)/mg) { - $options{sampling}->{cpu}->{num_cpu}++; - } - - unshift @{$options{sampling}->{cpu}->{values}}, [ - $1 + $2 + $3 + $4 + $5 + $6 + $7, - $4, - $5 - ]; - if (scalar(@{$options{sampling}->{cpu}->{values}}) > 60) { - pop @{$options{sampling}->{cpu}->{values}}; - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/audit/sampling/system/diskio.pm b/centreon-gorgone/gorgone/modules/centreon/audit/sampling/system/diskio.pm deleted file mode 100644 index 7ca7dac342..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/audit/sampling/system/diskio.pm +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::audit::sampling::system::diskio; - -use warnings; -use strict; -use gorgone::standard::misc; - -sub sample { - my (%options) = @_; - - if (!defined($options{sampling}->{diskio})) { - $options{sampling}->{diskio} = { - status_code => 0, - status_message => 'ok', - partitions => {} - }; - } - - my $time = time(); - my ($ret, $message, $buffer) = gorgone::standard::misc::slurp(file => '/proc/diskstats'); - if ($ret == 0) { - $options{sampling}->{diskio}->{status_code} = 1; - $options{sampling}->{diskio}->{status_message} = $message; - return ; - } - - while ($buffer =~ /^\s*\S+\s+\S+\s+(\S+)\s+\d+\s+\d+\s+(\d+)\s+(\d+)\s+\d+\s+\d+\s+(\d+)\s+(\d+)\s+\d+\s+\d+\s+(\d+)/mg) { - my ($partition_name, $read_sector, $write_sector, $read_ms, $write_ms) = ($1, $2, $4, $3, $5); - next if ($read_sector == 0 && $write_sector == 0); - if (!defined($options{sampling}->{diskio}->{partitions}->{$partition_name})) { - $options{sampling}->{diskio}->{partitions}->{$partition_name} = []; - } - unshift @{$options{sampling}->{diskio}->{partitions}->{$partition_name}}, [ - $time, - $read_sector, $write_sector, - $read_ms, $write_ms - ]; - if (scalar(@{$options{sampling}->{diskio}->{partitions}->{$partition_name}}) > 60) { - pop @{$options{sampling}->{diskio}->{partitions}->{$partition_name}}; - } - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/autodiscovery/class.pm b/centreon-gorgone/gorgone/modules/centreon/autodiscovery/class.pm deleted file mode 100644 index 26b7a5585c..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/autodiscovery/class.pm +++ /dev/null @@ -1,1205 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::autodiscovery::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::modules::centreon::autodiscovery::services::discovery; -use gorgone::class::tpapi::clapi; -use gorgone::class::tpapi::centreonv2; -use gorgone::class::sqlquery; -use gorgone::class::frame; -use JSON::XS; -use Time::HiRes; -use POSIX qw(strftime); -use Digest::MD5 qw(md5_hex); -use Try::Tiny; -use EV; - -use constant JOB_SCHEDULED => 0; -use constant JOB_FINISH => 1; -use constant JOB_FAILED => 2; -use constant JOB_RUNNING => 3; -use constant SAVE_RUNNING => 4; -use constant SAVE_FINISH => 5; -use constant SAVE_FAILED => 6; - -use constant CRON_ADDED_NONE => 0; -use constant CRON_ADDED_OK => 1; -use constant CRON_ADDED_KO => 2; -use constant CRON_ADDED_PROGRESS => 3; - -use constant EXECUTION_MODE_IMMEDIATE => 0; -use constant EXECUTION_MODE_CRON => 1; -use constant EXECUTION_MODE_PAUSE => 2; - -use constant MAX_INSERT_BY_QUERY => 100; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{global_timeout} = (defined($options{config}->{global_timeout}) && - $options{config}->{global_timeout} =~ /(\d+)/) ? $1 : 300; - $connector->{check_interval} = (defined($options{config}->{check_interval}) && - $options{config}->{check_interval} =~ /(\d+)/) ? $1 : 15; - $connector->{tpapi_clapi_name} = defined($options{config}->{tpapi_clapi}) && $options{config}->{tpapi_clapi} ne '' ? $options{config}->{tpapi_clapi} : 'clapi'; - $connector->{tpapi_centreonv2_name} = defined($options{config}->{tpapi_centreonv2}) && $options{config}->{tpapi_centreonv2} ne '' ? - $options{config}->{tpapi_centreonv2} : 'centreonv2'; - - $connector->{is_module_installed} = 0; - $connector->{is_module_installed_check_interval} = 60; - $connector->{is_module_installed_last_check} = -1; - - $connector->{hdisco_synced} = 0; - $connector->{hdisco_synced_failed_time} = -1; - $connector->{hdisco_synced_ok_time} = -1; - $connector->{hdisco_jobs_tokens} = {}; - $connector->{hdisco_jobs_ids} = {}; - - $connector->{service_discoveries} = {}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogInfo("[autodiscovery] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -=pod - -******************* -Host Discovery part -******************* - -For cron job, we use discovery token as cron ID. - -=cut - -sub hdisco_is_running_job { - my ($self, %options) = @_; - - if ($options{status} == JOB_RUNNING || - $options{status} == SAVE_RUNNING) { - return 1; - } - - return 0; -} - -sub hdisco_add_cron { - my ($self, %options) = @_; - - if (!defined($options{job}->{execution}->{parameters}->{cron_definition}) || - $options{job}->{execution}->{parameters}->{cron_definition} eq '') { - return (1, "missing 'cron_definition' parameter"); - } - - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgoneautodiscovery', - event => 'HOSTDISCOVERYCRONLISTENER', - token => 'cron-' . $options{discovery_token} - } - ] - }); - - $self->{logger}->writeLogDebug("[autodiscovery] -class- host discovery - add cron for job '" . $options{job}->{job_id} . "'"); - my $definition = { - id => $options{discovery_token}, - timespec => $options{job}->{execution}->{parameters}->{cron_definition}, - action => 'LAUNCHHOSTDISCOVERY', - parameters => { - job_id => $options{job}->{job_id}, - timeout => (defined($options{job}->{timeout}) && $options{job}->{timeout} =~ /(\d+)/) ? $1 : $self->{global_timeout} - } - }; - $self->send_internal_action({ - action => 'ADDCRON', - token => 'cron-' . $options{discovery_token}, - data => { - content => [ $definition ] - } - }); - - return 0; -} - -sub hdisco_addupdate_job { - my ($self, %options) = @_; - my ($status, $message); - - my $update = 0; - my $extra_infos = { cron_added => CRON_ADDED_NONE, listener_added => 0 }; - if (defined($self->{hdisco_jobs_ids}->{ $options{job}->{job_id} })) { - $extra_infos = $self->{hdisco_jobs_ids}->{ $options{job}->{job_id} }->{extra_infos}; - $update = 1; - } else { - $self->{logger}->writeLogDebug("[autodiscovery] -class- host discovery - new job '" . $options{job}->{job_id} . "'"); - # it's running so we have a token - if ($self->hdisco_is_running_job(status => $options{job}->{status})) { - $extra_infos->{listener_added} = 1; - $self->hdisco_add_joblistener( - jobs => [ - { job_id => $options{job}->{job_id}, target => $options{job}->{target}, token => $options{job}->{token} } - ] - ); - } - } - - # cron changed: we remove old definition - # right now: can be immediate or schedule (not both) - if ($update == 1 && - ($self->{hdisco_jobs_ids}->{ $options{job}->{job_id} }->{execution}->{mode} == EXECUTION_MODE_IMMEDIATE || - (defined($self->{hdisco_jobs_ids}->{ $options{job}->{job_id} }->{execution}->{parameters}->{cron_definition}) && - defined($options{job}->{execution}->{parameters}->{cron_definition}) && - $self->{hdisco_jobs_ids}->{ $options{job}->{job_id} }->{execution}->{parameters}->{cron_definition} ne $options{job}->{execution}->{parameters}->{cron_definition} - ) - ) - ) { - $self->hdisco_delete_cron(discovery_token => $options{job}->{token}); - $extra_infos->{cron_added} = CRON_ADDED_NONE; - } - - $self->{hdisco_jobs_ids}->{ $options{job}->{job_id} } = $options{job}; - $self->{hdisco_jobs_ids}->{ $options{job}->{job_id} }->{extra_infos} = $extra_infos; - if (!defined($options{job}->{token})) { - my $discovery_token = 'discovery_' . $options{job}->{job_id} . '_' . $self->generate_token(length => 4); - if ($self->update_job_information( - values => { - token => $discovery_token - }, - where_clause => [ - { id => $options{job}->{job_id} } - ] - ) == -1) { - return (1, 'cannot add discovery token'); - } - - $self->{hdisco_jobs_ids}->{ $options{job}->{job_id} }->{token} = $discovery_token; - $options{job}->{token} = $discovery_token; - } - - if (defined($options{job}->{token})) { - $self->{hdisco_jobs_tokens}->{ $options{job}->{token} } = $options{job}->{job_id}; - } - - if ($self->{hdisco_jobs_ids}->{ $options{job}->{job_id} }->{execution}->{mode} == EXECUTION_MODE_CRON && - ($extra_infos->{cron_added} == CRON_ADDED_NONE || $extra_infos->{cron_added} == CRON_ADDED_KO) - ) { - ($status, $message) = $self->hdisco_add_cron( - job => $options{job}, - discovery_token => $options{job}->{token} - ); - return ($status, $message) if ($status); - $self->{hdisco_jobs_ids}->{ $options{job}->{job_id} }->{extra_infos}->{cron_added} = CRON_ADDED_PROGRESS; - } - - return 0; -} - -sub hdisco_sync { - my ($self, %options) = @_; - - return if ($self->{is_module_installed} == 0); - return if ($self->{hdisco_synced} == 0 && (time() - $self->{hdisco_synced_failed_time}) < 60); - return if ($self->{hdisco_synced} == 1 && (time() - $self->{hdisco_synced_ok_time}) < 600); - - $self->{logger}->writeLogInfo('[autodiscovery] -class- host discovery - sync started'); - my ($status, $results, $message); - - $self->{hdisco_synced} = 0; - ($status, $results) = $self->{tpapi_centreonv2}->get_scheduling_jobs(); - if ($status != 0) { - $self->{hdisco_synced_failed_time} = time(); - $self->{logger}->writeLogError('[autodiscovery] -class- host discovery - cannot get host discovery jobs - ' . $self->{tpapi_centreonv2}->error()); - return ; - } - - my $jobs = {}; - foreach my $job (@{$results->{result}}) { - ($status, $message) = $self->hdisco_addupdate_job(job => $job); - if ($status) { - $self->{logger}->writeLogError('[autodiscovery] -class- host discovery - addupdate job - ' . $message); - } - - $jobs->{ $job->{job_id} } = 1; - } - - foreach my $job_id (keys %{$self->{hdisco_jobs_ids}}) { - next if (defined($jobs->{$job_id})); - - $self->{logger}->writeLogDebug("[autodiscovery] -class- host discovery - delete job '" . $job_id . "'"); - if (defined($self->{hdisco_jobs_ids}->{$job_id}->{token})) { - $self->hdisco_delete_cron(discovery_token => $self->{hdisco_jobs_ids}->{$job_id}->{token}); - delete $self->{hdisco_jobs_tokens}->{ $self->{hdisco_jobs_ids}->{$job_id}->{token} }; - } - delete $self->{hdisco_jobs_ids}->{$job_id}; - } - - $self->{hdisco_synced_ok_time} = time(); - $self->{hdisco_synced} = 1; -} - -sub get_host_job { - my ($self, %options) = @_; - - my ($status, $results) = $self->{tpapi_centreonv2}->get_scheduling_jobs(search => '{"id": ' . $options{job_id} . '}'); - if ($status != 0) { - return (1, "cannot get host discovery job '$options{job_id}' - " . $self->{tpapi_centreonv2}->error()); - } - - my $job; - foreach my $entry (@{$results->{result}}) { - if ($entry->{job_id} == $options{job_id}) { - $job = $entry; - last; - } - } - - return (0, 'ok', $job); -} - -sub hdisco_delete_cron { - my ($self, %options) = @_; - - return if (!defined($self->{hdisco_jobs_tokens}->{ $options{discovery_token} })); - my $job_id = $self->{hdisco_jobs_tokens}->{ $options{discovery_token} }; - return if ( - $self->{hdisco_jobs_ids}->{$job_id}->{extra_infos}->{cron_added} == CRON_ADDED_NONE || - $self->{hdisco_jobs_ids}->{$job_id}->{extra_infos}->{cron_added} == CRON_ADDED_KO - ); - - $self->{logger}->writeLogInfo("[autodiscovery] -class- host discovery - delete job '" . $job_id . "'"); - - $self->send_internal_action({ - action => 'DELETECRON', - token => $options{token}, - data => { - variables => [ $options{discovery_token} ] - } - }); -} - -sub action_addhostdiscoveryjob { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - if (!$self->is_hdisco_synced()) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => 'host discovery synchronization issue' - } - ); - return ; - } - - my $data = $options{frame}->getData(); - - my ($status, $message, $job); - ($status, $message, $job) = $self->get_host_job(job_id => $data->{content}->{job_id}); - if ($status != 0) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - cannot get host discovery job '$data->{content}->{job_id}' - " . $self->{tpapi_centreonv2}->error()); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "cannot get job '$data->{content}->{job_id}'" - } - ); - return 1; - } - - if (!defined($job)) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - cannot get host discovery job '$data->{content}->{job_id}' - " . $self->{tpapi_centreonv2}->error()); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "cannot get job '$data->{content}->{job_id}'" - } - ); - return 1; - } - - $job->{timeout} = $data->{content}->{timeout}; - ($status, $message) = $self->hdisco_addupdate_job(job => $job); - if ($status) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - add job '$data->{content}->{job_id}' - $message"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "add job '$data->{content}->{job_id}' - $message" - } - ); - return 1; - } - - # Launch a immediate job. - if ($self->{hdisco_jobs_ids}->{ $data->{content}->{job_id} }->{execution}->{mode} == EXECUTION_MODE_IMMEDIATE) { - ($status, $message) = $self->launchhostdiscovery( - job_id => $data->{content}->{job_id}, - timeout => $data->{content}->{timeout}, - source => 'immediate' - ); - if ($status) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "launch issue - $message" - } - ); - return 1; - } - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { - message => 'job ' . $data->{content}->{job_id} . ' added' - } - ); - - return 0; -} - -sub launchhostdiscovery { - my ($self, %options) = @_; - - return (1, 'host discovery sync not done') if (!$self->is_hdisco_synced()); - - my $job_id = $options{job_id}; - - if (!defined($job_id) || !defined($self->{hdisco_jobs_ids}->{$job_id})) { - return (1, 'trying to launch discovery for inexistant job'); - } - if ($self->hdisco_is_running_job(status => $self->{hdisco_jobs_ids}->{$job_id}->{status})) { - return (1, 'job is already running'); - } - if ($self->{hdisco_jobs_ids}->{$job_id}->{execution}->{mode} == EXECUTION_MODE_PAUSE && $options{source} eq 'cron') { - return (0, "job '$job_id' is paused"); - } - - $self->{logger}->writeLogInfo("[autodiscovery] -class- host discovery - launching discovery for job '" . $job_id . "'"); - - # Running - if ($self->update_job_information( - values => { - status => JOB_RUNNING, - message => 'Running', - last_execution => strftime("%F %H:%M:%S", localtime), - duration => 0, - discovered_items => 0 - }, - where_clause => [ - { - id => $job_id - } - ] - ) == -1) { - return (1, 'cannot update job status'); - } - $self->{hdisco_jobs_ids}->{$job_id}->{status} = JOB_RUNNING; - my $timeout = (defined($options{timeout}) && $options{timeout} =~ /(\d+)/) ? $1 : $self->{global_timeout}; - - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgoneautodiscovery', - event => 'HOSTDISCOVERYJOBLISTENER', - target => $self->{hdisco_jobs_ids}->{$job_id}->{target}, - token => $self->{hdisco_jobs_ids}->{$job_id}->{token}, - timeout => $timeout + $self->{check_interval} + 15, - log_pace => $self->{check_interval} - } - ] - }); - - # plugins attribute format: - # "plugins": { - # "centreon-plugin-Cloud-Aws-Ec2-Api": 20220727, - # ... - # } - - $self->send_internal_action({ - action => 'COMMAND', - target => $self->{hdisco_jobs_ids}->{$job_id}->{target}, - token => $self->{hdisco_jobs_ids}->{$job_id}->{token}, - data => { - instant => 1, - content => [ - { - command => $self->{hdisco_jobs_ids}->{$job_id}->{command_line}, - timeout => $timeout, - metadata => { - job_id => $job_id, - source => 'autodiscovery-host-job-discovery', - pkg_install => $self->{hdisco_jobs_ids}->{$job_id}->{plugins} - } - } - ] - } - }); - - return (0, "job '$job_id' launched"); -} - -sub action_launchhostdiscovery { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - if (!$self->is_hdisco_synced()) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => 'host discovery synchronization issue' - } - ); - return ; - } - - my $data = $options{frame}->getData(); - - my ($job_id, $timeout, $source); - if (defined($data->{variables}->[0]) && - defined($data->{variables}->[1]) && $data->{variables}->[1] eq 'schedule') { - $job_id = $data->{variables}->[0]; - $source = 'immediate'; - } elsif (defined($data->{content}->{job_id})) { - $job_id = $data->{content}->{job_id}; - $timeout = $data->{content}->{timeout}; - $source = 'cron'; - } - - my ($status, $message, $job); - ($status, $message, $job) = $self->get_host_job(job_id => $job_id); - if ($status != 0) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - cannot get host discovery job '$job_id' - " . $self->{tpapi_centreonv2}->error()); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "cannot get job '$job_id'" - } - ); - return 1; - } - - if (!defined($job)) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - cannot get host discovery job '$job_id' - " . $self->{tpapi_centreonv2}->error()); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "cannot get job '$job_id'" - } - ); - return 1; - } - - ($status, $message) = $self->hdisco_addupdate_job(job => $job); - if ($status) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - add job '$job_id' - $message"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "add job '$job_id' - $message" - } - ); - return 1; - } - - ($status, $message) = $self->launchhostdiscovery( - job_id => $job_id, - timeout => $timeout, - source => $source - ); - if ($status) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - launch discovery job '$job_id' - $message"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - instant => 1, - data => { - message => $message - } - ); - return 1; - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - instant => 1, - data => { - message => $message - } - ); -} - -sub discovery_postcommand_result { - my ($self, %options) = @_; - - my $data = $options{frame}->getData(); - - return 1 if (!defined($data->{data}->{metadata}->{job_id})); - - my $job_id = $data->{data}->{metadata}->{job_id}; - if (!defined($self->{hdisco_jobs_ids}->{$job_id})) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - found result for inexistant job '" . $job_id . "'"); - return 1; - } - - my $exit_code = $data->{data}->{result}->{exit_code}; - my $output = (defined($data->{data}->{result}->{stderr}) && $data->{data}->{result}->{stderr} ne '') ? - $data->{data}->{result}->{stderr} : $data->{data}->{result}->{stdout}; - - if ($exit_code != 0) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - execute discovery postcommand failed job '$job_id'"); - $self->update_job_status( - job_id => $job_id, - status => SAVE_FAILED, - message => $output - ); - return 1; - } - - $self->{logger}->writeLogDebug("[autodiscovery] -class- host discovery - finished discovery postcommand job '$job_id'"); - $self->update_job_status( - job_id => $job_id, - status => SAVE_FINISH, - message => 'Finished' - ); -} - -sub discovery_add_host_result { - my ($self, %options) = @_; - - if ($options{builder}->{num_lines} == MAX_INSERT_BY_QUERY) { - my ($status) = $self->{class_object_centreon}->custom_execute( - request => $options{builder}->{query} . $options{builder}->{values}, - bind_values => $options{builder}->{bind_values} - ); - if ($status == -1) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - failed to insert job '$options{job_id}' results"); - $self->update_job_status( - job_id => $options{job_id}, - status => JOB_FAILED, - message => 'Failed to insert job results' - ); - return 1; - } - $options{builder}->{num_lines} = 0; - $options{builder}->{values} = ''; - $options{builder}->{append} = ''; - $options{builder}->{bind_values} = (); - } - - # Generate uuid based on attributs - my $uuid_char = ''; - foreach (@{$options{uuid_parameters}}) { - $uuid_char .= $options{host}->{$_} if (defined($options{host}->{$_}) && $options{host}->{$_} ne ''); - } - my $ctx = Digest::MD5->new; - $ctx->add($uuid_char); - my $digest = $ctx->hexdigest; - my $uuid = substr($digest, 0, 8) . '-' . substr($digest, 8, 4) . '-' . substr($digest, 12, 4) . '-' . - substr($digest, 16, 4) . '-' . substr($digest, 20, 12); - my $encoded_host = JSON::XS->new->encode($options{host}); - - # Build bulk insert - $options{builder}->{values} .= $options{builder}->{append} . '(?, ?, ?)'; - $options{builder}->{append} = ', '; - push @{$options{builder}->{bind_values}}, $options{job_id}, $encoded_host, $uuid; - $options{builder}->{num_lines}++; - $options{builder}->{total_lines}++; - - return 0; -} - -sub discovery_command_result { - my ($self, %options) = @_; - - my $data = $options{frame}->getData(); - - return 1 if (!defined($data->{data}->{metadata}->{job_id})); - - my $job_id = $data->{data}->{metadata}->{job_id}; - if (!defined($self->{hdisco_jobs_ids}->{$job_id})) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - found result for inexistant job '" . $job_id . "'"); - return 1; - } - - $self->{logger}->writeLogInfo("[autodiscovery] -class- host discovery - found result for job '" . $job_id . "'"); - my $uuid_parameters = $self->{hdisco_jobs_ids}->{$job_id}->{uuid_parameters}; - my $exit_code = $data->{data}->{result}->{exit_code}; - - if ($exit_code != 0) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - execute discovery plugin failed job '$job_id'"); - $self->update_job_status( - job_id => $job_id, - status => JOB_FAILED, - message => (defined($data->{data}->{result}->{stderr}) && $data->{data}->{result}->{stderr} ne '') ? - $data->{data}->{result}->{stderr} : $data->{data}->{result}->{stdout} - ); - return 1; - } - - # Delete previous results - my $query = "DELETE FROM mod_host_disco_host WHERE job_id = ?"; - my ($status) = $self->{class_object_centreon}->custom_execute(request => $query, bind_values => [$job_id]); - if ($status == -1) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - failed to delete previous job '$job_id' results"); - $self->update_job_status( - job_id => $job_id, - status => JOB_FAILED, - message => 'Failed to delete previous job results' - ); - return 1; - } - - # Add new results - my $builder = { - query => "INSERT INTO mod_host_disco_host (job_id, discovery_result, uuid) VALUES ", - num_lines => 0, - total_lines => 0, - values => '', - append => '', - bind_values => [] - }; - my $duration = 0; - - try { - my $json = JSON::XS->new(); - $json->incr_parse($data->{data}->{result}->{stdout}); - while (my $obj = $json->incr_parse()) { - if (ref($obj) eq 'HASH') { - foreach my $host (@{$obj->{results}}) { - my $rv = $self->discovery_add_host_result(host => $host, job_id => $job_id, uuid_parameters => $uuid_parameters, builder => $builder); - return 1 if ($rv); - } - $duration = $obj->{duration}; - } elsif (ref($obj) eq 'ARRAY') { - foreach my $host (@$obj) { - my $rv = $self->discovery_add_host_result(host => $host, job_id => $job_id, uuid_parameters => $uuid_parameters, builder => $builder); - return 1 if ($rv); - } - } - } - } catch { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - failed to decode discovery plugin response job '$job_id'"); - $self->update_job_status( - job_id => $job_id, - status => JOB_FAILED, - message => 'Failed to decode discovery plugin response' - ); - return 1; - }; - - if ($builder->{values} ne '') { - ($status) = $self->{class_object_centreon}->custom_execute(request => $builder->{query} . $builder->{values}, bind_values => $builder->{bind_values}); - if ($status == -1) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - failed to insert job '$job_id' results"); - $self->update_job_status( - job_id => $job_id, - status => JOB_FAILED, - message => 'Failed to insert job results' - ); - return 1; - } - } - - if (defined($self->{hdisco_jobs_ids}->{$job_id}->{post_execution}->{commands}) && - scalar(@{$self->{hdisco_jobs_ids}->{$job_id}->{post_execution}->{commands}}) > 0) { - $self->{logger}->writeLogDebug("[autodiscovery] -class- host discovery - execute post command job '$job_id'"); - my $post_command = $self->{hdisco_jobs_ids}->{$job_id}->{post_execution}->{commands}->[0]; - - $self->send_internal_action({ - action => $post_command->{action}, - token => $self->{hdisco_jobs_ids}->{$job_id}->{token}, - data => { - instant => 1, - content => [ - { - command => $post_command->{command_line} . ' --token=' . $self->{tpapi_centreonv2}->get_token(), - metadata => { - job_id => $job_id, - source => 'autodiscovery-host-job-postcommand' - } - } - ] - } - }); - } - - $self->{logger}->writeLogDebug("[autodiscovery] -class- host discovery - finished discovery command job '$job_id'"); - $self->update_job_status( - job_id => $job_id, - status => JOB_FINISH, - message => 'Finished', - duration => $duration, - discovered_items => $builder->{total_lines} - ); - - return 0; -} - -sub action_deletehostdiscoveryjob { - my ($self, %options) = @_; - - # delete is call when it's in pause (execution_mode 2). - # in fact, we do a curl to sync. If don't exist in database, we remove it. otherwise we do nothing - $options{token} = $self->generate_token() if (!defined($options{token})); - if (!$self->is_hdisco_synced()) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => 'host discovery synchronization issue' - } - ); - return ; - } - - my $data = $options{frame}->getData(); - - my $discovery_token = $data->{variables}->[0]; - my $job_id = (defined($discovery_token) && defined($self->{hdisco_jobs_tokens}->{$discovery_token})) ? - $self->{hdisco_jobs_tokens}->{$discovery_token} : undef; - if (!defined($discovery_token) || $discovery_token eq '') { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - missing ':token' variable to delete discovery"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'missing discovery token' } - ); - return 1; - } - - my ($status, $message, $job); - ($status, $message, $job) = $self->get_host_job(job_id => $job_id); - if ($status != 0) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - cannot get host discovery job '$job_id' - " . $self->{tpapi_centreonv2}->error()); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "cannot get job '$job_id'" - } - ); - return 1; - } - - if (!defined($job)) { - $self->{logger}->writeLogDebug("[autodiscovery] -class- host discovery - delete job '" . $job_id . "'"); - if (defined($self->{hdisco_jobs_ids}->{$job_id}->{token})) { - $self->hdisco_delete_cron(discovery_token => $discovery_token); - delete $self->{hdisco_jobs_tokens}->{$discovery_token}; - } - delete $self->{hdisco_jobs_ids}->{$job_id}; - } else { - $self->hdisco_addupdate_job(job => $job); - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { message => 'job ' . $discovery_token . ' deleted' } - ); - - return 0; -} - -sub update_job_status { - my ($self, %options) = @_; - - my $values = { status => $options{status}, message => $options{message} }; - $values->{duration} = $options{duration} if (defined($options{duration})); - $values->{discovered_items} = $options{discovered_items} if (defined($options{discovered_items})); - $self->update_job_information( - values => $values, - where_clause => [ - { - id => $options{job_id} - } - ] - ); - $self->{hdisco_jobs_ids}->{$options{job_id}}->{status} = $options{status}; -} - -sub update_job_information { - my ($self, %options) = @_; - - return 1 if (!defined($options{where_clause}) || ref($options{where_clause}) ne 'ARRAY' || scalar($options{where_clause}) < 1); - return 1 if (!defined($options{values}) || ref($options{values}) ne 'HASH' || !keys %{$options{values}}); - - my $query = "UPDATE mod_host_disco_job SET "; - my @bind_values = (); - my $append = ''; - foreach (keys %{$options{values}}) { - $query .= $append . $_ . ' = ?'; - $append = ', '; - push @bind_values, $options{values}->{$_}; - } - - $query .= " WHERE "; - $append = ''; - foreach (@{$options{where_clause}}) { - my ($key, $value) = each %{$_}; - $query .= $append . $key . " = ?"; - $append = 'AND '; - push @bind_values, $value; - } - - my ($status) = $self->{class_object_centreon}->custom_execute(request => $query, bind_values => \@bind_values); - if ($status == -1) { - $self->{logger}->writeLogError('[autodiscovery] Failed to update job information'); - return -1; - } - - return 0; -} - -sub action_hostdiscoveryjoblistener { - my ($self, %options) = @_; - - return 0 if (!$self->is_hdisco_synced()); - return 0 if (!defined($options{token})); - return 0 if (!defined($self->{hdisco_jobs_tokens}->{ $options{token} })); - - my $data = $options{frame}->getData(); - - my $job_id = $self->{hdisco_jobs_tokens}->{ $options{token} }; - if ($data->{code} == GORGONE_MODULE_ACTION_COMMAND_RESULT && - $data->{data}->{metadata}->{source} eq 'autodiscovery-host-job-discovery') { - $self->discovery_command_result(%options); - return 1; - } - #if ($data->{code} == GORGONE_MODULE_ACTION_COMMAND_RESULT && - # $data->{data}->{metadata}->{source} eq 'autodiscovery-host-job-postcommand') { - # $self->discovery_postcommand_result(%options); - # return 1; - #} - - # Can happen if we have a execution command timeout - my $message = defined($data->{data}->{result}->{stdout}) ? $data->{data}->{result}->{stdout} : $data->{data}->{message}; - $message = $data->{message} if (!defined($message)); - if ($data->{code} == GORGONE_ACTION_FINISH_KO) { - $self->{hdisco_jobs_ids}->{$job_id}->{status} = JOB_FAILED; - $self->update_job_information( - values => { - status => JOB_FAILED, - message => $message, - duration => 0, - discovered_items => 0 - }, - where_clause => [ - { - id => $job_id - } - ] - ); - return 1; - } - - return 1; -} - -sub action_hostdiscoverycronlistener { - my ($self, %options) = @_; - - return 0 if (!defined($options{token}) || $options{token} !~ /^cron-(.*)/); - my $discovery_token = $1; - - return 0 if (!defined($self->{hdisco_jobs_tokens}->{ $discovery_token })); - - my $data = $options{frame}->getData(); - - my $job_id = $self->{hdisco_jobs_tokens}->{ $discovery_token }; - if ($data->{code} == GORGONE_ACTION_FINISH_KO) { - $self->{logger}->writeLogError("[autodiscovery] -class- host discovery - job '" . $job_id . "' add cron error"); - $self->{hdisco_jobs_ids}->{$job_id}->{extra_infos}->{cron_added} = CRON_ADDED_KO; - } elsif ($data->{code} == GORGONE_ACTION_FINISH_OK) { - $self->{logger}->writeLogInfo("[autodiscovery] -class- host discovery - job '" . $job_id . "' add cron ok"); - $self->{hdisco_jobs_ids}->{$job_id}->{extra_infos}->{cron_added} = CRON_ADDED_OK; - } - - return 1; -} - -sub hdisco_add_joblistener { - my ($self, %options) = @_; - - foreach (@{$options{jobs}}) { - $self->{logger}->writeLogDebug("[autodiscovery] -class- host discovery - register listener for '" . $_->{job_id} . "'"); - - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgoneautodiscovery', - event => 'HOSTDISCOVERYJOBLISTENER', - target => $_->{target}, - token => $_->{token}, - log_pace => $self->{check_interval} - } - ] - }); - } - - return 0; -} - -=pod - -********************** -Service Discovery part -********************** - -=cut - -sub action_servicediscoverylistener { - my ($self, %options) = @_; - - return 0 if (!defined($options{token})); - - # 'svc-disco-UUID-RULEID-HOSTID' . $self->{service_uuid} . '-' . $service_number . '-' . $rule_id . '-' . $host->{host_id} - return 0 if ($options{token} !~ /^svc-disco-(.*?)-(\d+)-(\d+)/); - - my ($uuid, $rule_id, $host_id) = ($1, $2, $3); - return 0 if (!defined($self->{service_discoveries}->{ $uuid })); - - $self->{service_discoveries}->{ $uuid }->discoverylistener( - rule_id => $rule_id, - host_id => $host_id, - %options - ); - - if (defined($self->{service_discoveries}->{ $uuid }) && $self->{service_discoveries}->{ $uuid }->is_finished()) { - return 0 if ($self->{service_discoveries}->{ $uuid }->is_post_execution()); - $self->{service_discoveries}->{ $uuid }->service_discovery_post_exec(); - delete $self->{service_discoveries}->{ $uuid }; - } -} - -sub action_launchservicediscovery { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{service_number}++; - my $svc_discovery = gorgone::modules::centreon::autodiscovery::services::discovery->new( - module_id => $self->{module_id}, - logger => $self->{logger}, - tpapi_clapi => $self->{tpapi_clapi}, - internal_socket => $self->{internal_socket}, - config => $self->{config}, - config_core => $self->{config_core}, - service_number => $self->{service_number}, - class_object_centreon => $self->{class_object_centreon}, - class_object_centstorage => $self->{class_object_centstorage}, - class_autodiscovery => $self - ); - - $self->{service_discoveries}->{ $svc_discovery->get_uuid() } = $svc_discovery; - my $status = $svc_discovery->launchdiscovery( - token => $options{token}, - frame => $options{frame} - ); - if ($status == -1) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'cannot launch discovery' } - ); - delete $self->{service_discoveries}->{ $svc_discovery->get_uuid() }; - } -} - -sub is_module_installed { - my ($self) = @_; - - return 1 if ($self->{is_module_installed} == 1); - return 0 if ((time() - $self->{is_module_installed_check_interval}) < $self->{is_module_installed_last_check}); - - $self->{logger}->writeLogDebug('[autodiscovery] -class- host discovery - check centreon module installed'); - $self->{is_module_installed_last_check} = time(); - - my ($status, $results) = $self->{tpapi_centreonv2}->get_platform_versions(); - if ($status != 0) { - $self->{logger}->writeLogError('[autodiscovery] -class- host discovery - cannot get platform versions - ' . $self->{tpapi_centreonv2}->error()); - return 0; - } - - if (defined($results->{modules}) && ref($results->{modules}) eq 'HASH' && - defined($results->{modules}->{'centreon-autodiscovery-server'})) { - $self->{logger}->writeLogDebug('[autodiscovery] -class- host discovery - module autodiscovery installed'); - $self->{is_module_installed} = 1; - } - - return $self->{is_module_installed}; -} - -sub is_hdisco_synced { - my ($self) = @_; - - return $self->{hdisco_synced} == 1 ? 1 : 0; -} - -sub event { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my $frame = gorgone::class::frame->new(); - my (undef, $rv) = $self->read_message(frame => $frame); - next if ($rv); - - my $raw = $frame->getFrame(); - $self->{logger}->writeLogDebug("[autodiscovery] Event: " . $$raw) if ($connector->{logger}->is_debug()); - if ($$raw =~ /^\[(.*?)\]/) { - if ((my $method = $connector->can('action_' . lc($1)))) { - next if ($frame->parse({ releaseFrame => 1, decode => 1 })); - - $method->($self, token => $frame->getToken(), frame => $frame); - } - } - } -} - -sub periodic_exec { - $connector->is_module_installed(); - $connector->hdisco_sync(); - - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[autodiscovery] $$ has quit"); - exit(0); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{tpapi_clapi} = gorgone::class::tpapi::clapi->new(); - $self->{tpapi_clapi}->set_configuration( - config => $self->{tpapi}->get_configuration(name => $self->{tpapi_clapi_name}) - ); - $self->{tpapi_centreonv2} = gorgone::class::tpapi::centreonv2->new(); - my ($status) = $self->{tpapi_centreonv2}->set_configuration( - config => $self->{tpapi}->get_configuration(name => $self->{tpapi_centreonv2_name}), - logger => $self->{logger} - ); - if ($status) { - $self->{logger}->writeLogError('[autodiscovery] -class- host discovery - configure api centreonv2 - ' . $self->{tpapi_centreonv2}->error()); - } - - $self->{db_centreon} = gorgone::class::db->new( - dsn => $self->{config_db_centreon}->{dsn}, - user => $self->{config_db_centreon}->{username}, - password => $self->{config_db_centreon}->{password}, - force => 2, - logger => $self->{logger} - ); - $self->{db_centstorage} = gorgone::class::db->new( - dsn => $self->{config_db_centstorage}->{dsn}, - user => $self->{config_db_centstorage}->{username}, - password => $self->{config_db_centstorage}->{password}, - force => 2, - logger => $self->{logger} - ); - - $self->{class_object_centreon} = gorgone::class::sqlquery->new( - logger => $self->{logger}, - db_centreon => $self->{db_centreon} - ); - $self->{class_object_centstorage} = gorgone::class::sqlquery->new( - logger => $self->{logger}, - db_centreon => $self->{db_centstorage} - ); - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-autodiscovery', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'AUTODISCOVERYREADY', - data => {} - }); - - $self->is_module_installed(); - $self->hdisco_sync(); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/autodiscovery/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/autodiscovery/hooks.pm deleted file mode 100644 index f20befe507..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/autodiscovery/hooks.pm +++ /dev/null @@ -1,164 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::autodiscovery::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::centreon::autodiscovery::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'autodiscovery'; -use constant EVENTS => [ - { event => 'AUTODISCOVERYREADY' }, - { event => 'HOSTDISCOVERYJOBLISTENER' }, - { event => 'HOSTDISCOVERYCRONLISTENER' }, - { event => 'SERVICEDISCOVERYLISTENER' }, - { event => 'ADDHOSTDISCOVERYJOB', uri => '/hosts', method => 'POST' }, - { event => 'DELETEHOSTDISCOVERYJOB', uri => '/hosts', method => 'DELETE' }, - { event => 'LAUNCHHOSTDISCOVERY', uri => '/hosts', method => 'GET' }, - { event => 'LAUNCHSERVICEDISCOVERY', uri => '/services', method => 'POST' } -]; - -my $config_core; -my $config; -my ($config_db_centreon, $config_db_centstorage); -my $autodiscovery = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centreon = $options{config_db_centreon}; - $config_db_centstorage = $options{config_db_centstorage}; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'AUTODISCOVERYREADY') { - $autodiscovery->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$autodiscovery->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { msg => 'gorgoneautodiscovery: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-autodiscovery', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($autodiscovery->{running}) && $autodiscovery->{running} == 1) { - $options{logger}->writeLogDebug("[autodiscovery] Send TERM signal $autodiscovery->{pid}"); - CORE::kill('TERM', $autodiscovery->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($autodiscovery->{running} == 1) { - $options{logger}->writeLogDebug("[autodiscovery] Send KILL signal for pool"); - CORE::kill('KILL', $autodiscovery->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($autodiscovery->{pid}) || $autodiscovery->{pid} != $pid); - - $autodiscovery = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($autodiscovery->{running}) && $autodiscovery->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[autodiscovery] Create module 'autodiscovery' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-autodiscovery'; - my $module = gorgone::modules::centreon::autodiscovery::class->new( - module_id => NAME, - logger => $options{logger}, - config_core => $config_core, - config => $config, - config_db_centreon => $config_db_centreon, - config_db_centstorage => $config_db_centstorage - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[autodiscovery] PID $child_pid (gorgone-autodiscovery)"); - $autodiscovery = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/autodiscovery/services/discovery.pm b/centreon-gorgone/gorgone/modules/centreon/autodiscovery/services/discovery.pm deleted file mode 100644 index 7024085e43..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/autodiscovery/services/discovery.pm +++ /dev/null @@ -1,966 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::autodiscovery::services::discovery; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::modules::centreon::autodiscovery::services::resources; -use Net::SMTP; -use XML::Simple; -use POSIX qw(strftime); -use Safe; - -sub new { - my ($class, %options) = @_; - my $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{internal_socket} = $options{internal_socket}; - $connector->{class_object_centreon} = $options{class_object_centreon}; - $connector->{class_object_centstorage} = $options{class_object_centstorage}; - $connector->{class_autodiscovery} = $options{class_autodiscovery}; - $connector->{tpapi_clapi} = $options{tpapi_clapi}; - $connector->{mail_subject} = defined($connector->{config}->{mail_subject}) ? $connector->{config}->{mail_subject} : 'Centreon Auto Discovery'; - $connector->{mail_from} = defined($connector->{config}->{mail_from}) ? $connector->{config}->{mail_from} : 'centreon-autodisco'; - - $connector->{service_pollers} = {}; - $connector->{audit_user_id} = undef; - $connector->{service_parrallel_commands_poller} = 8; - $connector->{service_current_commands_poller} = {}; - $connector->{finished} = 0; - $connector->{post_execution} = 0; - - $connector->{safe_display} = Safe->new(); - $connector->{safe_display}->share('$values'); - $connector->{safe_display}->share('$description'); - $connector->{safe_display}->permit_only(':default'); - $connector->{safe_display}->share_from( - 'gorgone::modules::centreon::autodiscovery::services::resources', - ['change_bytes'] - ); - - $connector->{safe_cv} = Safe->new(); - $connector->{safe_cv}->share('$values'); - $connector->{safe_cv}->permit_only(':default'); - - $connector->{uuid} = $connector->generate_token(length => 4) . ':' . $options{service_number}; - return $connector; -} - -sub database_init_transaction { - my ($self, %options) = @_; - - my $status = $self->{class_object_centreon}->{db_centreon}->transaction_mode(1); - if ($status == -1) { - $self->{logger}->writeLogError("$@"); - return -1; - } - return 0; -} - -sub database_commit_transaction { - my ($self, %options) = @_; - - my $status = $self->{class_object_centreon}->commit(); - if ($status == -1) { - $self->{logger}->writeLogError("$@"); - return -1; - } - - $self->{class_object_centreon}->transaction_mode(0); - return 0; -} - -sub database_error_rollback { - my ($self, %options) = @_; - - $self->{logger}->writeLogError($options{message}); - eval { - $self->{class_object_centreon}->rollback(); - $self->{class_object_centreon}->transaction_mode(0); - }; - if ($@) { - $self->{logger}->writeLogError("$@"); - } - return -1; -} - -sub get_uuid { - my ($self, %options) = @_; - - return $self->{uuid}; -} - -sub is_finished { - my ($self, %options) = @_; - - return $self->{finished}; -} - -sub is_post_execution { - my ($self, %options) = @_; - - return $self->{post_execution}; -} - -sub send_email { - my ($self, %options) = @_; - - my $messages = {}; - foreach my $journal (@{$self->{discovery}->{journal}}) { - $messages->{ $journal->{rule_id } } = [] if (!defined($messages->{ $journal->{rule_id } })); - push @{$messages->{ $journal->{rule_id } }}, $journal->{type} . " service '" . $journal->{service_name} . "' on host '" . $journal->{host_name} . "'."; - } - - my $contact_send = {}; - foreach my $rule_id (keys %{$self->{discovery}->{rules}}) { - next if (!defined($self->{discovery}->{rules}->{$rule_id}->{contact})); - next if (!defined($messages->{$rule_id})); - - foreach my $contact_id (keys %{$self->{discovery}->{rules}->{$rule_id}->{contact}}) { - next if (defined($contact_send->{$contact_id})); - $contact_send->{$contact_id} = 1; - - my $body = []; - foreach my $rule_id2 (keys %{$messages}) { - if (defined($self->{discovery}->{rules}->{$rule_id2}->{contact}->{$contact_id})) { - push @$body, @{$messages->{$rule_id2}}; - } - } - - if (scalar(@$body) > 0) { - $self->{logger}->writeLogDebug("[autodiscovery] -servicediscovery- $self->{uuid} send email to '" . $contact_id . "' (" . $self->{discovery}->{rules}->{$rule_id}->{contact}->{$contact_id}->{contact_email} . ")"); - - my $smtp = Net::SMTP->new('localhost', Timeout => 15); - if (!defined($smtp)) { - $self->{logger}->writeLogError("[autodiscovery] -servicediscovery- sent email error - " . $@); - next; - } - $smtp->mail($self->{mail_from}); - if (!$smtp->to($self->{discovery}->{rules}->{$rule_id}->{contact}->{$contact_id}->{contact_email})) { - $self->{logger}->writeLogError("[autodiscovery] -servicediscovery- sent email error - " . $smtp->message()); - next; - } - - $smtp->data(); - $smtp->datasend( - 'Date: ' . strftime('%a, %d %b %Y %H:%M:%S %z', localtime(time())) . "\n" . - 'From: ' . $self->{mail_from} . "\n" . - 'To: ' . $self->{discovery}->{rules}->{$rule_id}->{contact}->{$contact_id}->{contact_email} . "\n" . - 'Subject: ' . $self->{mail_subject} . "\n" . - "\n" . - join("\n", @$body) . "\n" - ); - $smtp->dataend(); - $smtp->quit(); - } - } - } -} - -sub restart_pollers { - my ($self, %options) = @_; - - return if ($self->{discovery}->{no_generate_config} == 1); - - my $poller_ids = {}; - foreach my $poller_id (keys %{$self->{discovery}->{pollers_reload}}) { - $self->{logger}->writeLogInfo("[autodiscovery] -servicediscovery- $self->{uuid} generate poller config '" . $poller_id . "'"); - $self->send_internal_action({ - action => 'COMMAND', - token => $self->{discovery}->{token} . ':config', - data => { - content => [ - { - command => $self->{tpapi_clapi}->get_applycfg_command(poller_id => $poller_id) - } - ] - } - }); - } -} - -sub audit_update { - my ($self, %options) = @_; - - return if ($self->{discovery}->{audit_enable} != 1); - - my $query = 'INSERT INTO log_action (action_log_date, object_type, object_id, object_name, action_type, log_contact_id) VALUES (?, ?, ?, ?, ?, ?)'; - my ($status, $sth) = $self->{class_object_centstorage}->custom_execute( - request => $query, - bind_values => [time(), $options{object_type}, $options{object_id}, $options{object_name}, $options{action_type}, $options{contact_id}] - ); - - return if (!defined($options{fields})); - - my $action_log_id = $self->{class_object_centstorage}->{db_centreon}->last_insert_id(); - foreach (keys %{$options{fields}}) { - $query = 'INSERT INTO log_action_modification (action_log_id, field_name, field_value) VALUES (?, ?, ?)'; - ($status) = $self->{class_object_centstorage}->custom_execute( - request => $query, - bind_values => [$action_log_id, $_, $options{fields}->{$_}] - ); - if ($status == -1) { - return -1; - } - } -} - -sub custom_variables { - my ($self, %options) = @_; - - if (defined($options{rule}->{rule_variable_custom}) && $options{rule}->{rule_variable_custom} ne '') { - local $SIG{__DIE__} = 'IGNORE'; - - our $values = { attributes => $options{discovery_svc}->{attributes}, service_name => $options{discovery_svc}->{service_name} }; - $self->{safe_cv}->reval($options{rule}->{rule_variable_custom}, 1); - if ($@) { - $self->{logger}->writeLogError("$options{logger_pre_message} custom variable code execution problem: " . $@); - } else { - $options{discovery_svc}->{attributes} = $values->{attributes}; - } - } -} - -sub get_description { - my ($self, %options) = @_; - - my $desc = $options{discovery_svc}->{service_name}; - if (defined($self->{discovery}->{rules}->{ $options{rule_id} }->{rule_scan_display_custom}) && $self->{discovery}->{rules}->{ $options{rule_id} }->{rule_scan_display_custom} ne '') { - local $SIG{__DIE__} = 'IGNORE'; - - our $description = $desc; - our $values = { attributes => $options{discovery_svc}->{attributes}, service_name => $options{discovery_svc}->{service_name} }; - $self->{safe_display}->reval($self->{discovery}->{rules}->{ $options{rule_id} }->{rule_scan_display_custom}, 1); - if ($@) { - $self->{logger}->writeLogError("$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] custom description code execution problem: " . $@); - } else { - $desc = $description; - } - } - - return $desc; -} - -sub link_service_autodisco { - my ($self, %options) = @_; - - my $query = 'INSERT IGNORE INTO mod_auto_disco_rule_service_relation (rule_rule_id, service_service_id) VALUES (' . $options{rule_id} . ', ' . $options{service_id} . ')'; - my ($status, $sth) = $self->{class_object_centreon}->custom_execute(request => $query); - if ($status == -1) { - return -1; - } - - return 0; -} - -sub update_service { - my ($self, %options) = @_; - my %query_update = (); - my @journal = (); - my @update_macros = (); - my @insert_macros = (); - - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{discovery}->{ $options{discovery_svc}->{service_name} } = { - type => 0, - macros => {}, - description => $self->get_description(%options) - }; - } - - return if ($self->{discovery}->{rules}->{ $options{rule_id} }->{rule_update} == 0); - - if ($options{service}->{template_id} != $self->{discovery}->{rules}->{ $options{rule_id} }->{service_template_model_id}) { - $query_update{service_template_model_stm_id} = $self->{discovery}->{rules}->{ $options{rule_id} }->{service_template_model_id}; - push @journal, { - host_name => $self->{discovery}->{hosts}->{ $options{host_id} }->{host_name}, - service_name => $options{discovery_svc}->{service_name}, - type => 'update', - msg => 'template', - rule_id => $options{rule_id} - }; - - $self->{logger}->writeLogDebug("$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> service update template"); - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{discovery}->{ $options{discovery_svc}->{service_name} }->{service_template_model_stm_id} = $self->{discovery}->{rules}->{ $options{rule_id} }->{service_template_model_id}; - } - } - if ($options{service}->{activate} == '0') { - $query_update{service_activate} = "'1'"; - push @journal, { - host_name => $self->{discovery}->{hosts}->{ $options{host_id} }->{host_name}, - service_name => $options{discovery_svc}->{service_name}, - type => 'enable', - rule_id => $options{rule_id} - }; - $self->{logger}->writeLogDebug("$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> service enable"); - } - - foreach my $macro_name (keys %{$options{macros}}) { - if (!defined($options{service}->{macros}->{'$_SERVICE' . $macro_name . '$'})) { - push @insert_macros, { - name => $macro_name, - value => $options{macros}->{$macro_name} - }; - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{discovery}->{ $options{discovery_svc}->{service_name} }->{macros}->{$macro_name} = { value => $options{macros}->{$macro_name}, type => 1 }; - } - } elsif ($options{service}->{macros}->{'$_SERVICE' . $macro_name . '$'} ne $options{macros}->{$macro_name}) { - push @update_macros, { - name => $macro_name, - value => $options{macros}->{$macro_name} - }; - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{discovery}->{ $options{discovery_svc}->{service_name} }->{macros}->{$macro_name} = { value => $options{macros}->{$macro_name}, type => 0 }; - } - } - } - - if (scalar(@insert_macros) > 0 || scalar(@update_macros) > 0) { - push @journal, { - host_name => $self->{discovery}->{hosts}->{ $options{host_id} }->{host_name}, - service_name => $options{discovery_svc}->{service_name}, - type => 'update', - msg => 'macros', - rule_id => $options{rule_id} - }; - $self->{logger}->writeLogDebug("$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> service update/insert macros"); - } - - return $options{service}->{id} if ($self->{discovery}->{dry_run} == 1 || scalar(@journal) == 0); - - return -1 if ($self->database_init_transaction() == -1); - - if (scalar(keys %query_update) > 0) { - my $set = ''; - my $set_append = ''; - foreach (keys %query_update) { - $set .= $set_append . $_ . ' = ' . $query_update{$_}; - $set_append = ', '; - } - my $query = 'UPDATE service SET ' . $set . ' WHERE service_id = ' . $options{service}->{id}; - my ($status) = $self->{class_object_centreon}->custom_execute(request => $query); - if ($status == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot update service"); - } - } - - foreach (@update_macros) { - my $query = 'UPDATE on_demand_macro_service SET svc_macro_value = ? WHERE svc_svc_id = ' . $options{service}->{id} . ' AND svc_macro_name = ?'; - my ($status) = $self->{class_object_centreon}->custom_execute( - request => $query, - bind_values => [$_->{value}, '$_SERVICE' . $_->{name} . '$'] - ); - if ($status == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot update macro"); - } - } - foreach (@insert_macros) { - my $query = 'INSERT on_demand_macro_service (svc_svc_id, svc_macro_name, svc_macro_value) VALUES (' . $options{service}->{id} . ', ?, ?)'; - my ($status) = $self->{class_object_centreon}->custom_execute( - request => $query, - bind_values => ['$_SERVICE' . $_->{name} . '$', $_->{value}] - ); - if ($status == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot insert macro"); - } - } - - if ($self->link_service_autodisco(%options, service_id => $options{service}->{id}) == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot link service to autodisco"); - } - - return -1 if ($self->database_commit_transaction() == -1); - - $self->{discovery}->{pollers_reload}->{ $options{poller_id} } = 1; - push @{$self->{discovery}->{journal}}, @journal; - - if (defined($query_update{service_activate})) { - $self->audit_update( - object_type => 'service', - action_type => 'enable', - object_id => $options{service}->{id}, - object_name => $options{discovery_svc}->{service_name}, - contact_id => $self->{audit_user_id} - ); - } - if (defined($query_update{service_template_model_stm_id})) { - $self->audit_update( - object_type => 'service', - action_type => 'c', - object_id => $options{service}->{id}, - object_name => $options{discovery_svc}->{service_name}, - contact_id => $self->{audit_user_id}, - fields => { service_template_model_stm_id => $query_update{service_template_model_stm_id} } - ); - } - - return $options{service}->{id}; -} - -sub create_service { - my ($self, %options) = @_; - - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{discovery}->{ $options{discovery_svc}->{service_name} } = { - type => 1, - service_template_model_stm_id => $self->{discovery}->{rules}->{ $options{rule_id} }->{service_template_model_id}, - macros => {}, - description => $self->get_description(%options) - }; - foreach (keys %{$options{macros}}) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{discovery}->{ $options{discovery_svc}->{service_name} }->{macros}->{$_} = { - value => $options{macros}->{$_}, - type => 1 - }; - } - } - - return 0 if ($self->{discovery}->{dry_run} == 1); - # We create the service - - return -1 if ($self->database_init_transaction() == -1); - - my $query = "INSERT INTO service (service_template_model_stm_id, service_description, service_register) VALUES (?, ?, '1')"; - my ($status, $sth) = $self->{class_object_centreon}->custom_execute( - request => $query, - bind_values => [$self->{discovery}->{rules}->{ $options{rule_id} }->{service_template_model_id}, $options{discovery_svc}->{service_name}] - ); - if ($status == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot create service"); - } - my $service_id = $self->{class_object_centreon}->{db_centreon}->last_insert_id(); - - $query = 'INSERT INTO host_service_relation (host_host_id, service_service_id) VALUES (' . $options{host_id} . ', ' . $service_id . ')'; - ($status) = $self->{class_object_centreon}->custom_execute(request => $query); - if ($status == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot link service to host"); - } - - $query = 'INSERT INTO extended_service_information (service_service_id) VALUES (' . $service_id . ')'; - ($status) = $self->{class_object_centreon}->custom_execute(request => $query); - if ($status == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot service extended information"); - } - - foreach (keys %{$options{macros}}) { - $query = 'INSERT INTO on_demand_macro_service (svc_svc_id, svc_macro_name, svc_macro_value) VALUES (' . $service_id . ', ?, ?)'; - ($status) = $self->{class_object_centreon}->custom_execute( - request => $query, - bind_values => ['$_SERVICE' . $_ . '$', $options{macros}->{$_}] - ); - if ($status == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot create macro '$_' => '$options{macros}->{$_}'"); - } - } - - if ($self->link_service_autodisco(%options, service_id => $service_id) == -1) { - return $self->database_error_rollback(message => "$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> cannot link service to autodisco"); - } - - return -1 if ($self->database_commit_transaction() == -1); - - $self->{discovery}->{pollers_reload}->{ $options{poller_id} } = 1; - - $self->audit_update( - object_type => 'service', - action_type => 'a', - object_id => $service_id, - object_name => $options{discovery_svc}->{service_name}, - contact_id => $self->{audit_user_id}, - fields => { - service_template_model_id => $self->{discovery}->{rules}->{ $options{rule_id} }->{service_template_model_id}, - service_description => $options{discovery_svc}->{service_name}, - service_register => '1', - service_hPars => $options{host_id} - } - ); - - return $service_id; -} - -sub crud_service { - my ($self, %options) = @_; - - my $service_id; - if (!defined($options{service})) { - $service_id = $self->create_service(%options); - $self->{logger}->writeLogDebug("$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> service created"); - if ($service_id != -1) { - push @{$self->{discovery}->{journal}}, { - host_name => $self->{discovery}->{hosts}->{ $options{host_id} }->{host_name}, - service_name => $options{discovery_svc}->{service_name}, - type => 'created', - rule_id => $options{rule_id} - }; - } - } else { - $service_id = $self->update_service(%options); - } - - return 0; -} - -sub disable_services { - my ($self, %options) = @_; - - return if ($self->{discovery}->{rules}->{ $options{rule_id} }->{rule_disable} != 1 || !defined($self->{discovery}->{rules}->{ $options{rule_id} }->{linked_services}->{ $options{host_id} })); - foreach my $service (keys %{$self->{discovery}->{rules}->{ $options{rule_id} }->{linked_services}->{ $options{host_id} }}) { - my $service_description = $self->{discovery}->{rules}->{ $options{rule_id} }->{linked_services}->{ $options{host_id} }->{$service}->{service_description}; - - if (!defined($options{discovery_svc}->{discovered_services}->{$service_description}) && - $self->{discovery}->{rules}->{ $options{rule_id} }->{linked_services}->{ $options{host_id} }->{$service}->{service_activate} == 1) { - $self->{logger}->writeLogDebug("$options{logger_pre_message} -> disable service '" . $service_description . "'"); - next if ($self->{discovery}->{dry_run} == 1); - - my $query = "UPDATE service SET service_activate = '0' WHERE service_id = " . $service; - my ($status) = $self->{class_object_centreon}->custom_execute(request => $query); - if ($status == -1) { - $self->{logger}->writeLogError("$options{logger_pre_message} -> cannot disable service '" . $service_description . "'"); - next; - } - - push @{$self->{discovery}->{journal}}, { - host_name => $self->{discovery}->{hosts}->{ $options{host_id} }->{host_name}, - service_name => $service_description, - type => 'disable', - rule_id => $options{rule_id} - }; - $self->{discovery}->{pollers_reload}->{ $options{poller_id} } = 1; - $self->audit_update( - object_type => 'service', - action_type => 'disable', - object_id => $service, - object_name => $service_description, - contact_id => $self->{audit_user_id} - ); - } - } -} - -sub service_response_parsing { - my ($self, %options) = @_; - - my $rule_alias = $self->{discovery}->{rules}->{ $options{rule_id} }->{rule_alias}; - my $poller_name = $self->{service_pollers}->{ $options{poller_id} }->{name}; - my $host_name = $self->{discovery}->{hosts}->{ $options{host_id} }->{host_name}; - my $logger_pre_message = "[autodiscovery] -servicediscovery- $self->{uuid} [" . $rule_alias . "] [" . $poller_name . "] [" . $host_name . "]"; - - my $xml; - eval { - $xml = XMLin($options{response}, ForceArray => 1, KeyAttr => []); - }; - if ($@) { - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{failed} = 1; - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{message} = 'load xml issue'; - } - $self->{logger}->writeLogError("$logger_pre_message -> load xml issue"); - $self->{logger}->writeLogDebug("$logger_pre_message -> load xml error: $@"); - return -1; - } - - my $discovery_svc = { discovered_services => {} }; - foreach my $attributes (@{$xml->{label}}) { - $discovery_svc->{service_name} = ''; - $discovery_svc->{attributes} = $attributes; - - $self->custom_variables( - discovery_svc => $discovery_svc, - rule => $self->{discovery}->{rules}->{ $options{rule_id} }, - logger_pre_message => $logger_pre_message - ); - - gorgone::modules::centreon::autodiscovery::services::resources::change_vars( - discovery_svc => $discovery_svc, - rule => $self->{discovery}->{rules}->{ $options{rule_id} }, - logger => $self->{logger}, - logger_pre_message => $logger_pre_message - ); - if ($discovery_svc->{service_name} eq '') { - $self->{logger}->writeLogError("$logger_pre_message -> no value for service name"); - next; - } - - if (defined($discovery_svc->{discovered_services}->{ $discovery_svc->{service_name} })) { - $self->{logger}->writeLogError("$logger_pre_message -> service '" . $discovery_svc->{service_name} . "' already created"); - next; - } - - $discovery_svc->{discovered_services}->{ $discovery_svc->{service_name} } = 1; - - next if ( - gorgone::modules::centreon::autodiscovery::services::resources::check_exinc( - discovery_svc => $discovery_svc, - rule => $self->{discovery}->{rules}->{ $options{rule_id} }, - logger => $self->{logger}, - logger_pre_message => $logger_pre_message - ) - ); - - my $macros = gorgone::modules::centreon::autodiscovery::services::resources::get_macros( - discovery_svc => $discovery_svc, - rule => $self->{discovery}->{rules}->{ $options{rule_id} } - ); - - my ($status, $service) = gorgone::modules::centreon::autodiscovery::services::resources::get_service( - class_object_centreon => $self->{class_object_centreon}, - host_id => $options{host_id}, - service_name => $discovery_svc->{service_name}, - logger => $self->{logger}, - logger_pre_message => $logger_pre_message - ); - next if ($status == -1); - - $self->crud_service( - discovery_svc => $discovery_svc, - rule_id => $options{rule_id}, - host_id => $options{host_id}, - poller_id => $options{poller_id}, - service => $service, - macros => $macros, - logger_pre_message => $logger_pre_message - ); - } - - $self->disable_services( - discovery_svc => $discovery_svc, - rule_id => $options{rule_id}, - host_id => $options{host_id}, - poller_id => $options{poller_id}, - logger_pre_message => $logger_pre_message - ); -} - -sub discoverylistener { - my ($self, %options) = @_; - - my $data = $options{frame}->getData(); - - return 0 if ($data->{code} != GORGONE_MODULE_ACTION_COMMAND_RESULT && $data->{code} != GORGONE_ACTION_FINISH_KO); - - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} } = { rules => {} } if (!defined($self->{discovery}->{manual}->{ $options{host_id} })); - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} } = { failed => 0, discovery => {} } if (!defined($self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} })); - } - - # if i have GORGONE_MODULE_ACTION_COMMAND_RESULT, i can't have GORGONE_ACTION_FINISH_KO - if ($data->{code} == GORGONE_MODULE_ACTION_COMMAND_RESULT) { - my $exit_code = $data->{data}->{result}->{exit_code}; - if ($exit_code == 0) { - $self->service_response_parsing( - rule_id => $options{rule_id}, - host_id => $options{host_id}, - poller_id => $self->{discovery}->{hosts}->{ $options{host_id} }->{poller_id}, - response => $data->{data}->{result}->{stdout} - ); - } else { - $self->{discovery}->{failed_discoveries}++; - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{failed} = 1; - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{message} = $data->{data}->{message}; - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{data} = $data->{data}; - } - } - } elsif ($data->{code} == GORGONE_ACTION_FINISH_KO) { - if ($self->{discovery}->{is_manual} == 1) { - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{failed} = 1; - $self->{discovery}->{manual}->{ $options{host_id} }->{rules}->{ $options{rule_id} }->{message} = $data->{data}->{message}; - } - $self->{discovery}->{failed_discoveries}++; - } else { - return 0; - } - - $self->{service_current_commands_poller}->{ $self->{discovery}->{hosts}->{ $options{host_id} }->{poller_id} }--; - $self->service_execute_commands(); - - $self->{discovery}->{done_discoveries}++; - my $progress = $self->{discovery}->{done_discoveries} * 100 / $self->{discovery}->{count_discoveries}; - my $div = int(int($progress) / 5); - if ($div > $self->{discovery}->{progress_div}) { - $self->{discovery}->{progress_div} = $div; - $self->send_log( - code => GORGONE_MODULE_CENTREON_AUTODISCO_SVC_PROGRESS, - token => $self->{discovery}->{token}, - instant => 1, - data => { - message => 'current progress', - complete => sprintf('%.2f', $progress) - } - ); - } - - $self->{logger}->writeLogDebug("[autodiscovery] -servicediscovery- $self->{uuid} current count $self->{discovery}->{done_discoveries}/$self->{discovery}->{count_discoveries}"); - if ($self->{discovery}->{done_discoveries} == $self->{discovery}->{count_discoveries}) { - $self->{logger}->writeLogInfo("[autodiscovery] -servicediscovery- $self->{uuid} discovery finished"); - $self->{finished} = 1; - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $self->{discovery}->{token}, - data => { - message => 'discovery finished', - failed_discoveries => $self->{discovery}->{failed_discoveries}, - count_discoveries => $self->{discovery}->{count_discoveries}, - journal => $self->{discovery}->{journal}, - manual => $self->{discovery}->{manual} - } - ); - } - - return 0; -} - -sub service_discovery_post_exec { - my ($self, %options) = @_; - - $self->{post_execution} = 1; - - if ($self->{discovery}->{is_manual} == 0) { - $self->restart_pollers(); - $self->send_email(); - } - - return 0; -} - -sub service_execute_commands { - my ($self, %options) = @_; - - foreach my $rule_id (keys %{$self->{discovery}->{rules}}) { - foreach my $poller_id (keys %{$self->{discovery}->{rules}->{$rule_id}->{hosts}}) { - next if (scalar(@{$self->{discovery}->{rules}->{$rule_id}->{hosts}->{$poller_id}}) <= 0); - $self->{service_current_commands_poller}->{$poller_id} = 0 if (!defined($self->{service_current_commands_poller}->{$poller_id})); - - while (1) { - last if ($self->{service_current_commands_poller}->{$poller_id} >= $self->{service_parrallel_commands_poller}); - my $host_id = shift @{$self->{discovery}->{rules}->{$rule_id}->{hosts}->{$poller_id}}; - last if (!defined($host_id)); - - my $host = $self->{discovery}->{hosts}->{$host_id}; - $self->{service_current_commands_poller}->{$poller_id}++; - - my $command = gorgone::modules::centreon::autodiscovery::services::resources::substitute_service_discovery_command( - command_line => $self->{discovery}->{rules}->{$rule_id}->{command_line}, - host => $host, - poller => $self->{service_pollers}->{$poller_id}, - vault_count => $options{vault_count} - ); - - $self->{logger}->writeLogDebug("[autodiscovery] -servicediscovery- $self->{uuid} [" . - $self->{discovery}->{rules}->{$rule_id}->{rule_alias} . "] [" . - $self->{service_pollers}->{$poller_id}->{name} . "] [" . - $host->{host_name} . "] -> substitute string: " . $command - ); - - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgoneautodiscovery', - event => 'SERVICEDISCOVERYLISTENER', - target => $poller_id, - token => 'svc-disco-' . $self->{uuid} . '-' . $rule_id . '-' . $host_id, - timeout => 120, - log_pace => 15 - } - ] - }); - - $self->send_internal_action({ - action => 'COMMAND', - target => $poller_id, - token => 'svc-disco-' . $self->{uuid} . '-' . $rule_id . '-' . $host_id, - data => { - instant => 1, - content => [ - { - command => $command, - timeout => 90 - } - ] - } - }); - } - } - } -} - -sub launchdiscovery { - my ($self, %options) = @_; - - my $data = $options{frame}->getData(); - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{logger}->writeLogInfo("[autodiscovery] -servicediscovery- $self->{uuid} discovery start"); - $self->send_log( - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - data => { message => 'servicediscovery start' } - ); - - ################ - # get pollers - ################ - $self->{logger}->writeLogDebug("[autodiscovery] -servicediscovery- $self->{uuid} load pollers configuration"); - my ($status, $message, $pollers) = gorgone::modules::centreon::autodiscovery::services::resources::get_pollers( - class_object_centreon => $self->{class_object_centreon} - ); - if ($status < 0) { - $self->send_log_msg_error(token => $options{token}, subname => 'servicediscovery', number => $self->{uuid}, message => $message); - return -1; - } - $self->{service_pollers} = $pollers; - - ################ - # get audit user - ################ - $self->{logger}->writeLogDebug("[autodiscovery] -servicediscovery- $self->{uuid} load audit configuration"); - - ($status, $message, my $audit_enable) = gorgone::modules::centreon::autodiscovery::services::resources::get_audit( - class_object_centstorage => $self->{class_object_centstorage} - ); - if ($status < 0) { - $self->send_log_msg_error(token => $options{token}, subname => 'servicediscovery', number => $self->{uuid}, message => $message); - return -1; - } - - if (!defined($self->{tpapi_clapi}->get_username())) { - $self->send_log_msg_error(token => $options{token}, subname => 'servicediscovery', number => $self->{uuid}, message => 'clapi ' . $self->{tpapi_clapi}->error()); - return -1; - } - ($status, $message, my $user_id) = gorgone::modules::centreon::autodiscovery::services::resources::get_audit_user_id( - class_object_centreon => $self->{class_object_centreon}, - clapi_user => $self->{tpapi_clapi}->get_username() - ); - if ($status < 0) { - $self->send_log_msg_error(token => $options{token}, subname => 'servicediscovery', number => $self->{uuid}, message => $message); - return -1; - } - $self->{audit_user_id} = $user_id; - - ################## - # get vault config - ################## - ($status, $message, my $vault_count) = gorgone::modules::centreon::autodiscovery::services::resources::get_vault_configured( - class_object_centreon => $self->{class_object_centreon} - ); - if ($status < 0) { - $self->send_log_msg_error(token => $options{token}, subname => 'servicediscovery', number => $self->{uuid}, message => $message); - return -1; - } - - ################ - # get rules - ################ - - $self->{logger}->writeLogDebug("[autodiscovery] -servicediscovery- $self->{uuid} load rules configuration"); - - ($status, $message, my $rules) = gorgone::modules::centreon::autodiscovery::services::resources::get_rules( - class_object_centreon => $self->{class_object_centreon}, - filter_rules => $data->{content}->{filter_rules}, - force_rule => (defined($data->{content}->{force_rule}) && $data->{content}->{force_rule} =~ /^1$/) ? 1 : 0 - ); - if ($status < 0) { - $self->send_log_msg_error(token => $options{token}, subname => 'servicediscovery', number => $self->{uuid}, message => $message); - return -1; - } - - ################# - # get hosts - ################# - gorgone::modules::centreon::autodiscovery::services::resources::reset_macro_hosts(); - my $all_hosts = {}; - my $total = 0; - foreach my $rule_id (keys %$rules) { - ($status, $message, my $hosts, my $count) = gorgone::modules::centreon::autodiscovery::services::resources::get_hosts( - host_template => $rules->{$rule_id}->{host_template}, - poller_id => $rules->{$rule_id}->{poller_id}, - class_object_centreon => $self->{class_object_centreon}, - with_macro => 1, - host_lookup => $data->{content}->{filter_hosts}, - poller_lookup => $data->{content}->{filter_pollers}, - vault_count => $vault_count - ); - if ($status < 0) { - $self->send_log_msg_error(token => $options{token}, subname => 'servicediscovery', number => $self->{uuid}, message => $message); - return -1; - } - - if (!defined($hosts) || scalar(keys %$hosts) == 0) { - $self->{logger}->writeLogInfo("[autodiscovery] -servicediscovery- $self->{uuid} no hosts found for rule '" . $options{rule}->{rule_alias} . "'"); - next; - } - - $total += $count; - $rules->{$rule_id}->{hosts} = $hosts->{pollers}; - $all_hosts = { %$all_hosts, %{$hosts->{infos}} }; - - foreach (('rule_scan_display_custom', 'rule_variable_custom')) { - if (defined($rules->{$rule_id}->{$_}) && $rules->{$rule_id}->{$_} ne '') { - $rules->{$rule_id}->{$_} =~ s/\$([a-zA-Z_\-\.]*?)\$/\$values->{attributes}->{$1}/msg; - $rules->{$rule_id}->{$_} =~ s/\@SERVICENAME\@/\$values->{service_name}/msg; - } - } - } - - if ($total == 0) { - $self->send_log_msg_error(token => $options{token}, subname => 'servicediscovery', number => $self->{uuid}, message => 'no hosts found'); - return -1; - } - - $self->{discovery} = { - token => $options{token}, - count_discoveries => $total, - failed_discoveries => 0, - done_discoveries => 0, - progress_div => 0, - rules => $rules, - manual => {}, - is_manual => (defined($data->{content}->{manual}) && $data->{content}->{manual} =~ /^1$/) ? 1 : 0, - dry_run => (defined($data->{content}->{dry_run}) && $data->{content}->{dry_run} =~ /^1$/) ? 1 : 0, - audit_enable => $audit_enable, - no_generate_config => (defined($data->{content}->{no_generate_config}) && $data->{content}->{no_generate_config} =~ /^1$/) ? 1 : 0, - options => defined($data->{content}) ? $data->{content} : {}, - hosts => $all_hosts, - journal => [], - pollers_reload => {} - }; - - $self->service_execute_commands(vault_count => $vault_count); - - return 0; -} - -sub event { - my ($self, %options) = @_; - - $self->{class_autodiscovery}->event(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/autodiscovery/services/resources.pm b/centreon-gorgone/gorgone/modules/centreon/autodiscovery/services/resources.pm deleted file mode 100644 index 7185326ba4..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/autodiscovery/services/resources.pm +++ /dev/null @@ -1,646 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::autodiscovery::services::resources; - -use strict; -use warnings; - -sub get_pollers { - my (%options) = @_; - - my ($status, $pollers) = $options{class_object_centreon}->custom_execute( - request => 'SELECT id, name FROM nagios_server', - mode => 1, - keys => 'id' - ); - if ($status == -1) { - return (-1, 'cannot get poller list'); - } - - if (scalar(keys %$pollers) == 0) { - return (-1, 'no pollers found in configuration'); - } - - foreach my $poller_id (keys %$pollers) { - $pollers->{$poller_id}->{resources} = {}; - ($status, my $resources) = $options{class_object_centreon}->custom_execute( - request => - 'SELECT resource_name, resource_line FROM cfg_resource_instance_relations, cfg_resource WHERE cfg_resource_instance_relations.instance_id = ?' . - " AND cfg_resource_instance_relations.resource_id = cfg_resource.resource_id AND resource_activate = '1'", - bind_values => [$poller_id], - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules resource list'); - } - - foreach (@$resources) { - $pollers->{$poller_id}->{resources}->{ $_->[0] } = $_->[1]; - } - } - - return (0, '', $pollers); -} - -sub get_audit { - my (%options) = @_; - my $audit = 0; - - my ($status, $rows) = $options{class_object_centstorage}->custom_execute( - request => - 'SELECT audit_log_option FROM config LIMIT 1', - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get audit configuration'); - } - if (defined($rows->[0]->[0])) { - $audit = $rows->[0]->[0]; - } - - return (1, '', $audit); -} - -sub get_audit_user_id { - my (%options) = @_; - my $user_id = 0; - - my ($status, $contacts) = $options{class_object_centreon}->custom_execute( - request => 'SELECT contact_id FROM contact WHERE contact_alias = ?', - bind_values => [$options{clapi_user}], - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get audit user'); - } - - if (defined($contacts->[0])) { - $user_id = $contacts->[0]->[0]; - } - - return (0, '', $user_id); -} - -sub get_vault_configured { - my (%options) = @_; - - my ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => "SELECT count(id) FROM vault_configuration", - mode => 2 - ); - if ($status == -1 || !defined($datas->[0])) { - return (-1, 'cannot get number of vault configured'); - } - - return (0, '', $datas->[0]->[0]); -} - -sub get_rules { - my (%options) = @_; - - my $filter = "rule_activate = '1' AND "; - if (defined($options{force_rule}) && $options{force_rule} == 1) { - $filter = ''; - } - - my @bind_values = (); - if (defined($options{filter_rules}) && scalar(@{$options{filter_rules}}) > 0) { - my $append = ''; - $filter .= 'rule_alias IN ('; - foreach my $rule (@{$options{filter_rules}}) { - $filter .= $append . '?'; - $append = ', '; - push @bind_values, $rule; - } - $filter .= ') AND '; - } - - my ($status, $rules) = $options{class_object_centreon}->custom_execute( - request => - "SELECT rule_id, rule_alias, service_display_name, rule_disable, rule_update, command_line, service_template_model_id, rule_scan_display_custom, rule_variable_custom - FROM mod_auto_disco_rule, command WHERE " . $filter . " mod_auto_disco_rule.command_command_id = command.command_id", - bind_values => \@bind_values, - mode => 1, - keys => 'rule_id' - ); - if ($status == -1) { - return (-1, 'cannot get rules list'); - } - if (scalar(keys %$rules) == 0) { - return (-1, 'no rules found in configuration'); - } - - $filter = '(' . join(',', keys %$rules) . ')'; - - ############################ - # Get mod_auto_disco_change - ($status, my $datas) = $options{class_object_centreon}->custom_execute( - request => 'SELECT rule_id, change_str, change_regexp, change_replace, change_modifier FROM mod_auto_disco_change WHERE rule_id IN ' . $filter . ' ORDER BY rule_id, change_order ASC', - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules change list'); - } - foreach (@$datas) { - $rules->{ $_->[0] }->{change} = [] if (!defined($rules->{ $_->[0] }->{change})); - push @{$rules->{ $_->[0] }->{change}}, { change_str => $_->[1], change_regexp => $_->[2], change_replace => $_->[3], change_modifier => $_->[4] }; - } - - ######################################### - # Get mod_auto_disco_inclusion_exclusion - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => 'SELECT rule_id, exinc_type, exinc_str, exinc_regexp FROM mod_auto_disco_inclusion_exclusion WHERE rule_id IN ' . $filter . ' ORDER BY rule_id, exinc_order ASC', - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules exinc list'); - } - foreach (@$datas) { - $rules->{ $_->[0] }->{exinc} = [] if (!defined($rules->{ $_->[0] }->{exinc})); - push @{$rules->{ $_->[0] }->{exinc}}, { exinc_type => $_->[1], exinc_str => $_->[2], exinc_regexp => $_->[3] }; - } - - ######################################### - # Get mod_auto_disco_macro - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => 'SELECT rule_id, macro_name, macro_value, is_empty FROM mod_auto_disco_macro WHERE rule_id IN ' . $filter, - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules macro list'); - } - foreach (@$datas) { - $rules->{ $_->[0] }->{macro} = {} if (!defined($rules->{ $_->[0] }->{macro})); - $rules->{ $_->[0] }->{macro}->{ $_->[1] } = { macro_value => $_->[2], is_empty => $_->[3] }; - } - - ######################################### - # Get mod_auto_disco_inst_rule_relation - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => 'SELECT rule_rule_id as rule_id, instance_id FROM mod_auto_disco_inst_rule_relation WHERE rule_rule_id IN ' . $filter, - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules instance list'); - } - foreach (@$datas) { - $rules->{ $_->[0] }->{poller_id} = [] if (!defined($rules->{ $_->[0] }->{poller_id})); - push @{$rules->{ $_->[0] }->{poller_id}}, $_->[1]; - } - - ######################################### - # Get mod_auto_disco_ht_rule_relation - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => 'SELECT rule_rule_id as rule_id, host_host_id FROM mod_auto_disco_ht_rule_relation WHERE rule_rule_id IN ' . $filter, - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules host template list'); - } - foreach (@$datas) { - $rules->{ $_->[0] }->{host_template} = [] if (!defined($rules->{ $_->[0] }->{host_template})); - push @{$rules->{ $_->[0] }->{host_template}}, $_->[1]; - } - - ######################################## - # Get services added by autodisco - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => 'SELECT rule_rule_id as rule_id, host_host_id as host_id, service_id, service_activate, service_description FROM mod_auto_disco_rule_service_relation, service, host_service_relation WHERE rule_rule_id IN ' . $filter . " AND mod_auto_disco_rule_service_relation.service_service_id = service.service_id AND service.service_id = host_service_relation.service_service_id", - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules host template list'); - } - foreach (@$datas) { - $rules->{ $_->[0] }->{linked_services} = {} if (!defined($rules->{ $_->[0] }->{linked_services})); - $rules->{ $_->[0] }->{linked_services}->{ $_->[1] } = {} if (!defined($rules->{ $_->[0] }->{linked_services}->{ $_->[1] })); - $rules->{ $_->[0] }->{linked_services}->{ $_->[1] }->{ $_->[2] } = { - service_activate => $_->[3], service_description => $_->[4] - }; - } - - ######################################### - # Get Contact - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => 'SELECT rule_id, contact_id, cg_id FROM mod_auto_disco_rule_contact_relation WHERE rule_id IN ' . $filter, - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules contact list'); - } - foreach (@$datas) { - if (defined($_->[1])) { - # Already add it - next if (defined($rules->{ $_->[0] }->{contact}->{ $_->[1] })); - if ((my $contact = get_contact(class_object_centreon => $options{class_object_centreon}, contact_id => $_->[1]))) { - $rules->{ $_->[0] }->{contact} = {} if (!defined($rules->{ $_->[0] }->{contact})); - $rules->{ $_->[0] }->{contact}->{ $contact->{contact_id} } = { contact_email => $contact->{contact_email} }; - } - } elsif (defined($_->[2])) { - ($status, my $datas2) = $options{class_object_centreon}->custom_execute( - request => "SELECT contact_contact_id as contact_id FROM contactgroup, contactgroup_contact_relation WHERE contactgroup.cg_id = '" . $_->[2] . "' AND contactgroup.cg_id = contactgroup_contact_relation.contactgroup_cg_id", - mode => 2 - ); - if ($status == -1) { - return (-1, 'cannot get rules contactgroup list'); - } - foreach my $row (@$datas2) { - # Already add it - next if (defined($rules->{ $_->[0] }->{contact}->{ $row->[0] })); - if ((my $contact = get_contact(class_object_centreon => $options{class_object_centreon}, contact_id => $row->[0]))) { - $rules->{ $_->[0] }->{contact} = {} if (!defined($rules->{ $_->[0] }->{contact})); - $rules->{ $_->[0] }->{contact}->{ $contact->{contact_id} } = { contact_email => $contact->{contact_email} }; - } - } - } - } - - # Filter rules - if (defined($options{filter_rules}) && ref($options{filter_rules}) eq 'SCALAR') { - foreach (keys %$rules) { - my $find = 0; - foreach my $opt_rule (@{$options{filter_rules}}) { - if ($opt_rule eq $rules->{$_}->{rule_alias}) { - $find = 1; - last; - } - } - - if ($find == 0) { - delete $rules->{$_}; - } - } - } - - return (0, '', $rules); -} - -sub get_contact { - my (%options) = @_; - - my ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => "SELECT contact_id, contact_email FROM contact WHERE contact_id = '" . $options{contact_id} . "' AND contact_activate = '1'", - mode => 1, - keys => 'contact_id' - ); - - if ($status == -1) { - return 0; - } - - return defined($datas->{ $options{contact_id} }) ? $datas->{ $options{contact_id} } : undef; -} - -my $done_macro_host = {}; - -sub reset_macro_hosts { - $done_macro_host = {}; -} - -sub get_hosts { - my (%options) = @_; - - if (!defined($options{host_template}) || scalar(@{$options{host_template}}) == 0) { - return (0, 'cannot get host list', []); - } - - my $filter = ''; - my $filter_append = ''; - my @bind_values = (); - - my $filter_host = ''; - if (defined($options{host_lookup}) && ref($options{host_lookup}) eq 'ARRAY' && scalar(@{$options{host_lookup}}) > 0) { - my $filter_append = ''; - foreach (@{$options{host_lookup}}) { - $filter_host .= $filter_append . '?'; - $filter_append = ', '; - push @bind_values, $_; - } - $filter_host = ' host.host_name IN (' . $filter_host . ') AND '; - } - - foreach (@{$options{host_template}}) { - $filter .= $filter_append . '?'; - $filter_append = ', '; - push @bind_values, $_; - } - $filter = ' host_template_relation.host_tpl_id IN (' . $filter . ') AND '; - - my $filter_poller = ''; - my $join_table = ''; - if (defined($options{poller_lookup}) && ref($options{poller_lookup}) eq 'ARRAY' && scalar(@{$options{poller_lookup}}) > 0) { - my $filter_append = ''; - foreach (@{$options{poller_lookup}}) { - $filter_poller .= $filter_append . '?'; - $filter_append = ', '; - push @bind_values, $_; - } - $filter_poller = ' nagios_server.name IN ('. $filter_poller .') AND nagios_server.id = ns_host_relation.nagios_server_id AND '; - $join_table = ', nagios_server '; - } elsif (defined($options{poller_id}) && scalar(@{$options{poller_id}}) > 0){ - my $filter_append = ''; - foreach (@{$options{poller_id}}) { - $filter_poller .= $filter_append . '?'; - $filter_append = ', '; - push @bind_values, $_; - } - $filter_poller =' ns_host_relation.nagios_server_id IN (' . $filter_poller . ') AND nagios_server.id = ns_host_relation.nagios_server_id AND '; - $join_table = ', nagios_server '; - } - - my ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => "SELECT host_id, host_address, host_name, nagios_server_id as poller_id - FROM host_template_relation, host, ns_host_relation " . $join_table . " - WHERE " . $filter_host . $filter . " host_template_relation.host_host_id = host.host_id - AND " . $filter_poller . " host.host_id = ns_host_relation.host_host_id - AND `host_activate` = '1' - ", - bind_values => \@bind_values, - mode => 1, - keys => 'host_id' - ); - if ($status == -1) { - return (-1, 'cannot host list'); - } - - my $hosts = { pollers => {}, infos => {} }; - my $count = 0; - foreach my $host_id (keys %$datas) { - if (defined($options{with_macro}) && $options{with_macro} == 1) { - if (defined($done_macro_host->{ $host_id })) { - $datas->{$host_id}->{macros} = $done_macro_host->{ $host_id }; - } else { - ($status, my $message, my $macros) = get_macros_host( - host_id => $host_id, - class_object_centreon => $options{class_object_centreon}, - vault_count => $options{vault_count} - ); - if ($status == -1) { - return (-1, $message); - } - $datas->{$host_id}->{macros} = $macros; - $done_macro_host->{ $host_id } = $macros; - } - } - - $count++; - push @{$hosts->{pollers}->{ $datas->{$host_id}->{poller_id} }}, $host_id; - $hosts->{infos}->{$host_id} = $datas->{$host_id}; - } - - return (0, '', $hosts, $count); -} - -sub set_macro { - my ($macros, $name, $value) = @_; - - if (!defined($macros->{$name})) { - $macros->{$name} = $value; - } -} - -sub get_macros_host { - my (%options) = @_; - my ($status, $datas); - my %macros = (); - my %loop_stop = (); - my @stack = ($options{host_id}); - - while ((my $lhost_id = shift(@stack))) { - if (defined($loop_stop{$lhost_id})) { - # Already done the host - next; - } - $loop_stop{$lhost_id} = 1; - - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => "SELECT host_snmp_community, host_snmp_version FROM host WHERE host_id = " . $lhost_id . " LIMIT 1", - mode => 2 - ); - if ($status == -1) { - return (-1, 'get macro: cannot get snmp information'); - } - - if (defined($datas->[0]->[0]) && $datas->[0]->[0] ne '') { - set_macro(\%macros, '$_HOSTSNMPCOMMUNITY$', $datas->[0]->[0]); - } - if (defined($datas->[0]->[1]) && $datas->[0]->[1] ne '') { - set_macro(\%macros, '$_HOSTSNMPVERSION$', $datas->[0]->[1]); - } - - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => "SELECT host_macro_name, host_macro_value, is_password FROM on_demand_macro_host WHERE host_host_id = " . $lhost_id, - mode => 2 - ); - if ($status == -1) { - return (-1, 'get macro: cannot get on_demand_macro_host'); - } - foreach (@$datas) { - my $macro_name = $_->[0]; - my $macro_value = $_->[1]; - my $is_password = $_->[2]; - # Replace macro value if a vault is used - if (defined($options{vault_count}) && $options{vault_count} > 0 && defined($is_password) && $is_password == 1) { - set_macro(\%macros, $macro_name, "{" . $macro_name . "::secret::" . $macro_value . "}"); - } else { - set_macro(\%macros, $macro_name, $macro_value); - } - } - - ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => "SELECT host_tpl_id FROM host_template_relation WHERE host_host_id = " . $lhost_id . " ORDER BY `order` DESC", - mode => 2 - ); - if ($status == -1) { - return (-1, 'get macro: cannot get host_template_relation'); - } - foreach (@$datas) { - unshift @stack, $_->[0]; - } - } - - return (0, '', \%macros); -} - -sub substitute_service_discovery_command { - my (%options) = @_; - - my $command = $options{command_line}; - while ($command =~ /(\$_HOST.*?\$)/) { - my ($substitute_str, $macro) = ('', $1); - $substitute_str = $options{host}->{macros}->{$macro} if (defined($options{host}->{macros}->{$macro})); - $command =~ s/\Q$macro\E/$substitute_str/g; - } - while ($command =~ /(\$(?:USER.*?|CENTREONPLUGINS)\$)/) { - my ($substitute_str, $macro) = ('', $1); - $substitute_str = $options{poller}->{resources}->{$macro} if (defined($options{poller}->{resources}->{$macro})); - $command =~ s/\Q$macro\E/$substitute_str/g; - } - - $command =~ s/\$HOSTADDRESS\$/$options{host}->{host_address}/g; - $command =~ s/\$HOSTNAME\$/$options{host}->{host_name}/g; - - if (defined($options{vault_count}) && $options{vault_count} > 0) { - $command .= ' --pass-manager="centreonvault"'; - } - - return $command; -} - -sub change_vars { - my (%options) = @_; - - # First we change '$$' values - if (defined($options{rule}->{change})) { - foreach my $change (@{$options{rule}->{change}}) { - next if (!defined($change->{change_str}) || $change->{change_str} eq '' || - !defined($change->{change_regexp}) || $change->{change_regexp} eq '' || - $change->{change_str} =~ /\@SERVICENAME\@/); - - if ($change->{change_str} !~ /\$(.+?)\$/) { - $options{logger}->writeLogError("$options{logger_pre_message} -> not a valid change configuration"); - next; - } - my $attr = $1; - if (!defined($options{discovery_svc}->{attributes}->{$attr})) { - $options{logger}->writeLogError("$options{logger_pre_message} -> change: '$attr' not exist in XML"); - next; - } - - eval "\$options{discovery_svc}->{attributes}->{\$attr} =~ s{$change->{change_regexp}}{$change->{change_replace}}$change->{change_modifier}"; - } - } - - $options{discovery_svc}->{service_name} = substitute_vars( - value => $options{rule}->{service_display_name}, - service_name => $options{discovery_svc}->{service_name}, - attributes => $options{discovery_svc}->{attributes} - ); - - if (defined($options{rule}->{change})) { - # Second pass for service_name now - foreach my $change (@{$options{rule}->{change}}) { - next if (!defined($change->{change_str}) || $change->{change_str} eq '' || - !defined($change->{change_regexp}) || $change->{change_regexp} eq '' || - $change->{change_str} !~ /\@SERVICENAME\@/); - eval "\$options{discovery_svc}->{service_name} =~ s{$change->{change_regexp}}{$change->{change_replace}}$change->{change_modifier}"; - } - } -} - -sub substitute_vars { - my (%options) = @_; - - my $value = $options{value}; - while ($value =~ /\$(.+?)\$/) { - my ($substitute_str, $macro) = ('', $1); - $substitute_str = $options{attributes}->{$macro} if (defined($options{attributes}->{$macro})); - $value =~ s/\$\Q$macro\E\$/$substitute_str/g; - } - $value =~ s/\@SERVICENAME\@/$options{service_name}/g; - return $value; -} - -sub change_bytes { - my (%options) = @_; - my $divide = defined($options{network}) ? 1000 : 1024; - my @units = ('K', 'M', 'G', 'T'); - my $unit = ''; - - for (my $i = 0; $i < scalar(@units); $i++) { - last if (($options{value} / $divide) < 1); - $unit = $units[$i]; - $options{value} = $options{value} / $divide; - } - - return (sprintf("%.2f", $options{value}), $unit . (defined($options{network}) ? 'b' : 'B')); -} - -sub check_exinc { - my (%options) = @_; - - return 0 if (!defined($options{rule}->{exinc})); - foreach my $exinc (@{$options{rule}->{exinc}}) { - next if (!defined($exinc->{exinc_str}) || $exinc->{exinc_str} eq ''); - my $value = substitute_vars( - value => $exinc->{exinc_str}, - service_name => $options{discovery_svc}->{service_name}, - attributes => $options{discovery_svc}->{attributes} - ); - if ($exinc->{exinc_type} == 1 && $value =~ /$exinc->{exinc_regexp}/) { - $options{logger}->writeLogDebug("$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> inclusion '$exinc->{exinc_regexp}'"); - return 0; - } elsif ($exinc->{exinc_type} == 0 && $value =~ /$exinc->{exinc_regexp}/) { - $options{logger}->writeLogDebug("$options{logger_pre_message} [" . $options{discovery_svc}->{service_name} . "] -> exclusion '$exinc->{exinc_regexp}'"); - return 1; - } - } - - return 0; -} - -sub get_macros { - my (%options) = @_; - my $macros = {}; - - return $macros if (!defined($options{rule}->{macro})); - foreach my $macro (keys %{$options{rule}->{macro}}) { - $macros->{$macro} = substitute_vars( - value => $options{rule}->{macro}->{$macro}->{macro_value}, - service_name => $options{discovery_svc}->{service_name}, - attributes => $options{discovery_svc}->{attributes} - ); - } - - return $macros; -} - -sub get_service { - my (%options) = @_; - - my $service; - my ($status, $datas) = $options{class_object_centreon}->custom_execute( - request => 'SELECT service_id, service_template_model_stm_id, service_activate, svc_macro_name, svc_macro_value FROM host, host_service_relation, service LEFT JOIN on_demand_macro_service ON on_demand_macro_service.svc_svc_id = service.service_id WHERE host_id = ' . $options{host_id} . - " AND host.host_id = host_service_relation.host_host_id AND host_service_relation.service_service_id = service.service_id AND service.service_description = ?", - bind_values => [$options{service_name}], - mode => 2 - ); - if ($status == -1) { - $options{logger}->writeLogError("$options{logger_pre_message} [" . $options{service_name} . "] -> cannot check service in configuration"); - return 1; - } - - foreach (@$datas) { - $service = { - id => $_->[0], - template_id => $_->[1], - activate => $_->[2], - macros => {} - } if (!defined($service->{id})); - if (defined($_->[3])) { - $service->{macros}->{ $_->[3] } = $_->[4]; - } - } - - return (0, $service); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/engine/class.pm b/centreon-gorgone/gorgone/modules/centreon/engine/class.pm deleted file mode 100644 index 178092a33e..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/engine/class.pm +++ /dev/null @@ -1,317 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::engine::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use JSON::XS; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{timeout} = defined($connector->{config}->{timeout}) ? $connector->{config}->{timeout} : 5; - - $connector->set_signal_handlers; - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogInfo("[engine] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub action_enginecommand { - my ($self, %options) = @_; - - my $command_file = ''; - if (defined($options{data}->{content}->{command_file}) && $options{data}->{content}->{command_file} ne '') { - $command_file = $options{data}->{content}->{command_file}; - } elsif (defined($self->{config}->{command_file}) && $self->{config}->{command_file} ne '') { - $command_file = $self->{config}->{command_file}; - } - - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "commands processing has started", - request_content => $options{data}->{content} - } - ); - - if (!defined($command_file) || $command_file eq '') { - $self->{logger}->writeLogError("[engine] Need command_file (config or call) argument"); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "need command_file (config or call) argument" - } - ); - return -1; - } - if (! -e $command_file) { - $self->{logger}->writeLogError("[engine] Command file '$command_file' must exist"); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command file '$command_file' must exist" - } - ); - return -1; - } - if (! -p $command_file) { - $self->{logger}->writeLogError("[engine] Command file '$command_file' must be a pipe file"); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command file '$command_file' must be a pipe file" - } - ); - return -1; - } - if (! -w $command_file) { - $self->{logger}->writeLogError("[engine] Command file '$command_file' must be writeable"); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command file '$command_file' must be writeable" - } - ); - return -1; - } - - my $fh; - eval { - local $SIG{ALRM} = sub { die 'Timeout command' }; - alarm $self->{timeout}; - open($fh, ">", $command_file) or die "cannot open '$command_file': $!"; - - foreach my $command (@{$options{data}->{content}->{commands}}) { - $self->{logger}->writeLogInfo("[engine] Processing external command '" . $command . "'"); - print $fh $command . "\n"; - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command has been submitted", - command => $command - } - ); - } - - close $fh; - alarm 0; - }; - if ($@) { - close $fh if (defined($fh)); - $self->{logger}->writeLogError("[engine] Submit engine command issue: $@"); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "submit engine command issue: $@" - } - ); - return -1 - } - - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "commands processing has finished" - } - ); - - return 0; -} - -sub action_run { - my ($self, %options) = @_; - - my $context; - { - local $SIG{__DIE__}; - $context = ZMQ::FFI->new(); - } - - my $socket_log = gorgone::standard::library::connect_com( - context => $context, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-engine-'. $$, - logger => $self->{logger}, - zmq_linger => 60000, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - - if ($options{action} eq 'ENGINECOMMAND') { - $self->action_enginecommand(%options, socket_log => $socket_log); - } else { - $self->send_log( - socket => $socket_log, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'action unknown' } - ); - return -1; - } - - $socket_log->close(); -} - -sub create_child { - my ($self, %options) = @_; - - $options{message} =~ /^\[(.*?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)$/m; - - my ($action, $token) = ($1, $2); - my ($rv, $data) = $self->json_decode(argument => $3, token => $token); - return undef if ($rv); - - if ($action =~ /^BCAST.*/) { - if ((my $method = $self->can('action_' . lc($action)))) { - $method->($self, token => $token, data => $data); - } - return undef; - } - - $self->{logger}->writeLogDebug('[engine] Create sub-process'); - my $child_pid = fork(); - if (!defined($child_pid)) { - $self->{logger}->writeLogError("[engine] Cannot fork process: $!"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { message => "cannot fork: $!" } - ); - return undef; - } - - if ($child_pid == 0) { - $self->set_fork(); - $self->action_run(action => $action, token => $token, data => $data); - exit(0); - } -} - -sub event { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($message) = $self->read_message(); - next if (!defined($message)); - - $self->{logger}->writeLogDebug("[engine] Event: $message"); - - if ($message !~ /^\[ACK\]/) { - $self->create_child(message => $message); - } - } -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[engine] $$ has quit"); - exit(0); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-engine', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'ENGINEREADY', - data => {} - }); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/engine/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/engine/hooks.pm deleted file mode 100644 index ef402d9b0b..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/engine/hooks.pm +++ /dev/null @@ -1,154 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::engine::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::standard::constants qw(:all); -use gorgone::modules::centreon::engine::class; - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'engine'; -use constant EVENTS => [ - { event => 'ENGINEREADY' }, - { event => 'ENGINECOMMAND', uri => '/command', method => 'POST' } -]; - -my $config_core; -my $config; -my $engine = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config->{command_file} = defined($config->{command_file}) ? $config->{command_file} : '/var/lib/centreon-engine/rw/centengine.cmd'; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'ENGINEREADY') { - $engine->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$engine->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { msg => 'gorgoneengine: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-engine', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($engine->{running}) && $engine->{running} == 1) { - $options{logger}->writeLogDebug("[engine] Send TERM signal $engine->{pid}"); - CORE::kill('TERM', $engine->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($engine->{running} == 1) { - $options{logger}->writeLogDebug("[engine] Send KILL signal for pool"); - CORE::kill('KILL', $engine->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($engine->{pid}) || $engine->{pid} != $pid); - - $engine = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($engine->{running}) && $engine->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[engine] Create module 'engine' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-engine'; - my $module = gorgone::modules::centreon::engine::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[engine] PID $child_pid (gorgone-engine)"); - $engine = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/judge/class.pm b/centreon-gorgone/gorgone/modules/centreon/judge/class.pm deleted file mode 100644 index 45fc4b23f6..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/judge/class.pm +++ /dev/null @@ -1,576 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::judge::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::class::db; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use JSON::XS; -use gorgone::modules::centreon::judge::type::distribute; -use gorgone::modules::centreon::judge::type::spare; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{timeout} = 600; - $connector->{check_alive_sync} = defined($connector->{config}->{check_alive}) && $connector->{config}->{check_alive} =~ /(\d+)/ ? $1 : 60; - $connector->{check_alive_last} = -1; - $connector->{check_alive} = 0; - - $connector->{cache_dir} = (defined($connector->{config}->{cache_dir}) && $connector->{config}->{cache_dir} ne '') ? - $connector->{config}->{cache_dir} : '/var/cache/centreon'; - - $connector->check_config(); - $connector->set_signal_handlers(); - return $connector; -} - -sub check_config { - my ($self, %options) = @_; - - $self->{clusters_spare} = {}; - $self->{clusters_distribute} = {}; - $self->{nodes} = {}; - if (defined($self->{config}->{cluster})) { - foreach (@{$self->{config}->{cluster}}) { - if (!defined($_->{name}) || $_->{name} eq '') { - $self->{logger}->writeLogError('[judge] -class- missing name for cluster in config'); - next; - } - - if (!defined($_->{type}) || $_->{type} !~ /distribute|spare/) { - $self->{logger}->writeLogError('[judge] -class- missing/unknown type for cluster in config'); - next; - } - - my $config; - if ($_->{type} =~ /(distribute)/) { - $config = gorgone::modules::centreon::judge::type::distribute::check_config(config => $_, logger => $self->{logger}); - } elsif ($_->{type} =~ /(spare)/) { - $config = gorgone::modules::centreon::judge::type::spare::check_config(config => $_, logger => $self->{logger}); - } - - next if (!defined($config)); - - $self->{'clusters_' . $1}->{$_->{name}} = $config; - - foreach (@{$config->{nodes}}) { - $self->{nodes}->{$_} = {}; - } - $self->{nodes}->{ $config->{spare} } = {} if (defined($config->{spare})); - } - } -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[judge] -class- $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub get_pollers_config { - my ($self, %options) = @_; - - $self->{pollers_config} = {}; - my ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => 'SELECT nagios_server_id, command_file, cfg_dir, centreonbroker_cfg_path, snmp_trapd_path_conf, ' . - 'engine_start_command, engine_stop_command, engine_restart_command, engine_reload_command, ' . - 'broker_reload_command, init_script_centreontrapd ' . - 'FROM cfg_nagios ' . - 'JOIN nagios_server ' . - 'WHERE id = nagios_server_id', - mode => 1, - keys => 'nagios_server_id' - ); - if ($status == -1 || !defined($datas)) { - $self->{logger}->writeLogError('[judge] -class- cannot get configuration for pollers'); - return -1; - } - - $self->{pollers_config} = $datas; - - return 0; -} - -sub get_clapi_user { - my ($self, %options) = @_; - - $self->{clapi_user} = $self->{config}->{clapi_user}; - $self->{clapi_password} = $self->{config}->{clapi_password}; - - if (!defined($self->{clapi_password})) { - $self->{logger}->writeLogError('[judge] -class- cannot get configuration for CLAPI user'); - return -1; - } - - return 0; - -=pod - $self->{clapi_user} = undef; - $self->{clapi_password} = undef; - my ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => "SELECT contact_alias, contact_passwd " . - "FROM `contact` " . - "WHERE `contact_admin` = '1' " . - "AND `contact_activate` = '1' " . - "AND `contact_passwd` IS NOT NULL " . - "LIMIT 1 ", - mode => 2 - ); - - if ($status == -1 || !defined($datas->[0]->[0])) { - $self->{logger}->writeLogError('[judge] -class- cannot get configuration for CLAPI user'); - return -1; - } - - my $clapi_user = $datas->[0]->[0]; - my $clapi_password = $datas->[0]->[1]; - if ($clapi_password =~ m/^md5__(.*)/) { - $clapi_password = $1; - } - - $self->{clapi_user} = $clapi_user; - $self->{clapi_password} = $clapi_password; -=cut - - return 0; -} - -sub action_judgemove { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - # { content => { cluster_name => 'moncluster', node_move => 2 } } - - return -1 if (!defined($options{data}->{content}->{cluster_name}) || $options{data}->{content}->{cluster_name} eq ''); - return -1 if (!defined($options{data}->{content}->{node_move}) || $options{data}->{content}->{node_move} eq ''); - - $self->send_log( - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - data => { message => 'failover start' } - ); - - if (!defined($self->{clusters_spare}->{ $options{data}->{content}->{cluster_name} })) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "unknown cluster_name '" . $options{data}->{content}->{cluster_name} . "' in config" } - ); - return -1; - } - - my $node_configured = 0; - foreach (@{$self->{clusters_spare}->{ $options{data}->{content}->{cluster_name} }->{nodes}}) { - if ($_ eq $options{data}->{content}->{node_move}) { - $node_configured = 1; - last; - } - } - if ($node_configured == 0) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "unknown node '" . $options{data}->{content}->{node_move} . "' in cluster config" } - ); - return -1; - } - - $self->check_alive(); - if ($self->{check_alive} == 0) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'cannot check cluster nodes status' } - ); - return -1; - } - - if (!gorgone::modules::centreon::judge::type::spare::is_ready_status(status => $self->{clusters_spare}->{ $options{data}->{content}->{cluster_name} }->{live}->{status})) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'cluster status not ready to move' } - ); - return -1; - } - if (!gorgone::modules::centreon::judge::type::spare::is_spare_ready(module => $self, ctime => time(), cluster => $self->{clusters_spare}->{ $options{data}->{content}->{cluster_name} })) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'cluster spare not ready' } - ); - return -1; - } - - gorgone::modules::centreon::judge::type::spare::migrate_steps_1_2_3( - token => $options{token}, - module => $self, - node_src => $options{data}->{content}->{node_move}, - cluster => $options{data}->{content}->{cluster_name}, - clusters => $self->{clusters_spare}, - no_update_running_failed => 1 - ); - - return 0; -} - -sub action_judgefailback { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - # { content => { cluster_name => 'moncluster' } } - - return -1 if (!defined($options{data}->{content}->{cluster_name}) || $options{data}->{content}->{cluster_name} eq ''); - - $self->send_log( - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - data => { message => 'failback start' } - ); - - if (!defined($self->{clusters_spare}->{ $options{data}->{content}->{cluster_name} })) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "unknown cluster_name '" . $options{data}->{content}->{cluster_name} . "' in config" } - ); - return -1; - } - - $self->check_alive(); - if ($self->{check_alive} == 0) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'cannot check cluster nodes status' } - ); - return -1; - } - - if ($self->get_clapi_user() != 0 || - $self->get_pollers_config() != 0) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'cannot get clapi user informations and/or poller config' } - ); - return -1; - } - - if (!gorgone::modules::centreon::judge::type::spare::is_failover_status(status => $self->{clusters_spare}->{ $options{data}->{content}->{cluster_name} }->{live}->{status})) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'cluster status not ready to failback' } - ); - return -1; - } - - gorgone::modules::centreon::judge::type::spare::failback_start( - token => $options{token}, - module => $self, - cluster => $options{data}->{content}->{cluster_name}, - clusters => $self->{clusters_spare} - ); - - return 0; -} - -sub action_judgeclean { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - # { content => { cluster_name => 'moncluster' } } - - return -1 if (!defined($options{data}->{content}->{cluster_name}) || $options{data}->{content}->{cluster_name} eq ''); - - $self->send_log( - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - data => { message => 'clean start' } - ); - - if (!defined($self->{clusters_spare}->{ $options{data}->{content}->{cluster_name} })) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "unknown cluster_name '" . $options{data}->{content}->{cluster_name} . "' in config" } - ); - return -1; - } - - gorgone::modules::centreon::judge::type::spare::clean( - token => $options{token}, - module => $self, - cluster => $options{data}->{content}->{cluster_name}, - clusters => $self->{clusters_spare} - ); - - return 0; -} - -sub action_judgelistener { - my ($self, %options) = @_; - - return 0 if (!defined($options{token})); - - if ($options{token} =~ /^judge-spare##(.*?)##(\d+)##/) { - gorgone::modules::centreon::judge::type::spare::migrate_steps_listener_response( - token => $options{token}, - cluster => $1, - state => $2, - clusters => $self->{clusters_spare}, - module => $self, - code => $options{data}->{code} - ); - } - - return 1; -} - -sub check_alive { - my ($self, %options) = @_; - - return if (time() - $self->{check_alive_sync} < $self->{check_alive_last}); - $self->{check_alive_last} = time(); - $self->{check_alive} = 0; - - my $request = q( - SELECT instances.instance_id, instances.running, instances.last_alive, count(hosts.instance_id) - FROM instances LEFT JOIN hosts ON hosts.instance_id = instances.instance_id AND hosts.enabled = 1 - GROUP BY instances.instance_id - ); - my ($status, $datas) = $self->{class_object_centstorage}->custom_execute( - request => $request, - mode => 2 - ); - if ($status == -1) { - $self->{logger}->writeLogError('[judge] -class- cannot get pollers status'); - return 1; - } - - foreach (@$datas) { - if (defined($self->{nodes}->{ $_->[0] })) { - $self->{nodes}->{ $_->[0] }->{running} = $_->[1]; - $self->{nodes}->{ $_->[0] }->{last_alive} = $_->[2]; - $self->{nodes}->{ $_->[0] }->{count_hosts} = $_->[3]; - } - } - - $self->{check_alive} = 1; -} - -sub add_pipeline_config_reload_poller { - my ($self, %options) = @_; - - my $actions = [ - { - action => 'REMOTECOPY', - target => $options{poller_id}, - timeout => 120, - log_pace => 5, - data => { - content => { - source => $self->{cache_dir} . '/config/engine/' . $options{poller_id}, - destination => $self->{pollers_config}->{ $options{poller_id} }->{cfg_dir} . '/', - cache_dir => $self->{cache_dir}, - owner => 'centreon-engine', - group => 'centreon-engine', - } - } - }, - { - action => 'REMOTECOPY', - target => $options{poller_id}, - timeout => 120, - log_pace => 5, - data => { - content => { - source => $self->{cache_dir} . '/config/broker/' . $options{poller_id}, - destination => $self->{pollers_config}->{ $options{poller_id} }->{centreonbroker_cfg_path} . '/', - cache_dir => $self->{cache_dir}, - owner => 'centreon-broker', - group => 'centreon-broker', - } - } - }, - { - action => 'COMMAND', - target => $options{poller_id}, - timeout => 60, - data => { - content => [ { - command => 'sudo ' . $self->{pollers_config}->{ $options{poller_id} }->{engine_reload_command} - } ] - } - } - ]; - - if (!defined($options{no_generate_config})) { - my $cmd = 'centreon -u ' . $self->{clapi_user} . ' -p ' . $self->{clapi_password} . ' -a POLLERGENERATE -v ' . $options{poller_id}; - unshift @$actions, { - action => 'COMMAND', - data => { - content => [ { - command => $cmd - } ] - } - }; - } - - $self->send_internal_action({ - action => 'ADDPIPELINE', - token => $options{token}, - timeout => $options{pipeline_timeout}, - data => $actions - }); -} - -sub test_types { - my ($self, %options) = @_; - - # we don't test if we cannot do check_alive - return if ($self->{check_alive} == 0); - - # distribute clusters - my $all_pollers = {}; - foreach (values %{$self->{clusters_distribute}}) { - my $pollers = gorgone::modules::centreon::judge::type::distribute::assign(cluster => $_, module => $self); - $all_pollers = { %$pollers, %$all_pollers }; - } - - if (scalar(keys %$all_pollers) > 0 && - $self->get_clapi_user() == 0 && - $self->get_pollers_config() == 0 - ) { - foreach (keys %$all_pollers) { - $self->add_pipeline_config_reload_poller(poller_id => $_); - } - } - - # spare clusters - gorgone::modules::centreon::judge::type::spare::init( - clusters => $self->{clusters_spare}, - module => $self - ); - gorgone::modules::centreon::judge::type::spare::check_migrate( - clusters => $self->{clusters_spare}, - module => $self - ); -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[judge] -class- $$ has quit"); - exit(0); - } - - $connector->check_alive(); - $connector->test_types(); -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-judge', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $connector->send_internal_action({ - action => 'JUDGEREADY', - data => {} - }); - - $self->{db_centstorage} = gorgone::class::db->new( - dsn => $self->{config_db_centstorage}->{dsn}, - user => $self->{config_db_centstorage}->{username}, - password => $self->{config_db_centstorage}->{password}, - force => 2, - logger => $self->{logger} - ); - $self->{db_centreon} = gorgone::class::db->new( - dsn => $self->{config_db_centreon}->{dsn}, - user => $self->{config_db_centreon}->{username}, - password => $self->{config_db_centreon}->{password}, - force => 2, - logger => $self->{logger} - ); - $self->{class_object_centstorage} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centstorage}); - $self->{class_object_centreon} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centreon}); - - $self->{db_gorgone} = gorgone::class::db->new( - type => $self->get_core_config(name => 'gorgone_db_type'), - db => $self->get_core_config(name => 'gorgone_db_name'), - host => $self->get_core_config(name => 'gorgone_db_host'), - port => $self->get_core_config(name => 'gorgone_db_port'), - user => $self->get_core_config(name => 'gorgone_db_user'), - password => $self->get_core_config(name => 'gorgone_db_password'), - force => 2, - logger => $self->{logger} - ); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/judge/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/judge/hooks.pm deleted file mode 100644 index 29154a078d..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/judge/hooks.pm +++ /dev/null @@ -1,161 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::judge::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::centreon::judge::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'judge'; -use constant EVENTS => [ - { event => 'JUDGEREADY' }, - { event => 'JUDGELISTENER' }, - { event => 'JUDGEFAILBACK', uri => '/failback', method => 'POST' }, - { event => 'JUDGEMOVE', uri => '/move', method => 'POST' }, - { event => 'JUDGECLEAN', uri => '/clean', method => 'POST' } -]; - -my $config_core; -my $config; -my ($config_db_centreon, $config_db_centstorage); -my $judge = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centstorage = $options{config_db_centstorage}; - $config_db_centreon = $options{config_db_centreon}; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'JUDGEREADY') { - $judge->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$judge->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-judge: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-judge', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($judge->{running}) && $judge->{running} == 1) { - $options{logger}->writeLogDebug("[judge] Send TERM signal $judge->{pid}"); - CORE::kill('TERM', $judge->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($judge->{running} == 1) { - $options{logger}->writeLogDebug('[judge] Send KILL signal for subprocess'); - CORE::kill('KILL', $judge->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($judge->{pid}) || $judge->{pid} != $pid); - - $judge = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($judge->{running}) && $judge->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[judge] Create module 'judge' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-judge'; - my $module = gorgone::modules::centreon::judge::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - config_db_centreon => $config_db_centreon, - config_db_centstorage => $config_db_centstorage - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[judge] PID $child_pid (gorgone-judge)"); - $judge = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/judge/type/distribute.pm b/centreon-gorgone/gorgone/modules/centreon/judge/type/distribute.pm deleted file mode 100644 index 910c3694c6..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/judge/type/distribute.pm +++ /dev/null @@ -1,117 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::judge::type::distribute; - -use strict; -use warnings; - -sub check_config { - my (%options) = @_; - - my $config = $options{config}; - my $sync = defined($config->{sync}) && $config->{sync} =~ /(\d+)/ ? $1 : 3600; - $config->{sync} = $sync; - $config->{sync_last} = -1; - - if (!defined($config->{sync}) || $config->{hcategory} eq '') { - $options{logger}->writeLogError("[judge] -class- please set hcategory for cluster '" . $config->{name} . "'"); - return undef; - } - - if (!defined($config->{nodes}) || scalar(@{$config->{nodes}}) <= 0) { - $options{logger}->writeLogError("[judge] -class- please set nodes for cluster '" . $config->{name} . "'"); - return undef; - } - - return $config; -} - -sub least_poller_hosts { - my (%options) = @_; - - my $poller_id; - my $lowest_hosts; - my $current_time = time(); - foreach (keys %{$options{module}->{nodes}}) { - next if (!defined($options{module}->{nodes}->{$_}->{running}) || $options{module}->{nodes}->{$_}->{running} == 0); - next if (($current_time - 300) > $options{module}->{nodes}->{$_}->{last_alive}); - - if (!defined($lowest_hosts) || $options{module}->{nodes}->{$_}->{count_hosts} < $lowest_hosts) { - $lowest_hosts = $options{module}->{nodes}->{$_}->{count_hosts}; - $poller_id = $_; - } - } - - if (defined($poller_id)) { - $options{module}->{nodes}->{$_}->{count_hosts}++; - } - return $poller_id; -} - -sub assign { - my (%options) = @_; - - return {} if (time() - $options{cluster}->{sync} < $options{cluster}->{sync_last}); - $options{cluster}->{sync_last} = time(); - - my $request = " - SELECT nhr.host_host_id - FROM hostcategories hc, hostcategories_relation hcr, ns_host_relation nhr, nagios_server ns - WHERE hc.hc_activate = '1' AND hc.hc_name = ? - AND hc.hc_id = hcr.hostcategories_hc_id - AND hcr.host_host_id = nhr.host_host_id - AND nhr.nagios_server_id = ns.id - AND ns.is_default = 1 - AND ns.ns_activate = '0' - "; - my ($status, $datas) = $options{module}->{class_object_centreon}->custom_execute( - request => $request, - bind_values => [$options{cluster}->{hcategory}], - mode => 2 - ); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{cluster}->{name} . "': cannot get hosts"); - return {}; - } - - my $pollers_reload = {}; - foreach (@$datas) { - my $poller_id = least_poller_hosts(module => $options{module}); - if (!defined($poller_id)) { - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{cluster}->{name} . "': cannot find poller for host '$_->[0]'"); - next; - } - - $pollers_reload->{$poller_id} = 1; - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{cluster}->{name} . "': assign host '$_->[0]' --> poller '$poller_id'"); - - ($status) = $options{module}->{class_object_centreon}->custom_execute( - request => "UPDATE `ns_host_relation` SET `nagios_server_id` = $poller_id WHERE `host_host_id` = $_->[0]" - ); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{cluster}->{name} . "': cannot assign host '$_->[0]' --> poller '$poller_id'"); - } - } - - return $pollers_reload; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/judge/type/spare.pm b/centreon-gorgone/gorgone/modules/centreon/judge/type/spare.pm deleted file mode 100644 index 9dc2890796..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/judge/type/spare.pm +++ /dev/null @@ -1,1001 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::judge::type::spare; - -use strict; -use warnings; -use gorgone::standard::constants qw(:all); - -=pod -cluster status: -UNKNOWN_STATUS: module restart when failoverProgress or failbackProgress running -NOTREADY_STATUS: init phase or sqlite issue at beginning -READY_STATUS: cluster can migrate -FAILOVER_RUNNING_STATUS -FAILOVER_FAIL_STATUS -FAILOVER_SUCCESS_STATUS -FAILBACK_RUNNING_STATUS -FAILBACK_FAIL_STATUS -FAILBACK_SUCCESS_STATUS - -migrate step: -1) update gorgone sqlite status = FAILOVER_RUNNING_STATUS (state = STATE_MIGRATION_UPDATE_SQLITE) -2) change centreon DB poller configuration (state = STATE_MIGRATION_UPDATE_CENTREON_DB) -3) generate config files for 2 configuration (listener on 2 clapi commands) (state = STATE_MIGRATION_GENERATE_CONFIGS) -4) push config/reload poller failed (listener on a pipeline) (state = STATE_MIGRATION_POLLER_FAILED) (continue even if it's failed) -5) push config/reload poller spare (listener on a pipeline) (state = STATE_MIGRATION_POLLER_SPARE) -6) update 'running' poller failed in centreon DB (state = STATE_MIGRATION_UPDATE_RUNNING_POLLER_FAILED) - -timeout on each step of a pipeline (default: 600 seconds) (finish and get an error if we have a listener on global pipeline token) -timeout on listener (default: 600 seconds). Need to set a listener value higher than each steps - -=cut - -use constant UNKNOWN_STATUS => -2; -use constant NOTREADY_STATUS => -1; -use constant READY_STATUS => 0; -use constant FAILOVER_RUNNING_STATUS => 1; -use constant FAILOVER_FAIL_STATUS => 2; -use constant FAILOVER_SUCCESS_STATUS => 3; -use constant FAILBACK_RUNNING_STATUS => 10; -use constant FAILBACK_FAIL_STATUS => 11; -use constant FAILBACK_SUCCESS_STATUS => 12; - -use constant STATE_MIGRATION_UPDATE_SQLITE => 1; -use constant STATE_MIGRATION_UPDATE_CENTREON_DB => 2; -use constant STATE_MIGRATION_GENERATE_CONFIGS => 3; -use constant STATE_MIGRATION_POLLER_FAILED => 4; -use constant STATE_MIGRATION_POLLER_SPARE => 5; -use constant STATE_MIGRATION_UPDATE_RUNNING_POLLER_FAILED => 6; - -use constant STATE_FAILBACK_GET_SQLITE => 10; -use constant STATE_FAILBACK_UPDATE_CENTREON_DB => 11; -use constant STATE_FAILBACK_GENERATE_CONFIGS => 12; -use constant STATE_FAILBACK_POLLER_SRC => 13; -use constant STATE_FAILBACK_POLLER_DST => 14; - -sub check_config { - my (%options) = @_; - - my $config = $options{config}; - if (!defined($config->{nodes}) || scalar(@{$config->{nodes}}) <= 0) { - $options{logger}->writeLogError("[judge] -class- please set nodes for cluster '" . $config->{name} . "'"); - return undef; - } - if (!defined($config->{spare})) { - $options{logger}->writeLogError("[judge] -class- please set spare for cluster '" . $config->{name} . "'"); - return undef; - } - - $config->{alive_timeout} = defined($config->{alive_timeout}) && $config->{alive_timeout} =~ /(\d+)/ ? $1 : 600; - $config->{live} = { status => NOTREADY_STATUS }; - - return $config; -} - -sub init { - my (%options) = @_; - - foreach (keys %{$options{clusters}}) { - next if ($options{clusters}->{$_}->{live}->{status} != NOTREADY_STATUS); - - my ($status, $sth) = $options{module}->{db_gorgone}->query({ - query => 'SELECT `status` FROM gorgone_centreon_judge_spare WHERE cluster_name = ?', - bind_values => [$options{clusters}->{$_}->{name}] - }); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- sqlite error to get cluster information '" . $options{clusters}->{$_}->{name} . "': cannot select"); - next; - } - - if (my $row = $sth->fetchrow_hashref()) { - $options{clusters}->{$_}->{live}->{status} = $row->{status}; - } else { - ($status) = $options{module}->{db_gorgone}->query({ - query => 'INSERT INTO gorgone_centreon_judge_spare (`cluster_name`, `status`) VALUES (?, ' . READY_STATUS . ')', - bind_values => [$options{clusters}->{$_}->{name}] - }); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- sqlite error to get cluster information '" . $options{clusters}->{$_}->{name} . "': cannot insert"); - next; - } - $options{clusters}->{$_}->{live}->{status} = READY_STATUS; - } - - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{$_}->{name} . "' init status is " . $options{clusters}->{$_}->{live}->{status}); - } -} - -sub send_log { - my (%options) = @_; - - $options{module}->send_log( - code => $options{code}, - token => defined($options{token}) ? $options{token} : $options{live}->{token}, - data => defined($options{data}) ? $options{data} : $options{live} - ); -} - -sub is_ready_status { - my (%options) = @_; - - if ($options{status} == READY_STATUS) { - return 1; - } - - return 0; -} - -sub is_failover_status { - my (%options) = @_; - - if ($options{status} == FAILOVER_FAIL_STATUS || $options{status} == FAILOVER_SUCCESS_STATUS) { - return 1; - } - - return 0; -} - -sub is_spare_ready { - my (%options) = @_; - - if (!defined($options{module}->{nodes}->{ $options{cluster}->{spare} }->{running}) || - $options{module}->{nodes}->{ $options{cluster}->{spare} }->{running} == 0 || - ($options{ctime} - $options{cluster}->{alive_timeout}) > $options{module}->{nodes}->{ $options{cluster}->{spare} }->{last_alive} - ) { - return 0; - } - - return 1; -} - -sub update_status { - my (%options) = @_; - - my ($status) = $options{module}->{db_gorgone}->query({ - query => 'UPDATE gorgone_centreon_judge_spare SET `status` = ' . $options{status} . ' WHERE `cluster_name` = ?', - bind_values => [$options{cluster}] - }); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{cluster} . "' step $options{step}: cannot update status"); - return -1; - } - - return 0; -} - -sub check_migrate { - my (%options) = @_; - - my $ctime = time(); - foreach (keys %{$options{clusters}}) { - next if ($options{clusters}->{$_}->{live}->{status} != READY_STATUS); - - if (!is_spare_ready(module => $options{module}, cluster => $options{clusters}->{$_}, ctime => $ctime)) { - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{$_}->{name} . "' cannot migrate - spare poller not alive"); - next; - } - - my $node_src; - foreach my $node_id (@{$options{clusters}->{$_}->{nodes}}) { - if (defined($options{module}->{nodes}->{$node_id}->{running}) && $options{module}->{nodes}->{$node_id}->{running} == 1 && - (($ctime - $options{clusters}->{$_}->{alive_timeout}) > $options{module}->{nodes}->{$node_id}->{last_alive}) - ) { - $node_src = $node_id; - last; - } - } - - if (defined($node_src)) { - my $token = $options{module}->generate_token(); - send_log( - module => $options{module}, - code => GORGONE_ACTION_BEGIN, - token => $token, - data => { message => 'failover start' } - ); - migrate_steps_1_2_3( - token => $options{token}, - module => $options{module}, - node_src => $node_src, - clusters => $options{clusters}, - cluster => $_ - ); - } - } -} - -sub clean { - my (%options) = @_; - - $options{clusters}->{ $options{cluster} }->{live}->{status} = READY_STATUS; - if (update_status( - module => $options{module}, - cluster => $options{cluster}, - status => READY_STATUS, - step => 'clean' - ) == -1) { - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'clean: cannot update status' } - ); - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' clean: cannot update status"); - return -1; - } - - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' clean: status updated"); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { message => 'clean: status updated' } - ); - return 0; -} - -=pod - -********************** -Failover migrate steps -********************** - -=cut - -sub migrate_steps_1_2_3 { - my (%options) = @_; - - $options{clusters}->{ $options{cluster} }->{live}->{token} = $options{token}; - $options{clusters}->{ $options{cluster} }->{live}->{status} = FAILOVER_RUNNING_STATUS; - $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_failed} = undef; - $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_spare} = undef; - $options{clusters}->{ $options{cluster} }->{live}->{token_config_responses} = 0; - $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_failed} = undef; - $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_spare} = undef; - $options{clusters}->{ $options{cluster} }->{live}->{node_src} = $options{node_src}; - $options{clusters}->{ $options{cluster} }->{live}->{node_dst} = $options{clusters}->{ $options{cluster} }->{token_config_node_spare}; - $options{clusters}->{ $options{cluster} }->{live}->{no_update_running_failed} = $options{no_update_running_failed}; - $options{clusters}->{ $options{cluster} }->{live}->{state} = undef; - - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILOVER_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - if ($options{module}->get_clapi_user() != 0 || - $options{module}->get_pollers_config() != 0) { - $options{clusters}->{ $options{cluster} }->{live}->{status} = READY_STATUS; - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'cannot get clapi user informations and/or poller config' } - ); - return -1; - } - - my ($status, $datas) = $options{module}->{class_object_centreon}->custom_execute( - request => 'SELECT host_host_id ' . - 'FROM ns_host_relation ' . - 'WHERE nagios_server_id = ?', - bind_values => [$options{node_src}], - mode => 2 - ); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' cannot get hosts associated --> poller $options{node_src}"); - $options{clusters}->{ $options{cluster} }->{live}->{status} = READY_STATUS; - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'cannot get hosts associated with source poller' } - ); - return -1; - } - if (scalar(@$datas) <= 0) { - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' no hosts associated --> poller $options{node_src}"); - $options{clusters}->{ $options{cluster} }->{live}->{status} = READY_STATUS; - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_OK, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'nothing done - no hosts associated with source poller' } - ); - return 0; - } - - ######## - # Step 1 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_SQLITE started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_MIGRATION_UPDATE_SQLITE; - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILOVER_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - my $data = { node_src => $options{node_src}, hosts => [] }; - push @{$data->{hosts}}, $_->[0] foreach (@$datas); - ($status, my $encoded) = $options{module}->json_encode( - argument => $data, - method => "-class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_SQLITE" - ); - if ($status == 1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_SQLITE: cannot encode json"); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'cannot encode json' } - ); - return -1; - } - - ($status) = $options{module}->{db_gorgone}->query({ - query => 'UPDATE gorgone_centreon_judge_spare SET `status` = ' . FAILOVER_RUNNING_STATUS . ', `data` = ? WHERE `cluster_name` = ?', - bind_values => [$encoded, $options{cluster}] - }); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_SQLITE: cannot update sqlite"); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'cannot update sqlite' } - ); - return -1; - } - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_SQLITE finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 2 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_CENTREON_DB started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_MIGRATION_UPDATE_CENTREON_DB; - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILOVER_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - ($status) = $options{module}->{class_object_centreon}->custom_execute( - request => 'UPDATE ns_host_relation SET nagios_server_id = ?' . - ' WHERE host_host_id IN (' . join(',', @{$data->{hosts}}) . ')', - bind_values => [$options{clusters}->{ $options{cluster} }->{spare}] - ); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_CENTREON_DB: cannot update database"); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'cannot update database' } - ); - return -1; - } - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_CENTREON_DB finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 3 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_GENERATE_CONFIGS started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_MIGRATION_GENERATE_CONFIGS; - $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_failed} = 'judge-spare##' . $options{clusters}->{ $options{cluster} }->{name} . '##' . STATE_MIGRATION_GENERATE_CONFIGS . '##' . $options{module}->generate_token(length => 8); - $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_spare} = 'judge-spare##' . $options{clusters}->{ $options{cluster} }->{name} . '##' . STATE_MIGRATION_GENERATE_CONFIGS . '##' . $options{module}->generate_token(length => 8); - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILOVER_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - $options{module}->send_internal_action( - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonejudge', - event => 'JUDGELISTENER', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_failed}, - timeout => 200 - } - ] - ); - $options{module}->send_internal_action( - action => 'ADDPIPELINE', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_failed}, - timeout => 180, - data => [ - { - action => 'COMMAND', - timeout => 150, - data => { - content => [ { - command => 'centreon -u ' . $options{module}->{clapi_user} . ' -p ' . $options{module}->{clapi_password} . ' -a POLLERGENERATE -v ' . $options{node_src}, - } ] - } - } - ] - ); - - $options{module}->send_internal_action( - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonejudge', - event => 'JUDGELISTENER', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_spare}, - timeout => 200 - } - ] - ); - $options{module}->send_internal_action( - action => 'ADDPIPELINE', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_spare}, - timeout => 180, - data => [ - { - action => 'COMMAND', - timeout => 150, - data => { - content => [ { - command => 'centreon -u ' . $options{module}->{clapi_user} . ' -p ' . $options{module}->{clapi_password} . ' -a POLLERGENERATE -v ' . $options{clusters}->{ $options{cluster} }->{spare}, - } ] - } - } - ] - ); - - return 0; -} - -sub migrate_step_3 { - my (%options) = @_; - - return 0 if ($options{code} != GORGONE_ACTION_FINISH_KO && $options{code} != GORGONE_ACTION_FINISH_OK); - return 0 if ($options{token} ne $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_failed} && - $options{token} ne $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_spare}); - - if ($options{code} == GORGONE_ACTION_FINISH_KO) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_GENERATE_CONFIGS: generate config error"); - $options{clusters}->{ $options{cluster} }->{live}->{status} = FAILOVER_FAIL_STATUS; - update_status( - module => $options{module}, - cluster => $options{cluster}, - status => FAILOVER_FAIL_STATUS, - step => 'STATE_MIGRATION_GENERATE_CONFIGS' - ); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'generate config error' } - ); - return -1; - } - - $options{clusters}->{ $options{cluster} }->{live}->{token_config_responses}++; - if ($options{clusters}->{ $options{cluster} }->{live}->{token_config_responses} < 2) { - return 0; - } - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_GENERATE_CONFIGS finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 4 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_POLLER_FAILED started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_MIGRATION_POLLER_FAILED; - $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_failed} = 'judge-spare##' . $options{clusters}->{ $options{cluster} }->{name} . '##' . STATE_MIGRATION_POLLER_FAILED . '##' . $options{module}->generate_token(length => 8); - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILOVER_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - $options{module}->send_internal_action( - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonejudge', - event => 'JUDGELISTENER', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_failed}, - timeout => 450 - } - ] - ); - $options{module}->add_pipeline_config_reload_poller( - token => $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_failed}, - poller_id => $options{clusters}->{ $options{cluster} }->{live}->{node_src}, - no_generate_config => 1, - pipeline_timeout => 400 - ); - - return 0; -} - -sub migrate_step_4 { - my (%options) = @_; - - return 0 if ($options{code} != GORGONE_ACTION_FINISH_KO && $options{code} != GORGONE_ACTION_FINISH_OK); - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_POLLER_FAILED finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 5 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_POLLER_SPARE started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_MIGRATION_POLLER_SPARE; - $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_spare} = 'judge-spare##' . $options{clusters}->{ $options{cluster} }->{name} . '##' . STATE_MIGRATION_POLLER_SPARE . '##' . $options{module}->generate_token(length => 8); - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILOVER_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - $options{module}->send_internal_action( - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonejudge', - event => 'JUDGELISTENER', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_spare}, - timeout => 450 - } - ] - ); - $options{module}->add_pipeline_config_reload_poller( - token => $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_spare}, - poller_id => $options{clusters}->{ $options{cluster} }->{spare}, - no_generate_config => 1, - pipeline_timeout => 400 - ); -} - -sub migrate_step_5 { - my (%options) = @_; - - return 0 if ($options{code} != GORGONE_ACTION_FINISH_KO && $options{code} != GORGONE_ACTION_FINISH_OK); - - if ($options{code} == GORGONE_ACTION_FINISH_KO) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_POLLER_SPARE: pipeline error"); - $options{clusters}->{ $options{cluster} }->{status} = FAILOVER_FAIL_STATUS; - update_status( - module => $options{module}, - cluster => $options{cluster}, - status => FAILOVER_FAIL_STATUS, - step => 'STATE_MIGRATION_POLLER_SPARE' - ); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'pipeline error' } - ); - return -1; - } - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_POLLER_SPARE finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 6 - ######## - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_MIGRATION_UPDATE_RUNNING_POLLER_FAILED; - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILOVER_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - if (!defined($options{clusters}->{ $options{cluster} }->{live}->{no_update_running_failed}) || - $options{clusters}->{ $options{cluster} }->{live}->{no_update_running_failed} != 1) { - my ($status) = $options{module}->{class_object_centstorage}->custom_execute( - request => 'UPDATE instances SET running = 0 ' . - ' WHERE instance_id = ?', - bind_values => [$options{clusters}->{ $options{cluster} }->{live}->{node_src}] - ); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_MIGRATION_UPDATE_RUNNING_POLLER_FAILED: cannot update database"); - } - } - - $options{clusters}->{ $options{cluster} }->{live}->{status} = FAILOVER_SUCCESS_STATUS; - update_status( - module => $options{module}, - cluster => $options{cluster}, - status => FAILOVER_SUCCESS_STATUS, - step => 'STATE_MIGRATION_POLLER_SPARE' - ); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_OK, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'failover finished' } - ); - - return 0; -} -sub migrate_steps_listener_response { - my (%options) = @_; - - return -1 if (!defined($options{clusters}->{ $options{cluster} })); - if ($options{state} != $options{clusters}->{ $options{cluster} }->{live}->{state}) { - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' wrong or old step responce received"); - return -1; - } - - if ($options{state} == STATE_MIGRATION_GENERATE_CONFIGS) { - return migrate_step_3(%options); - } - if ($options{state} == STATE_MIGRATION_POLLER_FAILED) { - return migrate_step_4(%options); - } - if ($options{state} == STATE_MIGRATION_POLLER_SPARE) { - return migrate_step_5(%options); - } - - if ($options{state} == STATE_FAILBACK_GENERATE_CONFIGS) { - return failback_generate_configs(%options); - } - if ($options{state} == STATE_FAILBACK_POLLER_SRC) { - return failback_poller_src(%options); - } - if ($options{state} == STATE_FAILBACK_POLLER_DST) { - return failback_poller_dst(%options); - } -} - -=pod - -********************** -Failback migrate steps -********************** - -=cut - -sub failback_start { - my (%options) = @_; - - $options{clusters}->{ $options{cluster} }->{live}->{token} = $options{token}; - $options{clusters}->{ $options{cluster} }->{live}->{status} = FAILBACK_RUNNING_STATUS; - $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_src} = undef; - $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_dst} = undef; - $options{clusters}->{ $options{cluster} }->{live}->{token_config_responses} = 0; - $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_src} = undef; - $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_dst} = undef; - $options{clusters}->{ $options{cluster} }->{live}->{node_src} = $options{clusters}->{ $options{cluster} }->{spare}; - $options{clusters}->{ $options{cluster} }->{live}->{node_dst} = undef; - - ######## - # Step 1 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_GET_SQLITE started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_FAILBACK_GET_SQLITE; - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILBACK_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - my ($status, $sth) = $options{module}->{db_gorgone}->query({ - query => 'SELECT `status`, `data` FROM gorgone_centreon_judge_spare WHERE cluster_name = ?', - bind_values => [$options{clusters}->{ $options{cluster} }->{name}] - }); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' cannot get sqlite information"); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'cannot get sqlite information' } - ); - return -1; - } - my $row = $sth->fetchrow_hashref(); - if (!defined($row)) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' no data in sqlite"); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'no data in sqlite' } - ); - return -1; - } - ($status, my $decoded) = $options{module}->json_decode( - argument => $row->{data}, - method => "-class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' cannot decode json information" - ); - if ($status == 1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' cannot decode json"); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'cannot decode json' } - ); - return -1; - } - - $options{clusters}->{ $options{cluster} }->{live}->{node_dst} = $decoded->{node_src}; - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_GET_SQLITE finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 2 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_UPDATE_CENTREON_DB started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_FAILBACK_UPDATE_CENTREON_DB; - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILBACK_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - ($status) = $options{module}->{class_object_centreon}->custom_execute( - request => 'UPDATE ns_host_relation SET nagios_server_id = ?' . - ' WHERE host_host_id IN (' . join(',', @{$decoded->{hosts}}) . ')', - bind_values => [$options{clusters}->{ $options{cluster} }->{live}->{node_dst}] - ); - if ($status == -1) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_UPDATE_CENTREON_DB: cannot update database"); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'cannot update database' } - ); - return -1; - } - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_UPDATE_CENTREON_DB finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 3 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_GENERATE_CONFIGS started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_FAILBACK_GENERATE_CONFIGS; - $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_src} = 'judge-spare##' . $options{clusters}->{ $options{cluster} }->{name} . '##' . STATE_FAILBACK_GENERATE_CONFIGS . '##' . $options{module}->generate_token(length => 8); - $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_dst} = 'judge-spare##' . $options{clusters}->{ $options{cluster} }->{name} . '##' . STATE_FAILBACK_GENERATE_CONFIGS . '##' . $options{module}->generate_token(length => 8); - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILBACK_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - $options{module}->send_internal_action( - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonejudge', - event => 'JUDGELISTENER', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_src}, - timeout => 200 - } - ] - ); - $options{module}->send_internal_action( - action => 'ADDPIPELINE', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_src}, - timeout => 180, - data => [ - { - action => 'COMMAND', - timeout => 150, - data => { - content => [ { - command => 'centreon -u ' . $options{module}->{clapi_user} . ' -p ' . $options{module}->{clapi_password} . ' -a POLLERGENERATE -v ' . $options{clusters}->{ $options{cluster} }->{live}->{node_src} - } ] - } - } - ] - ); - - $options{module}->send_internal_action( - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonejudge', - event => 'JUDGELISTENER', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_dst}, - timeout => 200 - } - ] - ); - $options{module}->send_internal_action( - action => 'ADDPIPELINE', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_dst}, - timeout => 180, - data => [ - { - action => 'COMMAND', - timeout => 150, - data => { - content => [ { - command => 'centreon -u ' . $options{module}->{clapi_user} . ' -p ' . $options{module}->{clapi_password} . ' -a POLLERGENERATE -v ' . $options{clusters}->{ $options{cluster} }->{live}->{node_dst} - } ] - } - } - ] - ); - - return 0; -} - -sub failback_generate_configs { - my (%options) = @_; - - return 0 if ($options{code} != GORGONE_ACTION_FINISH_KO && $options{code} != GORGONE_ACTION_FINISH_OK); - return 0 if ($options{token} ne $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_src} && - $options{token} ne $options{clusters}->{ $options{cluster} }->{live}->{token_config_node_dst}); - - if ($options{code} == GORGONE_ACTION_FINISH_KO) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_GENERATE_CONFIGS: generate config error"); - $options{clusters}->{ $options{cluster} }->{live}->{status} = FAILBACK_FAIL_STATUS; - update_status( - module => $options{module}, - cluster => $options{cluster}, - status => FAILBACK_FAIL_STATUS, - step => 'STATE_FAILBACK_GENERATE_CONFIGS' - ); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'generate config error' } - ); - return -1; - } - - $options{clusters}->{ $options{cluster} }->{live}->{token_config_responses}++; - if ($options{clusters}->{ $options{cluster} }->{live}->{token_config_responses} < 2) { - return 0; - } - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_GENERATE_CONFIGS finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 4 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_POLLER_SRC started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_FAILBACK_POLLER_SRC; - $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_src} = 'judge-spare##' . $options{clusters}->{ $options{cluster} }->{name} . '##' . STATE_FAILBACK_POLLER_SRC . '##' . $options{module}->generate_token(length => 8); - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILBACK_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - $options{module}->send_internal_action( - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonejudge', - event => 'JUDGELISTENER', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_src}, - timeout => 450 - } - ] - ); - $options{module}->add_pipeline_config_reload_poller( - token => $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_src}, - poller_id => $options{clusters}->{ $options{cluster} }->{live}->{node_src}, - no_generate_config => 1, - pipeline_timeout => 400 - ); - - return 0; -} - -sub failback_poller_src { - my (%options) = @_; - - return 0 if ($options{code} != GORGONE_ACTION_FINISH_KO && $options{code} != GORGONE_ACTION_FINISH_OK); - - if ($options{code} == GORGONE_ACTION_FINISH_KO) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_POLLER_SRC: pipeline error"); - $options{clusters}->{ $options{cluster} }->{status} = FAILBACK_FAIL_STATUS; - update_status( - module => $options{module}, - cluster => $options{cluster}, - status => FAILBACK_FAIL_STATUS, - step => 'STATE_FAILBACK_POLLER_SRC' - ); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'pipeline error' } - ); - return -1; - } - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_POLLER_SRC finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - ######## - # Step 5 - ######## - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_POLLER_DST started"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{clusters}->{ $options{cluster} }->{live}->{state} = STATE_FAILBACK_POLLER_DST; - $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_dst} = 'judge-spare##' . $options{clusters}->{ $options{cluster} }->{name} . '##' . STATE_FAILBACK_POLLER_DST . '##' . $options{module}->generate_token(length => 8); - send_log(module => $options{module}, code => GORGONE_MODULE_CENTREON_JUDGE_FAILBACK_RUNNING, live => $options{clusters}->{ $options{cluster} }->{live}); - - $options{module}->send_internal_action( - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonejudge', - event => 'JUDGELISTENER', - token => $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_dst}, - timeout => 450 - } - ] - ); - $options{module}->add_pipeline_config_reload_poller( - token => $options{clusters}->{ $options{cluster} }->{live}->{token_pipeline_node_dst}, - poller_id => $options{clusters}->{ $options{cluster} }->{live}->{node_dst}, - no_generate_config => 1, - pipeline_timeout => 400 - ); -} - -sub failback_poller_dst { - my (%options) = @_; - - return 0 if ($options{code} != GORGONE_ACTION_FINISH_KO && $options{code} != GORGONE_ACTION_FINISH_OK); - - if ($options{code} == GORGONE_ACTION_FINISH_KO) { - $options{module}->{logger}->writeLogError("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_POLLER_DST: pipeline error"); - $options{clusters}->{ $options{cluster} }->{status} = FAILBACK_FAIL_STATUS; - update_status( - module => $options{module}, - cluster => $options{cluster}, - status => FAILBACK_FAIL_STATUS, - step => 'STATE_FAILBACK_POLLER_DST' - ); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'pipeline error' } - ); - return -1; - } - - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - $options{module}->{logger}->writeLogInfo("[judge] -class- cluster '" . $options{clusters}->{ $options{cluster} }->{name} . "' step STATE_FAILBACK_POLLER_DST finished"); - $options{module}->{logger}->writeLogInfo('[judge] -class- ************************************'); - - $options{clusters}->{ $options{cluster} }->{live}->{status} = FAILBACK_SUCCESS_STATUS; - update_status( - module => $options{module}, - cluster => $options{cluster}, - status => FAILBACK_SUCCESS_STATUS, - step => 'STATE_FAILBACK_POLLER_DST' - ); - send_log( - module => $options{module}, - code => GORGONE_ACTION_FINISH_OK, - token => $options{clusters}->{ $options{cluster} }->{live}->{token}, - data => { message => 'failback finished' } - ); - - return 0; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/legacycmd/class.pm b/centreon-gorgone/gorgone/modules/centreon/legacycmd/class.pm deleted file mode 100644 index 67d2a2121a..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/legacycmd/class.pm +++ /dev/null @@ -1,831 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::legacycmd::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use gorgone::class::sqlquery; -use gorgone::class::tpapi::clapi; -use File::Copy; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{tpapi_clapi_name} = defined($options{config}->{tpapi_clapi}) && $options{config}->{tpapi_clapi} ne '' - ? $options{config}->{tpapi_clapi} - : 'clapi'; - if (!defined($connector->{config}->{cmd_file}) || $connector->{config}->{cmd_file} eq '') { - $connector->{config}->{cmd_file} = '/var/lib/centreon/centcore.cmd'; - } - if (!defined($connector->{config}->{cmd_dir}) || $connector->{config}->{cmd_dir} eq '') { - $connector->{config}->{cmd_dir} = '/var/lib/centreon/centcore/'; - } - $connector->{config}->{bulk_external_cmd} = - defined($connector->{config}->{bulk_external_cmd}) && $connector->{config}->{bulk_external_cmd} =~ /(\d+)/ ? $1 : 50; - $connector->{config}->{bulk_external_cmd_sequential} = - defined($connector->{config}->{bulk_external_cmd_sequential}) && $connector->{config}->{bulk_external_cmd_sequential} =~ /^False|0$/i ? 0 : 1; - $connector->{config}->{dirty_mode} = defined($connector->{config}->{dirty_mode}) ? $connector->{config}->{dirty_mode} : 1; - $connector->{gorgone_illegal_characters} = '`'; - $connector->{cache_refresh_interval} = 60; - $connector->{cache_refresh_last} = -1; - $connector->{bulk_commands} = {}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[legacycmd] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub cache_refresh { - my ($self, %options) = @_; - - return if ((time() - $self->{cache_refresh_interval}) < $self->{cache_refresh_last}); - $self->{cache_refresh_last} = time(); - - # get pollers config - $self->{pollers} = undef; - my ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => 'SELECT nagios_server_id, command_file, cfg_dir, centreonbroker_cfg_path, snmp_trapd_path_conf, ' . - 'engine_start_command, engine_stop_command, engine_restart_command, engine_reload_command, ' . - 'broker_reload_command, init_script_centreontrapd ' . - 'FROM cfg_nagios, nagios_server ' . - "WHERE nagios_server.id = cfg_nagios.nagios_server_id AND cfg_nagios.nagios_activate = '1'", - mode => 1, - keys => 'nagios_server_id' - ); - if ($status == -1 || !defined($datas)) { - $self->{logger}->writeLogError('[legacycmd] Cannot get configuration for pollers'); - return ; - } - - $self->{pollers} = $datas; - - # check illegal characters - ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => "SELECT `value` FROM options WHERE `key` = 'gorgone_illegal_characters'", - mode => 2 - ); - if ($status == -1) { - $self->{logger}->writeLogError('[legacycmd] Cannot get illegal characters'); - return ; - } - - if (defined($datas->[0]->[0])) { - $self->{gorgone_illegal_characters} = $datas->[0]->[0]; - } -} - -sub check_pollers_config { - my ($self, %options) = @_; - - return defined($self->{pollers}) ? 1 : 0; -} - -sub send_external_commands { - my ($self, %options) = @_; - my $token = $options{token}; - $token = $self->generate_token() if (!defined($token)); - - my $targets = []; - $targets = [$options{target}] if (defined($options{target})); - if (scalar(@$targets) <= 0) { - $targets = [keys %{$self->{bulk_commands}}]; - } - - foreach my $target (@$targets) { - next if (!defined($self->{bulk_commands}->{$target}) || scalar(@{$self->{bulk_commands}->{$target}}) <= 0); - $self->send_internal_action({ - action => 'ENGINECOMMAND', - target => $target, - token => $token, - data => { - logging => $options{logging}, - content => { - command_file => $self->{pollers}->{$target}->{command_file}, - commands => [ - join("\n", @{$self->{bulk_commands}->{$target}}) - ] - } - } - }); - - $self->{logger}->writeLogDebug("[legacycmd] send external commands for '$target'"); - $self->{bulk_commands}->{$target} = []; - } -} - -sub add_external_command { - my ($self, %options) = @_; - - $options{param} =~ s/[\Q$self->{gorgone_illegal_characters}\E]//g - if (defined($self->{gorgone_illegal_characters}) && $self->{gorgone_illegal_characters} ne ''); - if ($options{action} == 1) { - $self->send_internal_action({ - action => 'ENGINECOMMAND', - target => $options{target}, - token => $options{token}, - data => { - logging => $options{logging}, - content => { - command_file => $self->{pollers}->{ $options{target} }->{command_file}, - commands => [ - $options{param} - ] - } - } - }); - } else { - $self->{bulk_commands}->{ $options{target} } = [] if (!defined($self->{bulk_commands}->{ $options{target} })); - push @{$self->{bulk_commands}->{ $options{target} }}, $options{param}; - if (scalar(@{$self->{bulk_commands}->{ $options{target} }}) > $self->{config}->{bulk_external_cmd}) { - $self->send_external_commands(%options); - } - } -} - -sub execute_cmd { - my ($self, %options) = @_; - - chomp $options{target}; - chomp $options{param} if (defined($options{param})); - my $token = $options{token}; - $token = $self->generate_token() if (!defined($token)); - - my $msg = "[legacycmd] Handling command '" . $options{cmd} . "'"; - $msg .= ", Target: '" . $options{target} . "'" if (defined($options{target})); - $msg .= ", Parameters: '" . $options{param} . "'" if (defined($options{param})); - $self->{logger}->writeLogInfo($msg); - - if ($options{cmd} eq 'EXTERNALCMD') { - $self->add_external_command( - action => $options{action}, - param => $options{param}, - target => $options{target}, - token => $options{token}, - logging => $options{logging} - ); - return 0; - } - - $self->send_external_commands(target => $options{target}) - if (defined($options{target}) && $self->{config}->{bulk_external_cmd_sequential} == 1); - - if ($options{cmd} eq 'SENDCFGFILE') { - my $cache_dir = (defined($connector->{config}->{cache_dir}) && $connector->{config}->{cache_dir} ne '') ? - $connector->{config}->{cache_dir} : '/var/cache/centreon'; - # engine - $self->send_internal_action({ - action => 'REMOTECOPY', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => { - source => $cache_dir . '/config/engine/' . $options{target}, - destination => $self->{pollers}->{$options{target}}->{cfg_dir} . '/', - cache_dir => $cache_dir, - owner => 'centreon-engine', - group => 'centreon-engine', - metadata => { - centcore_proxy => 1, - centcore_cmd => 'SENDCFGFILE' - } - } - } - }); - # broker - $self->send_internal_action({ - action => 'REMOTECOPY', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => { - source => $cache_dir . '/config/broker/' . $options{target}, - destination => $self->{pollers}->{$options{target}}->{centreonbroker_cfg_path} . '/', - cache_dir => $cache_dir, - owner => 'centreon-broker', - group => 'centreon-broker', - metadata => { - centcore_proxy => 1, - centcore_cmd => 'SENDCFGFILE' - } - } - } - }); - } elsif ($options{cmd} eq 'SENDEXPORTFILE') { - if (!defined($self->{clapi_password})) { - return (-1, 'need centreon clapi password to execute SENDEXPORTFILE command'); - } - - my $cache_dir = (defined($connector->{config}->{cache_dir}) && $connector->{config}->{cache_dir} ne '') ? - $connector->{config}->{cache_dir} : '/var/cache/centreon'; - my $remote_dir = (defined($connector->{config}->{remote_dir})) ? - $connector->{config}->{remote_dir} : '/var/cache/centreon/config/remote-data/'; - # remote server - $self->send_internal_action({ - action => 'REMOTECOPY', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => { - source => $cache_dir . '/config/export/' . $options{target}, - destination => $remote_dir, - cache_dir => $cache_dir, - owner => 'centreon', - group => 'centreon', - metadata => { - centcore_cmd => 'SENDEXPORTFILE' - } - } - } - }); - - # Forward data use to be done by createRemoteTask as well as task_id in a gorgone command - # Command name: AddImportTaskWithParent - # Data: ['parent_id' => $task->getId()] - $self->send_internal_action({ - action => 'ADDIMPORTTASKWITHPARENT', - token => $options{token}, - target => $options{target}, - data => { - logging => $options{logging}, - content => { - parent_id => $options{param}, - cbd_reload => 'sudo ' . $self->{pollers}->{ $options{target} }->{broker_reload_command} - } - } - }); - } elsif ($options{cmd} eq 'SYNCTRAP') { - my $cache_dir = (defined($connector->{config}->{cache_dir}) && $connector->{config}->{cache_dir} ne '') ? - $connector->{config}->{cache_dir} : '/var/cache/centreon'; - my $cache_dir_trap = (defined($connector->{config}->{cache_dir_trap}) && $connector->{config}->{cache_dir_trap} ne '') ? - $connector->{config}->{cache_dir_trap} : '/etc/snmp/centreon_traps/'; - # centreontrapd - $self->send_internal_action({ - action => 'REMOTECOPY', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => { - source => $cache_dir_trap . '/' . $options{target} . '/centreontrapd.sdb', - destination => $self->{pollers}->{$options{target}}->{snmp_trapd_path_conf} . '/', - cache_dir => $cache_dir, - owner => 'centreon', - group => 'centreon', - metadata => { - centcore_proxy => 1, - centcore_cmd => 'SYNCTRAP' - } - } - } - }); - } elsif ($options{cmd} eq 'ENGINERESTART') { - my $cmd = $self->{pollers}->{$options{target}}->{engine_restart_command}; - $self->send_internal_action({ - action => 'ACTIONENGINE', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => { - command => 'sudo ' . $cmd, - plugins => $self->{pollers}->{ $options{target} }->{cfg_dir} . '/plugins.json', - metadata => { - centcore_proxy => 1, - centcore_cmd => 'ENGINERESTART' - } - } - } - }); - } elsif ($options{cmd} eq 'RESTART') { - my $cmd = $self->{pollers}->{$options{target}}->{engine_restart_command}; - $self->send_internal_action({ - action => 'COMMAND', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => [ - { - command => 'sudo ' . $cmd, - metadata => { - centcore_proxy => 1, - centcore_cmd => 'RESTART' - } - } - ] - } - }); - } elsif ($options{cmd} eq 'ENGINERELOAD') { - my $cmd = $self->{pollers}->{ $options{target} }->{engine_reload_command}; - $self->send_internal_action({ - action => 'ACTIONENGINE', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => { - command => 'sudo ' . $cmd, - plugins => $self->{pollers}->{ $options{target} }->{cfg_dir} . '/plugins.json', - metadata => { - centcore_proxy => 1, - centcore_cmd => 'ENGINERELOAD' - } - } - } - }); - } elsif ($options{cmd} eq 'RELOAD') { - my $cmd = $self->{pollers}->{$options{target}}->{engine_reload_command}; - $self->send_internal_action({ - action => 'COMMAND', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => [ - { - command => 'sudo ' . $cmd, - metadata => { - centcore_proxy => 1, - centcore_cmd => 'RELOAD' - } - } - ] - } - }); - } elsif ($options{cmd} eq 'START') { - my $cmd = $self->{pollers}->{$options{target}}->{engine_start_command}; - $self->send_internal_action({ - action => 'COMMAND', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => [ - { - command => 'sudo ' . $cmd, - metadata => { - centcore_proxy => 1, - centcore_cmd => 'START' - } - } - ] - } - }); - } elsif ($options{cmd} eq 'STOP') { - my $cmd = $self->{pollers}->{$options{target}}->{engine_stop_command}; - $self->send_internal_action({ - action => 'COMMAND', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => [ - { - command => 'sudo ' . $cmd, - metadata => { - centcore_proxy => 1, - centcore_cmd => 'STOP' - } - } - ] - } - }); - } elsif ($options{cmd} eq 'RELOADBROKER') { - my $cmd = $self->{pollers}->{$options{target}}->{broker_reload_command}; - $self->send_internal_action({ - action => 'COMMAND', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => [ - { - command => 'sudo ' . $cmd, - metadata => { - centcore_proxy => 1, - centcore_cmd => 'RELOADBROKER' - } - } - ] - } - }); - } elsif ($options{cmd} eq 'RESTARTCENTREONTRAPD') { - my $cmd = $self->{pollers}->{$options{target}}->{init_script_centreontrapd}; - $self->send_internal_action({ - action => 'COMMAND', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => [ - { - command => 'sudo service ' . $cmd . ' restart', - metadata => { - centcore_proxy => 1, - centcore_cmd => 'RESTARTCENTREONTRAPD' - } - } - ] - } - }); - } elsif ($options{cmd} eq 'RELOADCENTREONTRAPD') { - my $cmd = $self->{pollers}->{$options{target}}->{init_script_centreontrapd}; - $self->send_internal_action({ - action => 'COMMAND', - target => $options{target}, - token => $token, - data => { - logging => $options{logging}, - content => [ - { - command => 'sudo service ' . $cmd . ' reload', - metadata => { - centcore_proxy => 1, - centcore_cmd => 'RELOADCENTREONTRAPD' - } - } - ] - } - }); - } elsif ($options{cmd} eq 'STARTWORKER') { - if (!defined($self->{clapi_password})) { - return (-1, 'need centreon clapi password to execute STARTWORKER command'); - } - my $centreon_dir = (defined($connector->{config}->{centreon_dir})) ? - $connector->{config}->{centreon_dir} : '/usr/share/centreon'; - my $cmd = $centreon_dir . '/bin/centreon -u "' . $self->{clapi_user} . '" -p "' . - $self->{clapi_password} . '" -w -o CentreonWorker -a processQueue'; - $self->send_internal_action({ - action => 'COMMAND', - target => undef, - token => $token, - data => { - logging => $options{logging}, - content => [ - { - command => $cmd, - metadata => { - centcore_cmd => 'STARTWORKER' - } - } - ] - } - }); - } - - return 0; -} - -sub action_addimporttaskwithparent { - my ($self, %options) = @_; - - if (!defined($options{data}->{content}->{parent_id})) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "expected parent_id task ID, found '" . $options{data}->{content}->{parent_id} . "'", - } - ); - return -1; - } - - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time()); - my $datetime = sprintf('%04d-%02d-%02d %02d:%02d:%02d', $year+1900, $mon+1, $mday, $hour, $min, $sec); - - my ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => "INSERT INTO task (`type`, `status`, `parent_id`, `created_at`) VALUES ('import', 'pending', '" . $options{data}->{content}->{parent_id} . "', '" . $datetime . "')" - ); - if ($status == -1) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "Cannot add import task on Remote Server.", - } - ); - return -1; - } - - my $centreon_dir = (defined($connector->{config}->{centreon_dir})) ? - $connector->{config}->{centreon_dir} : '/usr/share/centreon'; - my $cmd = $centreon_dir . '/bin/centreon -u "' . $self->{clapi_user} . '" -p "' . - $self->{clapi_password} . '" -w -o CentreonWorker -a processQueue'; - $self->send_internal_action({ - action => 'COMMAND', - token => $options{token}, - data => { - logging => $options{data}->{logging}, - content => [ - { - command => $cmd - } - ], - parameters => { no_fork => 1 } - } - }); - $self->send_internal_action({ - action => 'COMMAND', - token => $options{token}, - data => { - logging => $options{data}->{logging}, - content => [ - { - command => $options{data}->{content}->{cbd_reload} - } - ] - } - }); - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => 'Task inserted on Remote Server', - } - ); - - return 0; -} - -sub move_cmd_file { - my ($self, %options) = @_; - - my $operator = '+<'; - if ($self->{config}->{dirty_mode} == 1) { - $operator = '<'; - } - my $handle; - if (-e $options{dst}) { - if (!open($handle, $operator, $options{dst})) { - $self->{logger}->writeLogError("[legacycmd] Cannot open file '" . $options{dst} . "': $!"); - return -1; - } - - return (0, $handle); - } - - return -1 if (!defined($options{src})); - return -1 if (! -e $options{src}); - - if (!File::Copy::move($options{src}, $options{dst})) { - $self->{logger}->writeLogError("[legacycmd] Cannot move file '" . $options{src} . "': $!"); - return -1; - } - - if (!open($handle, $operator, $options{dst})) { - $self->{logger}->writeLogError("[legacycmd] Cannot open file '" . $options{dst} . "': $!"); - return -1; - } - - return (0, $handle); -} - -sub handle_file { - my ($self, %options) = @_; - require bytes; - - $self->{logger}->writeLogDebug("[legacycmd] Processing file '" . $options{file} . "'"); - my $handle = $options{handle}; - while (my $line = <$handle>) { - if ($self->{stop} == 1) { - close($handle); - return -1; - } - - if ($line =~ /^(.*?):([^:]*)(?::(.*)){0,1}/) { - $self->execute_cmd(action => 0, cmd => $1, target => $2, param => $3, logging => 0); - if ($self->{config}->{dirty_mode} != 1) { - my $current_pos = tell($handle); - seek($handle, $current_pos - bytes::length($line), 0); - syswrite($handle, '-'); - # line is useless - $line = <$handle>; - } - } - } - - close($handle); - unlink($options{file}); - return 0; -} - -sub handle_centcore_cmd { - my ($self, %options) = @_; - - my ($code, $handle) = $self->move_cmd_file( - src => $self->{config}->{cmd_file}, - dst => $self->{config}->{cmd_file} . '_read', - ); - return if ($code == -1); - $self->handle_file(handle => $handle, file => $self->{config}->{cmd_file} . '_read'); -} - -sub handle_centcore_dir { - my ($self, %options) = @_; - - my ($dh, @files); - if (!opendir($dh, $self->{config}->{cmd_dir})) { - $self->{logger}->writeLogError("[legacycmd] Cannot open directory '" . $self->{config}->{cmd_dir} . "': $!"); - return ; - } - @files = sort { - (stat($self->{config}->{cmd_dir} . '/' . $a))[10] <=> (stat($self->{config}->{cmd_dir} . '/' . $b))[10] - } (readdir($dh)); - closedir($dh); - - my ($code, $handle); - foreach (@files) { - next if ($_ =~ /^\./); - my $file = $self->{config}->{cmd_dir} . '/' . $_; - if ($file =~ /_read$/) { - ($code, $handle) = $self->move_cmd_file( - dst => $file, - ); - } else { - ($code, $handle) = $self->move_cmd_file( - src => $file, - dst => $file . '_read', - ); - $file .= '_read'; - } - return if ($code == -1); - if ($self->handle_file(handle => $handle, file => $file) == -1) { - return ; - } - } -} - -sub handle_cmd_files { - my ($self, %options) = @_; - - return if ($self->check_pollers_config() == 0); - $self->handle_centcore_cmd(); - $self->handle_centcore_dir(); - $self->send_external_commands(logging => 0); -} - -sub action_centreoncommand { - my ($self, %options) = @_; - - $self->{logger}->writeLogDebug('[legacycmd] -class- start centreoncommand'); - $options{token} = $self->generate_token() if (!defined($options{token})); - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action centreoncommand proceed' }); - - if (!defined($options{data}->{content}) || ref($options{data}->{content}) ne 'ARRAY') { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => "expected array, found '" . ref($options{data}->{content}) . "'", - } - ); - return -1; - } - - if ($self->check_pollers_config() == 0) { - $self->{logger}->writeLogError('[legacycmd] cannot get centreon database configuration'); - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get centreon database configuration' }); - return 1; - } - - foreach my $command (@{$options{data}->{content}}) { - my ($code, $message) = $self->execute_cmd( - action => 1, - token => $options{token}, - target => $command->{target}, - cmd => $command->{command}, - param => $command->{param}, - logging => 1 - ); - - if ($code == -1) { - $self->{logger}->writeLogError('[legacycmd] -class- ' . $message); - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => $message }); - return 1; - } - } - - $self->{logger}->writeLogDebug('[legacycmd] -class- finish centreoncommand'); - return 0; -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[legacycmd] $$ has quit"); - exit(0); - } - - $connector->cache_refresh(); - $connector->handle_cmd_files(); -} - -sub run { - my ($self, %options) = @_; - - $self->{tpapi_clapi} = gorgone::class::tpapi::clapi->new(); - $self->{tpapi_clapi}->set_configuration( - config => $self->{tpapi}->get_configuration(name => $self->{tpapi_clapi_name}) - ); - - $self->{clapi_user} = $self->{tpapi_clapi}->get_username(); - $self->{clapi_password} = $self->{tpapi_clapi}->get_password(protected => 1); - - # Connect internal - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-legacycmd', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'LEGACYCMDREADY', - data => {} - }); - - $self->{db_centreon} = gorgone::class::db->new( - dsn => $self->{config_db_centreon}->{dsn}, - user => $self->{config_db_centreon}->{username}, - password => $self->{config_db_centreon}->{password}, - force => 2, - logger => $self->{logger} - ); - $self->{class_object_centreon} = gorgone::class::sqlquery->new( - logger => $self->{logger}, - db_centreon => $self->{db_centreon} - ); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/legacycmd/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/legacycmd/hooks.pm deleted file mode 100644 index 25636686c3..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/legacycmd/hooks.pm +++ /dev/null @@ -1,162 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::legacycmd::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::centreon::legacycmd::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'legacycmd'; -use constant EVENTS => [ - { event => 'CENTREONCOMMAND', uri => '/command', method => 'POST' }, - { event => 'LEGACYCMDREADY' }, - { event => 'ADDIMPORTTASKWITHPARENT' } -]; - -my $config_core; -my $config; -my $legacycmd = {}; -my $stop = 0; -my $config_db_centreon; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centreon = $options{config_db_centreon}; - $config->{cmd_file} = defined($config->{cmd_file}) ? $config->{cmd_file} : '/var/lib/centreon/centcore.cmd'; - $config->{cache_dir} = defined($config->{cache_dir}) ? $config->{cache_dir} : '/var/cache/centreon/'; - $config->{cache_dir_trap} = defined($config->{cache_dir_trap}) ? $config->{cache_dir_trap} : '/etc/snmp/centreon_traps/'; - $config->{remote_dir} = defined($config->{remote_dir}) ? $config->{remote_dir} : '/var/lib/centreon/remote-data/'; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'LEGACYCMDREADY') { - $legacycmd->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$legacycmd->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-legacycmd: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-legacycmd', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($legacycmd->{running}) && $legacycmd->{running} == 1) { - $options{logger}->writeLogDebug("[legacycmd] Send TERM signal $legacycmd->{running}"); - CORE::kill('TERM', $legacycmd->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($legacycmd->{running} == 1) { - $options{logger}->writeLogDebug("[legacycmd] Send KILL signal for pool"); - CORE::kill('KILL', $legacycmd->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($legacycmd->{pid}) || $legacycmd->{pid} != $pid); - - $legacycmd = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($legacycmd->{running}) && $legacycmd->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[legacycmd] Create module 'legacycmd' process"); - - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-legacycmd'; - my $module = gorgone::modules::centreon::legacycmd::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - config_db_centreon => $config_db_centreon, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[legacycmd] PID $child_pid (gorgone-legacycmd)"); - $legacycmd = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/class.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etl/class.pm deleted file mode 100644 index 420342fcc2..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/class.pm +++ /dev/null @@ -1,879 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etl::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::sqlquery; -use gorgone::class::http::http; -use XML::LibXML::Simple; -use JSON::XS; -use gorgone::modules::centreon::mbi::libs::Messages; -use gorgone::modules::centreon::mbi::etl::import::main; -use gorgone::modules::centreon::mbi::etl::event::main; -use gorgone::modules::centreon::mbi::etl::perfdata::main; -use gorgone::modules::centreon::mbi::libs::centreon::ETLProperties; -use Try::Tiny; -use EV; - -use constant NONE => 0; -use constant RUNNING => 1; -use constant STOP => 2; - -use constant NOTDONE => 0; -use constant DONE => 1; - -use constant UNPLANNED => -1; -use constant PLANNED => 0; -#use constant RUNNING => 1; -use constant FINISHED => 2; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{cbis_profile} = (defined($connector->{config}->{cbis_profile}) && $connector->{config}->{cbis_profile} ne '') ? - $connector->{config}->{cbis_profile} : '/etc/centreon-bi/cbis-profile.xml'; - $connector->{reports_profile} = (defined($connector->{config}->{reports_profile}) && $connector->{config}->{reports_profile} ne '') ? - $connector->{config}->{reports_profile} : '/etc/centreon-bi/reports-profile.xml'; - - $connector->{run} = { status => NONE }; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[nodes] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub reset { - my ($self, %options) = @_; - - $self->{run} = { status => NONE }; -} - -sub runko { - my ($self, %options) = @_; - - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => defined($options{token}) ? $options{token} : $self->{run}->{token}, - data => { - messages => [ ['E', $options{msg} ] ] - } - ); - - $self->check_stopped_ko(); - return 1; -} - -sub db_parse_xml { - my ($self, %options) = @_; - - my ($rv, $message, $content) = gorgone::standard::misc::slurp(file => $options{file}); - return (0, $message) if (!$rv); - eval { - $SIG{__WARN__} = sub {}; - $content = XMLin($content, ForceArray => [], KeyAttr => []); - }; - if ($@) { - die 'cannot read xml file: ' . $@; - } - - my $dbcon = {}; - if (!defined($content->{profile})) { - die 'no profile'; - } - foreach my $profile (@{$content->{profile}}) { - my $name = lc($profile->{name}); - $name =~ s/censtorage/centstorage/; - $dbcon->{$name} = { port => 3306 }; - foreach my $prop (@{$profile->{baseproperties}->{property}}) { - if ($prop->{name} eq 'odaURL' && $prop->{value} =~ /jdbc\:[a-z]+\:\/\/([^:]*)(\:\d+)?\/(.*)/) { - $dbcon->{$name}->{host} = $1; - $dbcon->{$name}->{db} = $3; - if (defined($2) && $2 ne '') { - $dbcon->{$name}->{port} = $2; - $dbcon->{$name}->{port} =~ s/\://; - } - $dbcon->{$name}->{db} =~ s/\?autoReconnect\=true//; - } elsif ($prop->{name} eq 'odaUser') { - $dbcon->{$name}->{user} = $prop->{value}; - } elsif ($prop->{name} eq 'odaPassword') { - $dbcon->{$name}->{password} = $prop->{value}; - } - } - } - foreach my $profile ('centreon', 'centstorage') { - die 'cannot find profile ' . $profile if (!defined($dbcon->{$profile})); - foreach ('host', 'db', 'port', 'user', 'password') { - die "property $_ for profile $profile must be defined" - if (!defined($dbcon->{$profile}->{$_}) || $dbcon->{$profile}->{$_} eq ''); - } - } - - return $dbcon; -} - -sub execute_action { - my ($self, %options) = @_; - - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgone-' . $self->{module_id}, - event => 'CENTREONMBIETLLISTENER', - token => $self->{module_id} . '-' . $self->{run}->{token} . '-' . $options{substep}, - timeout => 43200 - } - ] - }); - - my $content = { - dbmon => $self->{run}->{dbmon}, - dbbi => $self->{run}->{dbbi}, - params => $options{params} - }; - if (defined($options{etlProperties})) { - $content->{etlProperties} = $self->{run}->{etlProperties}; - } - if (defined($options{dataRetention})) { - $content->{dataRetention} = $self->{run}->{dataRetention}; - } - if (defined($options{options})) { - $content->{options} = $self->{run}->{options}; - } - - $self->send_internal_action({ - action => $options{action}, - token => $self->{module_id} . '-' . $self->{run}->{token} . '-' . $options{substep}, - data => { - instant => 1, - content => $content - } - }); -} - -sub watch_etl_event { - my ($self, %options) = @_; - - if (defined($options{indexes})) { - $self->{run}->{schedule}->{event}->{substeps_executed}++; - my ($idx, $idx2) = split(/-/, $options{indexes}); - $self->{run}->{schedule}->{event}->{stages}->[$idx]->[$idx2]->{status} = FINISHED; - } - - return if (!$self->check_stopped_ko()); - - if ($self->{run}->{schedule}->{event}->{substeps_executed} >= $self->{run}->{schedule}->{event}->{substeps_total}) { - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][EVENT] <<<<<<< end'] ] }); - $self->{run}->{schedule}->{event}->{status} = FINISHED; - $self->check_stopped_ok(); - return ; - } - - my $stage = $self->{run}->{schedule}->{event}->{current_stage}; - my $stage_finished = 0; - while ($stage <= 2) { - while (my ($idx, $val) = each(@{$self->{run}->{schedule}->{event}->{stages}->[$stage]})) { - if (!defined($val->{status})) { - $self->{logger}->writeLogDebug("[mbi-etl] execute substep event-$stage-$idx"); - $self->{run}->{schedule}->{event}->{substeps_execute}++; - $self->execute_action( - action => 'CENTREONMBIETLWORKERSEVENT', - substep => "event-$stage-$idx", - etlProperties => 1, - options => 1, - params => $self->{run}->{schedule}->{event}->{stages}->[$stage]->[$idx] - ); - $self->{run}->{schedule}->{event}->{stages}->[$stage]->[$idx]->{status} = RUNNING; - } elsif ($val->{status} == FINISHED) { - $stage_finished++; - } - } - - if ($stage_finished >= scalar(@{$self->{run}->{schedule}->{event}->{stages}->[$stage]})) { - $self->{run}->{schedule}->{event}->{current_stage}++; - $stage = $self->{run}->{schedule}->{event}->{current_stage}; - } else { - last; - } - } -} - -sub watch_etl_perfdata { - my ($self, %options) = @_; - - if (defined($options{indexes})) { - $self->{run}->{schedule}->{perfdata}->{substeps_executed}++; - my ($idx, $idx2) = split(/-/, $options{indexes}); - $self->{run}->{schedule}->{perfdata}->{stages}->[$idx]->[$idx2]->{status} = FINISHED; - } - - return if (!$self->check_stopped_ko()); - - if ($self->{run}->{schedule}->{perfdata}->{substeps_executed} >= $self->{run}->{schedule}->{perfdata}->{substeps_total}) { - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][PERFDATA] <<<<<<< end'] ] }); - $self->{run}->{schedule}->{perfdata}->{status} = FINISHED; - $self->check_stopped_ok(); - return ; - } - - my $stage = $self->{run}->{schedule}->{perfdata}->{current_stage}; - my $stage_finished = 0; - while ($stage <= 2) { - while (my ($idx, $val) = each(@{$self->{run}->{schedule}->{perfdata}->{stages}->[$stage]})) { - if (!defined($val->{status})) { - $self->{logger}->writeLogDebug("[mbi-etl] execute substep perfdata-$stage-$idx"); - $self->{run}->{schedule}->{perfdata}->{substeps_execute}++; - $self->execute_action( - action => 'CENTREONMBIETLWORKERSPERFDATA', - substep => "perfdata-$stage-$idx", - etlProperties => 1, - options => 1, - params => $self->{run}->{schedule}->{perfdata}->{stages}->[$stage]->[$idx] - ); - $self->{run}->{schedule}->{perfdata}->{stages}->[$stage]->[$idx]->{status} = RUNNING; - } elsif ($val->{status} == FINISHED) { - $stage_finished++; - } - } - - if ($stage_finished >= scalar(@{$self->{run}->{schedule}->{perfdata}->{stages}->[$stage]})) { - $self->{run}->{schedule}->{perfdata}->{current_stage}++; - $stage = $self->{run}->{schedule}->{perfdata}->{current_stage}; - } else { - last; - } - } -} - -sub watch_etl_dimensions { - my ($self, %options) = @_; - - if (defined($options{indexes})) { - $self->{run}->{schedule}->{dimensions}->{substeps_executed}++; - } - - return if (!$self->check_stopped_ko()); - - if ($self->{run}->{schedule}->{dimensions}->{substeps_executed} >= $self->{run}->{schedule}->{dimensions}->{substeps_total}) { - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][DIMENSIONS] <<<<<<< end'] ] }); - $self->{run}->{schedule}->{dimensions}->{status} = FINISHED; - $self->run_etl(); - $self->check_stopped_ok(); - return ; - } - - $self->{run}->{schedule}->{dimensions}->{substeps_execute}++; - $self->execute_action( - action => 'CENTREONMBIETLWORKERSDIMENSIONS', - substep => 'dimensions-1', - etlProperties => 1, - options => 1, - params => {} - ); -} - -sub watch_etl_import { - my ($self, %options) = @_; - - if (defined($options{indexes})) { - $self->{run}->{schedule}->{import}->{substeps_executed}++; - my ($idx, $idx2) = split(/-/, $options{indexes}); - if (defined($idx) && defined($idx2)) { - $self->{run}->{schedule}->{import}->{actions}->[$idx]->{actions}->[$idx2]->{status} = FINISHED; - } else { - $self->{run}->{schedule}->{import}->{actions}->[$idx]->{status} = FINISHED; - } - } - - return if (!$self->check_stopped_ko()); - - if ($self->{run}->{schedule}->{import}->{substeps_executed} >= $self->{run}->{schedule}->{import}->{substeps_total}) { - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][IMPORT] <<<<<<< end'] ] }); - $self->{run}->{schedule}->{import}->{status} = FINISHED; - $self->run_etl(); - $self->check_stopped_ok(); - return ; - } - - while (my ($idx, $val) = each(@{$self->{run}->{schedule}->{import}->{actions}})) { - if (!defined($val->{status})) { - $self->{logger}->writeLogDebug("[mbi-etl] execute substep import-$idx"); - $self->{run}->{schedule}->{import}->{substeps_execute}++; - $self->{run}->{schedule}->{import}->{actions}->[$idx]->{status} = RUNNING; - $self->execute_action( - action => 'CENTREONMBIETLWORKERSIMPORT', - substep => "import-$idx", - params => { - type => $val->{type}, - db => $val->{db}, - sql => $val->{sql}, - command => $val->{command}, - message => $val->{message} - } - ); - } elsif ($val->{status} == FINISHED) { - while (my ($idx2, $val2) = each(@{$val->{actions}})) { - next if (defined($val2->{status})); - - $self->{logger}->writeLogDebug("[mbi-etl] execute substep import-$idx-$idx2"); - $self->{run}->{schedule}->{import}->{substeps_execute}++; - $self->{run}->{schedule}->{import}->{actions}->[$idx]->{actions}->[$idx2]->{status} = RUNNING; - $self->execute_action( - action => 'CENTREONMBIETLWORKERSIMPORT', - substep => "import-$idx-$idx2", - params => $val2 - ); - } - } - } -} - -sub run_etl_import { - my ($self, %options) = @_; - - if ((defined($self->{run}->{etlProperties}->{'host.dedicated'}) && $self->{run}->{etlProperties}->{'host.dedicated'} eq 'false') - || ($self->{run}->{dbbi}->{centstorage}->{host} . ':' . $self->{run}->{dbbi}->{centstorage}->{port} eq $self->{run}->{dbmon}->{centstorage}->{host} . ':' . $self->{run}->{dbmon}->{centstorage}->{port}) - || ($self->{run}->{dbbi}->{centreon}->{host} . ':' . $self->{run}->{dbbi}->{centreon}->{port} eq $self->{run}->{dbmon}->{centreon}->{host} . ':' . $self->{run}->{dbmon}->{centreon}->{port})) { - die 'Do not execute this script if the reporting engine is installed on the monitoring server. In case of "all in one" installation, do not consider this message'; - } - - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][IMPORT] >>>>>>> start' ] ] }); - - gorgone::modules::centreon::mbi::etl::import::main::prepare($self); - - $self->{run}->{schedule}->{import}->{status} = RUNNING; - - $self->{run}->{schedule}->{import}->{substeps_execute} = 0; - $self->{run}->{schedule}->{import}->{substeps_executed} = 0; - $self->{run}->{schedule}->{import}->{substeps_total} = 0; - foreach (@{$self->{run}->{schedule}->{import}->{actions}}) { - $self->{run}->{schedule}->{import}->{substeps_total}++; - my $num = defined($_->{actions}) ? scalar(@{$_->{actions}}) : 0; - $self->{run}->{schedule}->{import}->{substeps_total} += $num if ($num > 0); - } - - $self->{logger}->writeLogDebug("[mbi-etl] import substeps " . $self->{run}->{schedule}->{import}->{substeps_total}); - - $self->watch_etl_import(); -} - -sub run_etl_dimensions { - my ($self, %options) = @_; - - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][DIMENSIONS] >>>>>>> start' ] ] }); - $self->{run}->{schedule}->{dimensions}->{status} = RUNNING; - $self->{run}->{schedule}->{dimensions}->{substeps_execute} = 0; - $self->{run}->{schedule}->{dimensions}->{substeps_executed} = 0; - $self->{run}->{schedule}->{dimensions}->{substeps_total} = 1; - $self->watch_etl_dimensions(); -} - -sub run_etl_event { - my ($self, %options) = @_; - - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][EVENT] >>>>>>> start' ] ] }); - - gorgone::modules::centreon::mbi::etl::event::main::prepare($self); - - $self->{run}->{schedule}->{event}->{status} = RUNNING; - $self->{run}->{schedule}->{event}->{current_stage} = 0; - $self->{run}->{schedule}->{event}->{substeps_execute} = 0; - $self->{run}->{schedule}->{event}->{substeps_executed} = 0; - $self->{run}->{schedule}->{event}->{substeps_total} = - scalar(@{$self->{run}->{schedule}->{event}->{stages}->[0]}) + scalar(@{$self->{run}->{schedule}->{event}->{stages}->[1]}) + scalar(@{$self->{run}->{schedule}->{event}->{stages}->[2]}); - - $self->{logger}->writeLogDebug("[mbi-etl] event substeps " . $self->{run}->{schedule}->{event}->{substeps_total}); - - $self->watch_etl_event(); -} - -sub run_etl_perfdata { - my ($self, %options) = @_; - - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][PERFDATA] >>>>>>> start' ] ] }); - - gorgone::modules::centreon::mbi::etl::perfdata::main::prepare($self); - - $self->{run}->{schedule}->{perfdata}->{status} = RUNNING; - $self->{run}->{schedule}->{perfdata}->{current_stage} = 0; - $self->{run}->{schedule}->{perfdata}->{substeps_execute} = 0; - $self->{run}->{schedule}->{perfdata}->{substeps_executed} = 0; - $self->{run}->{schedule}->{perfdata}->{substeps_total} = - scalar(@{$self->{run}->{schedule}->{perfdata}->{stages}->[0]}) + scalar(@{$self->{run}->{schedule}->{perfdata}->{stages}->[1]}) + scalar(@{$self->{run}->{schedule}->{perfdata}->{stages}->[2]}); - - $self->{logger}->writeLogDebug("[mbi-etl] perfdata substeps " . $self->{run}->{schedule}->{perfdata}->{substeps_total}); - - $self->watch_etl_perfdata(); -} - -sub run_etl { - my ($self, %options) = @_; - - if ($self->{run}->{schedule}->{import}->{status} == PLANNED) { - $self->run_etl_import(); - return ; - } elsif ($self->{run}->{schedule}->{dimensions}->{status} == PLANNED) { - $self->run_etl_dimensions(); - return ; - } - if ($self->{run}->{schedule}->{event}->{status} == PLANNED) { - $self->run_etl_event(); - } - if ($self->{run}->{schedule}->{perfdata}->{status} == PLANNED) { - $self->run_etl_perfdata(); - } -} - -sub check_stopped_ko_import { - my ($self, %options) = @_; - - return 0 if ($self->{run}->{schedule}->{import}->{substeps_executed} >= $self->{run}->{schedule}->{import}->{substeps_execute}); - - return 1; -} - -sub check_stopped_ko_dimensions { - my ($self, %options) = @_; - - return 0 if ($self->{run}->{schedule}->{dimensions}->{substeps_executed} >= $self->{run}->{schedule}->{dimensions}->{substeps_execute}); - - return 1; -} - -sub check_stopped_ko_event { - my ($self, %options) = @_; - - return 0 if ($self->{run}->{schedule}->{event}->{substeps_executed} >= $self->{run}->{schedule}->{event}->{substeps_execute}); - - return 1; -} - -sub check_stopped_ko_perfdata { - my ($self, %options) = @_; - - return 0 if ($self->{run}->{schedule}->{perfdata}->{substeps_executed} >= $self->{run}->{schedule}->{perfdata}->{substeps_execute}); - - return 1; -} - -sub check_stopped_ko { - my ($self, %options) = @_; - - # if nothing planned. we stop - if ($self->{run}->{schedule}->{planned} == NOTDONE) { - $self->reset(); - return 0; - } - - return 1 if ($self->{run}->{status} != STOP); - - my $stopped = 0; - $stopped += $self->check_stopped_ko_import() - if ($self->{run}->{schedule}->{import}->{status} == RUNNING); - $stopped += $self->check_stopped_ko_dimensions() - if ($self->{run}->{schedule}->{dimensions}->{status} == RUNNING); - $stopped += $self->check_stopped_ko_event() - if ($self->{run}->{schedule}->{event}->{status} == RUNNING); - $stopped += $self->check_stopped_ko_perfdata() - if ($self->{run}->{schedule}->{perfdata}->{status} == RUNNING); - - if ($stopped == 0) { - $self->reset(); - return 0; - } - - return 1; -} - -sub check_stopped_ok_import { - my ($self, %options) = @_; - - return 0 if ($self->{run}->{schedule}->{import}->{substeps_executed} >= $self->{run}->{schedule}->{import}->{substeps_total}); - - return 1; -} - -sub check_stopped_ok_dimensions { - my ($self, %options) = @_; - - return 0 if ($self->{run}->{schedule}->{dimensions}->{substeps_executed} >= $self->{run}->{schedule}->{dimensions}->{substeps_total}); - - return 1; -} - -sub check_stopped_ok_event { - my ($self, %options) = @_; - - return 0 if ($self->{run}->{schedule}->{event}->{substeps_executed} >= $self->{run}->{schedule}->{event}->{substeps_total}); - - return 1; -} - -sub check_stopped_ok_perfdata { - my ($self, %options) = @_; - - return 0 if ($self->{run}->{schedule}->{perfdata}->{substeps_executed} >= $self->{run}->{schedule}->{perfdata}->{substeps_total}); - - return 1; -} - -sub check_stopped_ok { - my ($self, %options) = @_; - - return 1 if ($self->{run}->{status} == STOP); - - my $stopped = 0; - $stopped += $self->check_stopped_ok_import() - if ($self->{run}->{schedule}->{import}->{status} == RUNNING); - $stopped += $self->check_stopped_ok_dimensions() - if ($self->{run}->{schedule}->{dimensions}->{status} == RUNNING); - $stopped += $self->check_stopped_ok_event() - if ($self->{run}->{schedule}->{event}->{status} == RUNNING); - $stopped += $self->check_stopped_ok_perfdata() - if ($self->{run}->{schedule}->{perfdata}->{status} == RUNNING); - - if ($stopped == 0) { - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $self->{run}->{token}, - data => { - messages => [ ['I', '[SCHEDULER] <<<<<<< end' ] ] - } - ); - $self->reset(); - return 0; - } - - return 1; -} - -sub planning { - my ($self, %options) = @_; - - if ($self->{run}->{options}->{import} == 1) { - $self->{run}->{schedule}->{import}->{status} = PLANNED; - $self->{run}->{schedule}->{steps_total}++; - } - if ($self->{run}->{options}->{dimensions} == 1) { - $self->{run}->{schedule}->{dimensions}->{status} = PLANNED; - $self->{run}->{schedule}->{steps_total}++; - } - if ($self->{run}->{options}->{event} == 1) { - $self->{run}->{schedule}->{event}->{status} = PLANNED; - $self->{run}->{schedule}->{steps_total}++; - } - if ($self->{run}->{options}->{perfdata} == 1) { - $self->{run}->{schedule}->{perfdata}->{status} = PLANNED; - $self->{run}->{schedule}->{steps_total}++; - } - - if ($self->{run}->{schedule}->{steps_total} == 0) { - die "[SCHEDULING] nothing planned"; - } - - $self->{run}->{schedule}->{steps_executed} = 0; - $self->{run}->{schedule}->{planned} = DONE; -} - -sub check_basic_options { - my ($self, %options) = @_; - - if (($options{daily} == 0 && $options{rebuild} == 0 && $options{create_tables} == 0 && !defined($options{centile})) - || ($options{daily} == 1 && $options{rebuild} == 1)) { - die "Specify one execution method"; - } - if (($options{rebuild} == 1 || $options{create_tables} == 1) - && (($options{start} ne '' && $options{end} eq '') - || ($options{start} eq '' && $options{end} ne ''))) { - die "Specify both options start and end or neither of them to use default data retention options"; - } - if ($options{rebuild} == 1 && $options{start} ne '' && $options{end} ne '' - && ($options{start} !~ /[1-2][0-9]{3}\-[0-1][0-9]\-[0-3][0-9]/ || $options{end} !~ /[1-2][0-9]{3}\-[0-1][0-9]\-[0-3][0-9]/)) { - die "Verify period start or end date format"; - } -} - -sub action_centreonmbietlrun { - my ($self, %options) = @_; - - try { - $options{token} = $self->generate_token() if (!defined($options{token})); - - return $self->runko(token => $options{token}, msg => '[SCHEDULER] already running') if ($self->{run}->{status} == RUNNING); - return $self->runko(token => $options{token}, msg => '[SCHEDULER] currently wait previous execution finished - can restart gorgone mbi process') if ($self->{run}->{status} == STOP); - - $self->{run}->{token} = $options{token}; - $self->{run}->{messages} = gorgone::modules::centreon::mbi::libs::Messages->new(); - - $self->check_basic_options(%{$options{data}->{content}}); - - $self->{run}->{schedule} = { - steps_total => 0, - steps_executed => 0, - planned => NOTDONE, - import => { status => UNPLANNED, actions => [] }, - dimensions => { status => UNPLANNED }, - event => { status => UNPLANNED, stages => [ [], [], [] ] }, - perfdata => { status => UNPLANNED, stages => [ [], [], [] ] } - }; - $self->{run}->{status} = RUNNING; - - $self->{run}->{options} = $options{data}->{content}; - - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER] >>>>>>> start' ] ] }); - - $self->{run}->{dbmon} = $self->db_parse_xml(file => $self->{cbis_profile}); - $self->{run}->{dbbi} = $self->db_parse_xml(file => $self->{reports_profile}); - - $self->{run}->{dbmon_centreon_con} = gorgone::class::db->new( - type => 'mysql', - force => 2, - logger => $self->{logger}, - die => 1, - %{$self->{run}->{dbmon}->{centreon}} - ); - $self->{run}->{dbmon_centstorage_con} = gorgone::class::db->new( - type => 'mysql', - force => 2, - logger => $self->{logger}, - die => 1, - %{$self->{run}->{dbmon}->{centstorage}} - ); - $self->{run}->{dbbi_centstorage_con} = gorgone::class::db->new( - type => 'mysql', - force => 2, - logger => $self->{logger}, - die => 1, - %{$self->{run}->{dbbi}->{centstorage}} - ); - - $self->{etlProp} = gorgone::modules::centreon::mbi::libs::centreon::ETLProperties->new($self->{logger}, $self->{run}->{dbmon_centreon_con}); - ($self->{run}->{etlProperties}, $self->{run}->{dataRetention}) = $self->{etlProp}->getProperties(); - - $self->planning(); - $self->run_etl(); - } catch { - $self->runko(msg => $_); - $self->reset(); - }; - - return 0; -} - -sub action_centreonmbietllistener { - my ($self, %options) = @_; - - return 0 if (!defined($options{token}) || $options{token} !~ /^$self->{module_id}-$self->{run}->{token}-(.*?)-(.*)$/); - my ($type, $indexes) = ($1, $2); - - if ($options{data}->{code} == GORGONE_ACTION_FINISH_KO) { - $self->{run}->{status} = STOP; - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $self->{run}->{token}, data => $options{data}->{data}); - } elsif ($options{data}->{code} == GORGONE_ACTION_FINISH_OK) { - $self->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $self->{run}->{token}, data => $options{data}->{data}); - } else { - return 0; - } - - if ($type eq 'import') { - $self->watch_etl_import(indexes => $indexes); - } elsif ($type eq 'dimensions') { - $self->watch_etl_dimensions(indexes => $indexes); - } elsif ($type eq 'event') { - $self->watch_etl_event(indexes => $indexes); - } elsif ($type eq 'perfdata') { - $self->watch_etl_perfdata(indexes => $indexes); - } - - return 1; -} - -sub action_centreonmbietlkill { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - if ($self->{run}->{status} == NONE) { - $self->{logger}->writeLogDebug('[mbi-etl] kill action - etl not running'); - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { - messages => 'etl not running' - } - ); - return 0; - } - - $self->{logger}->writeLogDebug('[mbi-etl] kill sent to the module etlworkers'); - - $self->send_internal_action({ - action => 'KILL', - token => $options{token}, - data => { - content => { - package => 'gorgone::modules::centreon::mbi::etlworkers::hooks' - } - } - }); - - # RUNNING or STOP - $self->send_log( - code => GORGONE_ACTION_CONTINUE, - token => $options{token}, - data => { - messages => 'kill sent to the module etlworkers' - } - ); - - $self->reset(); - - return 0; -} - -sub action_centreonmbietlstatus { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - my $map_etl_status = { - 0 => 'ready', - 1 => 'running', - 2 => 'stopping' - }; - - my $map_planning_status = { - 0 => 'running', - 1 => 'ok' - }; - - my $map_section_status = { - -1 => 'unplanned', - 0 => 'planned', - 1 => 'running', - 2 => 'ok' - }; - - my $section = {}; - foreach ('import', 'dimensions', 'event', 'perfdata') { - next if (!defined($self->{run}->{schedule})); - - $section->{$_} = { - status => $self->{run}->{schedule}->{$_}->{status}, - statusStr => $map_section_status->{ $self->{run}->{schedule}->{$_}->{status} } - }; - if ($self->{run}->{schedule}->{$_}->{status} == RUNNING) { - $section->{$_}->{steps_total} = $self->{run}->{schedule}->{$_}->{substeps_total}; - $section->{$_}->{steps_executed} = $self->{run}->{schedule}->{$_}->{substeps_executed}; - } - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { - token => defined($self->{run}->{token}) ? $self->{run}->{token} : undef, - - status => $self->{run}->{status}, - statusStr => $map_etl_status->{ $self->{run}->{status} }, - - planning => defined($self->{run}->{schedule}->{planned}) ? $self->{run}->{schedule}->{planned} : undef, - planningStr => defined($self->{run}->{schedule}->{planned}) ? $map_planning_status->{ $self->{run}->{schedule}->{planned} } : undef, - - sections => $section - } - ); - - return 0; -} - - - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[" . $connector->{module_id} . "] $$ has quit"); - exit(0); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-' . $self->{module_id}, - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'CENTREONMBIETLREADY', - data => {} - }); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/event/main.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etl/event/main.pm deleted file mode 100644 index 6ccbcc447f..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/event/main.pm +++ /dev/null @@ -1,292 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etl::event::main; - -use strict; -use warnings; - -use gorgone::modules::centreon::mbi::libs::bi::Time; -use gorgone::modules::centreon::mbi::libs::bi::LiveService; -use gorgone::modules::centreon::mbi::libs::bi::MySQLTables; -use gorgone::modules::centreon::mbi::libs::Utils; - -my ($biTables, $utils, $liveService, $time); -my ($start, $end); - -sub initVars { - my ($etl) = @_; - - $biTables = gorgone::modules::centreon::mbi::libs::bi::MySQLTables->new($etl->{run}->{messages}, $etl->{run}->{dbbi_centstorage_con}); - $utils = gorgone::modules::centreon::mbi::libs::Utils->new($etl->{run}->{messages}); - $liveService = gorgone::modules::centreon::mbi::libs::bi::LiveService->new($etl->{run}->{messages}, $etl->{run}->{dbbi_centstorage_con}); - $time = gorgone::modules::centreon::mbi::libs::bi::Time->new($etl->{run}->{messages}, $etl->{run}->{dbbi_centstorage_con}); -} - -sub emptyTableForRebuild { - my ($etl, %options) = @_; - - my $sql = [ [ '[CREATE] Deleting table [' . $options{name} . ']', 'DROP TABLE IF EXISTS `' . $options{name} . '`' ] ]; - - my $structure = $biTables->dumpTableStructure($options{name}); - $structure =~ s/KEY.*\(\`$options{column}\`\)\,//g; - $structure =~ s/KEY.*\(\`$options{column}\`\)//g; - $structure =~ s/\,[\n\s+]+\)/\n\)/g; - - if (defined($options{start})) { - $structure =~ s/\n.*PARTITION.*//g; - $structure =~ s/\,[\n\s]+\)/\)/; - $structure .= ' PARTITION BY RANGE(`' . $options{column} . '`) ('; - - my $partitionsPerf = $utils->getRangePartitionDate($options{start}, $options{end}); - - my $append = ''; - foreach (@$partitionsPerf) { - $structure .= $append . "PARTITION p" . $_->{name} . " VALUES LESS THAN (" . $_->{epoch} . ")"; - $append = ','; - } - $structure .= ');'; - } - - push @$sql, - [ '[CREATE] Add table [' . $options{name} . ']', $structure ], - [ "[INDEXING] Adding index [idx_$options{name}_$options{column}] on table [$options{name}]", "ALTER TABLE `$options{name}` ADD INDEX `idx_$options{name}_$options{column}` (`$options{column}`)" ]; - - push @{$etl->{run}->{schedule}->{event}->{stages}->[0]}, { type => 'sql', db => 'centstorage', sql => $sql }; -} - -sub deleteEntriesForRebuild { - my ($etl, %options) = @_; - - my $sql = []; - if (!$biTables->isTablePartitioned($options{name})) { - push @$sql, - [ - "[PURGE] Delete table [$options{name}] from $options{start} to $options{end}", - "DELETE FROM $options{name} WHERE time_id >= " . $utils->getDateEpoch($options{start}) . " AND time_id < " . $utils->getDateEpoch($options{end}) - ]; - } else { - my $structure = $biTables->dumpTableStructure($options{name}); - my $partitionsPerf = $utils->getRangePartitionDate($options{start}, $options{end}); - foreach (@$partitionsPerf) { - if ($structure =~ /p$_->{name}/m) { - push @$sql, - [ - "[PURGE] Truncate partition $_->{name} on table [$options{name}]", - "ALTER TABLE $options{name} TRUNCATE PARTITION p$_->{name}" - ]; - } else { - push @$sql, - [ - '[PARTITIONS] Add partition [p' . $_->{name} . '] on table [' . $options{name} . ']', - "ALTER TABLE `$options{name}` ADD PARTITION (PARTITION `p$_->{name}` VALUES LESS THAN(" . $_->{epoch} . "))" - ]; - } - } - } - - push @{$etl->{run}->{schedule}->{event}->{stages}->[0]}, { type => 'sql', db => 'centstorage', sql => $sql }; -} - -sub purgeAvailabilityTables { - my ($etl, $start, $end) = @_; - - my $firstDayOfMonth = $start; - $firstDayOfMonth =~ s/([1-2][0-9]{3})\-([0-1][0-9])\-[0-3][0-9]/$1\-$2\-01/; - - if ($etl->{run}->{options}->{nopurge} == 0) { - if (!defined($etl->{run}->{options}->{service_only}) || $etl->{run}->{options}->{service_only} == 0) { - if (!defined($etl->{run}->{options}->{month_only}) || $etl->{run}->{options}->{month_only} == 0) { - emptyTableForRebuild($etl, name => 'mod_bi_hostavailability', column => 'time_id', start => $start, end => $end); - } - - emptyTableForRebuild($etl, name => 'mod_bi_hgmonthavailability', column => 'time_id'); - } - if (!defined($etl->{run}->{options}->{host_only}) || $etl->{run}->{options}->{host_only} == 0) { - if (!defined($etl->{run}->{options}->{month_only}) || $etl->{run}->{options}->{month_only} == 0) { - emptyTableForRebuild($etl, name => 'mod_bi_serviceavailability', column => 'time_id', start => $start, end => $end); - } - - emptyTableForRebuild($etl, name => 'mod_bi_hgservicemonthavailability', column => 'time_id'); - } - } else { - if (!defined($etl->{run}->{options}->{service_only}) || $etl->{run}->{options}->{service_only} == 0) { - if (!defined($etl->{run}->{options}->{month_only}) || $etl->{run}->{options}->{month_only} == 0) { - deleteEntriesForRebuild($etl, name => 'mod_bi_hostavailability', start => $start, end => $end); - } - - deleteEntriesForRebuild($etl, name => 'mod_bi_hgmonthavailability', start => $firstDayOfMonth, end => $end); - } - if (!defined($etl->{run}->{options}->{host_only}) || $etl->{run}->{options}->{host_only} == 0) { - if (!defined($etl->{run}->{options}->{month_only}) || $etl->{run}->{options}->{month_only} == 0) { - deleteEntriesForRebuild($etl, name => 'mod_bi_serviceavailability', start => $start, end => $end); - } - deleteEntriesForRebuild($etl, name => 'mod_bi_hgservicemonthavailability', start => $firstDayOfMonth, end => $end); - } - } -} - -sub processByDay { - my ($etl, $liveServices, $start, $end) = @_; - - while (my ($liveserviceName, $liveserviceId) = each (%$liveServices)) { - if (!defined($etl->{run}->{options}->{service_only}) || $etl->{run}->{options}->{service_only} == 0) { - push @{$etl->{run}->{schedule}->{event}->{stages}->[1]}, { - type => 'availability_day_hosts', - liveserviceName => $liveserviceName, - liveserviceId => $liveserviceId, - start => $start, - end => $end - }; - } - - if (!defined($etl->{run}->{options}->{host_only}) || $etl->{run}->{options}->{host_only} == 0) { - push @{$etl->{run}->{schedule}->{event}->{stages}->[1]}, { - type => 'availability_day_services', - liveserviceName => $liveserviceName, - liveserviceId => $liveserviceId, - start => $start, - end => $end - }; - } - } -} - -sub processHostgroupAvailability { - my ($etl, $start, $end) = @_; - - $time->insertTimeEntriesForPeriod($start, $end); - if (!defined($etl->{run}->{options}->{service_only}) || $etl->{run}->{options}->{service_only} == 0) { - push @{$etl->{run}->{schedule}->{event}->{stages}->[2]}, { - type => 'availability_month_services', - start => $start, - end => $end - }; - } - if (!defined($etl->{run}->{options}->{host_only}) || $etl->{run}->{options}->{host_only} == 0) { - push @{$etl->{run}->{schedule}->{event}->{stages}->[2]}, { - type => 'availability_month_hosts', - start => $start, - end => $end - }; - } -} - -sub dailyProcessing { - my ($etl, $liveServices) = @_; - - # getting yesterday start and end date to process yesterday data - my ($start, $end) = $utils->getYesterdayTodayDate(); - # daily mod_bi_time table filling - $time->insertTimeEntriesForPeriod($start, $end); - - my ($epoch, $partName) = $utils->getDateEpoch($end); - push @{$etl->{run}->{schedule}->{event}->{stages}->[0]}, { - type => 'sql', - db => 'centstorage', - sql => [ - [ - '[PARTITIONS] Add partition [p' . $partName . '] on table [mod_bi_hostavailability]', - "ALTER TABLE `mod_bi_hostavailability` ADD PARTITION (PARTITION `p$partName` VALUES LESS THAN(" . $epoch . "))" - ] - ] - }; - push @{$etl->{run}->{schedule}->{event}->{stages}->[0]}, { - type => 'sql', - db => 'centstorage', - sql => [ - [ - '[PARTITIONS] Add partition [p' . $partName . '] on table [mod_bi_serviceavailability]', - "ALTER TABLE `mod_bi_serviceavailability` ADD PARTITION (PARTITION `p$partName` VALUES LESS THAN(" . $epoch . "))" - ] - ] - }; - - # Calculating availability of hosts and services for the current day - processByDay($etl, $liveServices, $start, $end); - - # Calculating statistics for last month if day of month si 1 - my ($year, $mon, $day) = split('-', $end); - if ($day == 1) { - processHostgroupAvailability($etl, $utils->subtractDateMonths($end, 1), $utils->subtractDateDays($end, 1)); - } - - push @{$etl->{run}->{schedule}->{event}->{stages}->[0]}, - { type => 'events', services => 1, start => $start, end => $end }, { type => 'events', hosts => 1, start => $start, end => $end }; -} - -# rebuild availability statistics -sub rebuildAvailability { - my ($etl, $start, $end, $liveServices) = @_; - - my $days = $utils->getRangePartitionDate($start, $end); - foreach (@$days) { - $end = $_->{date}; - processByDay($etl, $liveServices, $start, $end); - - my ($year, $mon, $day) = split('-', $end); - if ($day == 1) { - processHostgroupAvailability($etl, $utils->subtractDateMonths($end, 1), $utils->subtractDateDays($end, 1)); - } - - $start = $end; - } -} - -sub rebuildProcessing { - my ($etl, $liveServices) = @_; - - if ($etl->{run}->{options}->{start} ne '' && $etl->{run}->{options}->{end} ne '') { - # setting manually start and end dates for each granularity of perfdata - ($start, $end) = ($etl->{run}->{options}->{start}, $etl->{run}->{options}->{end}); - }else { - # getting max perfdata retention period to fill mod_bi_time - my $periods = $etl->{etlProp}->getRetentionPeriods(); - ($start, $end) = ($periods->{'availability.daily'}->{start}, $periods->{'availability.daily'}->{end}); - } - - # insert entries into table mod_bi_time - $time->insertTimeEntriesForPeriod($start, $end); - if (!defined($etl->{run}->{options}->{events_only}) || $etl->{run}->{options}->{events_only} == 0) { - purgeAvailabilityTables($etl, $start, $end); - rebuildAvailability($etl, $start, $end, $liveServices); - } - - if (!defined($etl->{run}->{options}->{availability_only}) || $etl->{run}->{options}->{availability_only} == 0) { - push @{$etl->{run}->{schedule}->{event}->{stages}->[0]}, - { type => 'events', services => 1, start => $start, end => $end }, { type => 'events', hosts => 1, start => $start, end => $end }; - } -} - -sub prepare { - my ($etl) = @_; - - initVars($etl); - - my $liveServiceList = $liveService->getLiveServicesByNameForTpIds($etl->{run}->{etlProperties}->{'liveservices.availability'}); - - if ($etl->{run}->{options}->{daily} == 1) { - dailyProcessing($etl, $liveServiceList); - } elsif ($etl->{run}->{options}->{rebuild} == 1) { - rebuildProcessing($etl, $liveServiceList); - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etl/hooks.pm deleted file mode 100644 index bc210ca41e..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/hooks.pm +++ /dev/null @@ -1,156 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etl::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::centreon::mbi::etl::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'mbietl'; -use constant EVENTS => [ - { event => 'CENTREONMBIETLRUN', uri => '/run', method => 'POST' }, - { event => 'CENTREONMBIETLKILL', uri => '/kill', method => 'GET' }, - { event => 'CENTREONMBIETLSTATUS', uri => '/status', method => 'GET' }, - { event => 'CENTREONMBIETLLISTENER' }, - { event => 'CENTREONMBIETLREADY' } -]; - -my $config_core; -my $config; -my $run = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'CENTREONMBIETLREADY') { - $run->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$run->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-' . NAME . ': still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-' . NAME, - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($run->{running}) && $run->{running} == 1) { - $options{logger}->writeLogDebug("[" . NAME . "] Send TERM signal $run->{pid}"); - CORE::kill('TERM', $run->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($run->{running} == 1) { - $options{logger}->writeLogDebug("[" . NAME . "] Send KILL signal $run->{pid}"); - CORE::kill('KILL', $run->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($run->{pid}) || $run->{pid} != $pid); - - $run = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($run->{running}) && $run->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[" . NAME . "] Create module '" . NAME . "' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-' . NAME; - my $module = gorgone::modules::centreon::mbi::etl::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[" . NAME . "] PID $child_pid (gorgone-" . NAME . ")"); - $run = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/import/main.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etl/import/main.pm deleted file mode 100644 index 54bf7b0c6f..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/import/main.pm +++ /dev/null @@ -1,427 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etl::import::main; - -use strict; -use warnings; - -use gorgone::modules::centreon::mbi::libs::bi::MySQLTables; -use gorgone::modules::centreon::mbi::libs::Utils; - -my ($biTables, $monTables, $utils); -my ($argsMon, $argsBi); - -sub initVars { - my ($etl) = @_; - - $biTables = gorgone::modules::centreon::mbi::libs::bi::MySQLTables->new($etl->{run}->{messages}, $etl->{run}->{dbbi_centstorage_con}); - $monTables = gorgone::modules::centreon::mbi::libs::bi::MySQLTables->new($etl->{run}->{messages}, $etl->{run}->{dbmon_centstorage_con}); - $utils = gorgone::modules::centreon::mbi::libs::Utils->new($etl->{run}->{messages}); - $argsMon = $utils->buildCliMysqlArgs($etl->{run}->{dbmon}->{centstorage}); - $argsBi = $utils->buildCliMysqlArgs($etl->{run}->{dbbi}->{centstorage}); -} - -# Create tables for centstorage database on reporting server -sub createTables { - my ($etl, $periods, $options, $notTimedTables) = @_; - - #Creating all centreon bi tables exept the one already created - my $sth = $etl->{run}->{dbmon_centstorage_con}->query({ query => "SHOW TABLES LIKE 'mod_bi_%'" }); - while (my @row = $sth->fetchrow_array()) { - my $name = $row[0]; - if (!$biTables->tableExists($name)) { - my $structure = $monTables->dumpTableStructure($name); - push @{$etl->{run}->{schedule}->{import}->{actions}}, - { - type => 1, db => 'centstorage', sql => [ ["[CREATE] add table [$name]", $structure] ], actions => [] - }; - } - } - - # Manage centreonAcl - my $action; - if ($options->{create_tables} == 0) { - #Update centreon_acl table each time centreon-only is started - not the best way but need for Widgets - my $cmd = sprintf( - "mysqldump --replace --no-create-info --skip-add-drop-table --skip-add-locks --skip-comments %s '%s' %s | mysql %s '%s'", - $argsMon, - $etl->{run}->{dbmon}->{centstorage}->{db}, - 'centreon_acl', - $argsBi, - $etl->{run}->{dbbi}->{centstorage}->{db} - ); - $action = { type => 2, message => '[LOAD] import table [centreon_acl]', command => $cmd }; - } - - if (!$biTables->tableExists('centreon_acl')) { - my $structure = $monTables->dumpTableStructure('centreon_acl'); - push @{$etl->{run}->{schedule}->{import}->{actions}}, - { - type => 1, db => 'centstorage', sql => [ ["[CREATE] add table [centreon_acl]", $structure] ], actions => defined($action) ? [$action] : [] - }; - } elsif (defined($action)) { - if ($options->{rebuild} == 1 && $options->{nopurge} == 0) { - push @{$etl->{run}->{schedule}->{import}->{actions}}, { - type => 1, db => 'centstorage', sql => [ ["[TRUNCATE] table [centreon_acl]", 'TRUNCATE table centreon_acl'] ], actions => defined($action) ? [$action] : [] - }; - } else { - push @{$etl->{run}->{schedule}->{import}->{actions}}, $action; - } - } - - my $tables = join('|', @$notTimedTables); - $sth = $etl->{run}->{dbmon_centstorage_con}->query({ query => "SHOW TABLES LIKE 'mod_bam_reporting_%'" }); - while (my @row = $sth->fetchrow_array()) { - my $name = $row[0]; - next if ($name =~ /^(?:$tables)$/); - - if (!$biTables->tableExists($name)) { - my $structure = $monTables->dumpTableStructure($name); - push @{$etl->{run}->{schedule}->{import}->{actions}}, - { - type => 1, db => 'centstorage', sql => [ ["[CREATE] Add table [$name]", $structure] ], actions => [] - }; - } - } -} - -# Extract data from Centreon DB server -sub extractData { - my ($etl, $options, $notTimedTables) = @_; - - foreach my $name (@$notTimedTables) { - my $action = { type => 1, db => 'centstorage', sql => [], actions => [] }; - - push @{$action->{sql}}, [ '[CREATE] Deleting table [' . $name . ']', 'DROP TABLE IF EXISTS `' . $name . '`' ]; - - my $structure = $monTables->dumpTableStructure($name); - $structure =~ s/(CONSTRAINT.*\n)//g; - $structure =~ s/(\,\n\s+\))/\)/g; - $structure =~ s/auto_increment\=[0-9]+//i; - $structure =~ s/auto_increment//i; - - push @{$action->{sql}}, [ "[CREATE] Add table [$name]", $structure ]; - if ($name eq 'hoststateevents' || $name eq 'servicestateevents') { - # add drop indexes - my $indexes = $etl->{run}->{dbmon_centstorage_con}->query({ query => "SHOW INDEX FROM " . $name }); - my $previous = ''; - while (my $row = $indexes->fetchrow_hashref()) { - if ($row->{Key_name} ne $previous) { - if (lc($row->{Key_name}) eq lc('PRIMARY')) { - push @{$action->{sql}}, - [ - "[INDEXING] Deleting index [PRIMARY KEY] on table [".$name."]", - "ALTER TABLE `" . $name . "` DROP PRIMARY KEY" - ]; - } else { - push @{$action->{sql}}, - [ - "[INDEXING] Deleting index [$row->{Key_name}] on table [".$name."]", - "ALTER TABLE `" . $name . "` DROP INDEX " . $row->{Key_name} - ]; - } - } - $previous = $row->{Key_name}; - } - - push @{$action->{sql}}, - [ - "[INDEXING] Adding index [in_downtime, start_time, end_time] on table [" . $name . "]", - "ALTER TABLE `" . $name . "` ADD INDEX `idx_" . $name . "_downtime_start_end_time` (in_downtime, start_time, end_time)" - ], - [ - "[INDEXING] Adding index [end_time] on table [" . $name . "]", - "ALTER TABLE `" . $name . "` ADD INDEX `idx_" . $name . "_end_time` (`end_time`)" - ]; - if ($name eq 'servicestateevents') { - push @{$action->{sql}}, - [ - "[INDEXING] Adding index [host_id, service_id, start_time, end_time, ack_time, state, last_update] on table [servicestateevents]", - "ALTER TABLE `servicestateevents` ADD INDEX `idx_servicestateevents_multi` (host_id, service_id, start_time, end_time, ack_time, state, last_update)" - ]; - } - } - - my $cmd = sprintf( - "mysqldump --no-create-info --skip-add-drop-table --skip-add-locks --skip-comments %s '%s' %s | mysql %s '%s'", - $argsMon, - $etl->{run}->{dbmon}->{centstorage}->{db}, - $name, - $argsBi, - $etl->{run}->{dbbi}->{centstorage}->{db} - ); - push @{$action->{actions}}, { type => 2, message => '[LOAD] import table [' . $name . ']', command => $cmd }; - push @{$etl->{run}->{schedule}->{import}->{actions}}, $action; - } -} - -# load data into the reporting server from files copied from the monitoring server -sub extractCentreonDB { - my ($etl, $etlProperties) = @_; - - my $tables = 'host hostgroup_relation hostgroup hostcategories_relation hostcategories ' . - 'host_service_relation service service_categories service_categories_relation ' . - 'timeperiod mod_bi_options servicegroup mod_bi_options_centiles servicegroup_relation contact contactgroup_service_relation '. - 'host_template_relation command contact_host_relation contactgroup_host_relation contactgroup contact_service_relation'; - - my $mon = $utils->buildCliMysqlArgs($etl->{run}->{dbmon}->{centreon}); - my $bi = $utils->buildCliMysqlArgs($etl->{run}->{dbbi}->{centreon}); - - my $cmd = sprintf( - "mysqldump --skip-add-drop-table --skip-add-locks --skip-comments %s '%s' %s | mysql --force %s '%s'", - $mon, - $etl->{run}->{dbmon}->{centreon}->{db}, - $tables, - $bi, - $etl->{run}->{dbbi}->{centreon}->{db} - ); - - push @{$etl->{run}->{schedule}->{import}->{actions}}, { - type => 1, - db => 'centreon', - sql => [ - [ '[DROPDB] database ' . $etl->{run}->{dbbi}->{centreon}->{db}, "DROP DATABASE `$etl->{run}->{dbbi}->{centreon}->{db}`" ], - [ '[CREATEDB] database ' . $etl->{run}->{dbbi}->{centreon}->{db}, "CREATE DATABASE `$etl->{run}->{dbbi}->{centreon}->{db}`" ], - ], - actions => [ - { type => 2, message => '[LOAD] import table [' . $tables . ']', command => $cmd } - ] - }; -} - -sub dataBin { - my ($etl, $etlProperties, $options, $periods) = @_; - - return if ($options->{ignore_databin} == 1 || $options->{centreon_only} == 1 || (defined($options->{bam_only}) && $options->{bam_only} == 1)); - - my $action = { type => 1, db => 'centstorage', sql => [], actions => [] }; - - my $drop = 0; - if ($options->{rebuild} == 1 && $options->{nopurge} == 0) { - push @{$action->{sql}}, [ '[CREATE] Deleting table [data_bin]', 'DROP TABLE IF EXISTS `data_bin`' ]; - $drop = 1; - } - - my $isExists = 0; - $isExists = 1 if ($biTables->tableExists('data_bin')); - - my $partitionsPerf = $utils->getRangePartitionDate($periods->{raw_perfdata}->{start}, $periods->{raw_perfdata}->{end}); - - if ($isExists == 0 || $drop == 1) { - $action->{create} = 1; - - my $structure = $monTables->dumpTableStructure('data_bin'); - $structure =~ s/KEY.*\(\`id_metric\`\)\,//g; - $structure =~ s/KEY.*\(\`id_metric\`\)//g; - $structure =~ s/\n.*PARTITION.*//g; - $structure =~ s/\,[\n\s]+\)/\)/; - $structure .= " PARTITION BY RANGE(`ctime`) ("; - - my $append = ''; - foreach (@$partitionsPerf) { - $structure .= $append . "PARTITION p" . $_->{name} . " VALUES LESS THAN (" . $_->{epoch} . ")"; - $append = ','; - } - $structure .= ');'; - - push @{$action->{sql}}, - [ '[CREATE] Add table [data_bin]', $structure ], - [ '[INDEXING] Adding index [ctime] on table [data_bin]', "ALTER TABLE `data_bin` ADD INDEX `idx_data_bin_ctime` (`ctime`)" ], - [ '[INDEXING] Adding index [id_metric_id, ctime] on table [data_bin]', "ALTER TABLE `data_bin` ADD INDEX `idx_data_bin_idmetric_ctime` (`id_metric`,`ctime`)" ]; - } - - if ($isExists == 1 && $drop == 0) { - my $start = $biTables->getLastPartRange('data_bin'); - my $partitions = $utils->getRangePartitionDate($start, $periods->{raw_perfdata}->{end}); - foreach (@$partitions) { - push @{$action->{sql}}, - [ '[PARTITIONS] Add partition [' . $_->{name} . '] on table [data_bin]', "ALTER TABLE `data_bin` ADD PARTITION (PARTITION `p$_->{name}` VALUES LESS THAN($_->{epoch}))"]; - } - } - - if ($etl->{run}->{options}->{create_tables} == 0 && ($etlProperties->{'statistics.type'} eq 'all' || $etlProperties->{'statistics.type'} eq 'perfdata')) { - my $epoch = $utils->getDateEpoch($periods->{raw_perfdata}->{start}); - - my $overCond = 'ctime >= ' . $epoch . ' AND '; - foreach (@$partitionsPerf) { - my $cmd = sprintf( - "mysqldump --insert-ignore --single-transaction --no-create-info --skip-add-drop-table --skip-disable-keys --skip-add-locks --skip-comments %s --databases '%s' --tables %s --where=\"%s\" | mysql --init-command='SET SESSION unique_checks=0' %s '%s'", - $argsMon, - $etl->{run}->{dbmon}->{centstorage}->{db}, - 'data_bin', - $overCond . 'ctime < ' . $_->{epoch}, - $argsBi, - $etl->{run}->{dbbi}->{centstorage}->{db} - ); - $overCond = 'ctime >= ' . $_->{epoch} . ' AND '; - push @{$action->{actions}}, { type => 2, message => '[LOAD] partition [' . $_->{name} . '] on table [data_bin]', command => $cmd }; - } - - #my $file = $etlProperties->{'reporting.storage.directory'} . '/data_bin.sql'; - #push @{$action->{actions}}, { - # type => 3, - # message => '[LOAD] table [data_bin]', - # table => 'data_bin', - # db => 'centstorage', - # dump => $cmd, - # file => $file, - # load => "LOAD DATA LOCAL INFILE '" . $file . "' INTO TABLE `data_bin` CHARACTER SET UTF8 IGNORE 1 LINES" - #}; - } - - push @{$etl->{run}->{schedule}->{import}->{actions}}, $action; -} - -sub selectTables { - my ($etl, $etlProperties, $options) = @_; - - my @notTimedTables = (); - my %timedTables = (); - - my @ctime = ('ctime', 'ctime'); - my @startEnd = ('date_start', 'date_end'); - my @timeId = ('time_id', 'time_id'); - my $importComment = $etlProperties->{'import.comments'}; - my $importDowntimes = $etlProperties->{'import.downtimes'}; - - if (!defined($etlProperties->{'statistics.type'})) { - die 'cannot determine statistics type or compatibility mode for data integration'; - } - - if (!defined($options->{databin_only}) || $options->{databin_only} == 0) { - if (!defined($options->{bam_only}) || $options->{bam_only} == 0) { - if ($etlProperties->{'statistics.type'} eq 'all') { - push @notTimedTables, 'index_data'; - push @notTimedTables, 'metrics'; - push @notTimedTables, 'hoststateevents'; - push @notTimedTables, 'servicestateevents'; - push @notTimedTables, 'instances'; - push @notTimedTables, 'hosts'; - - if ($importComment eq 'true'){ - push @notTimedTables, 'comments'; - } - if ($importDowntimes eq 'true'){ - push @notTimedTables, 'downtimes'; - } - - push @notTimedTables, 'acknowledgements'; - } - if ($etlProperties->{'statistics.type'} eq 'availability') { - push @notTimedTables, 'hoststateevents'; - push @notTimedTables, 'servicestateevents'; - push @notTimedTables, 'instances'; - push @notTimedTables, 'hosts'; - if ($importComment eq 'true'){ - push @notTimedTables, 'comments'; - } - push @notTimedTables, 'acknowledgements'; - } - if ($etlProperties->{'statistics.type'} eq "perfdata") { - push @notTimedTables, 'index_data'; - push @notTimedTables, 'metrics'; - push @notTimedTables, 'instances'; - push @notTimedTables, 'hosts'; - push @notTimedTables, 'acknowledgements'; - - } - } - - my $sth = $etl->{run}->{dbmon_centreon_con}->query({ query => "SELECT id FROM modules_informations WHERE name='centreon-bam-server'" }); - if (my $row = $sth->fetchrow_array() && $etlProperties->{'statistics.type'} ne 'perfdata') { - push @notTimedTables, "mod_bam_reporting_ba_availabilities"; - push @notTimedTables, "mod_bam_reporting_ba"; - push @notTimedTables, "mod_bam_reporting_ba_events"; - push @notTimedTables, "mod_bam_reporting_ba_events_durations"; - push @notTimedTables, "mod_bam_reporting_bv"; - push @notTimedTables, "mod_bam_reporting_kpi"; - push @notTimedTables, "mod_bam_reporting_kpi_events"; - push @notTimedTables, "mod_bam_reporting_relations_ba_bv"; - push @notTimedTables, "mod_bam_reporting_relations_ba_kpi_events"; - push @notTimedTables, "mod_bam_reporting_timeperiods"; - } - } - - return (\@notTimedTables, \%timedTables); -} - -sub prepare { - my ($etl) = @_; - - initVars($etl); - - # define data extraction period based on program options --start & --end or on data retention period - my %periods; - if ($etl->{run}->{options}->{rebuild} == 1 || $etl->{run}->{options}->{create_tables}) { - if ($etl->{run}->{options}->{start} eq '' && $etl->{run}->{options}->{end} eq '') { - # get max values for retention by type of statistics in order to be able to rebuild hourly and daily stats - my ($start, $end) = $etl->{etlProp}->getMaxRetentionPeriodFor('perfdata'); - - $periods{raw_perfdata} = { start => $start, end => $end }; - ($start, $end) = $etl->{etlProp}->getMaxRetentionPeriodFor('availability'); - $periods{raw_availabilitydata} = { start => $start, end => $end}; - } elsif ($etl->{run}->{options}->{start} ne '' && $etl->{run}->{options}->{end} ne '') { - # set period defined manually - my %dates = (start => $etl->{run}->{options}->{start}, end => $etl->{run}->{options}->{end}); - $periods{raw_perfdata} = \%dates; - $periods{raw_availabilitydata} = \%dates; - } - } else { - # set yesterday start and end dates as period (--daily) - my %dates; - ($dates{start}, $dates{end}) = $utils->getYesterdayTodayDate(); - $periods{raw_perfdata} = \%dates; - $periods{raw_availabilitydata} = \%dates; - } - - # identify the Centreon Storage DB tables to extract based on ETL properties - my ($notTimedTables, $timedTables) = selectTables( - $etl, - $etl->{run}->{etlProperties}, - $etl->{run}->{options} - ); - - dataBin( - $etl, - $etl->{run}->{etlProperties}, - $etl->{run}->{options}, - \%periods - ); - - # create non existing tables - createTables($etl, \%periods, $etl->{run}->{options}, $notTimedTables); - - # If we only need to create empty tables, create them then exit program - return if ($etl->{run}->{options}->{create_tables} == 1); - - # extract raw availability and perfdata from monitoring server and insert it into reporting server - if ($etl->{run}->{options}->{centreon_only} == 0) { - extractData($etl, $etl->{run}->{options}, $notTimedTables); - } - - # extract Centreon configuration DB from monitoring server and insert it into reporting server - if ((!defined($etl->{run}->{options}->{databin_only}) || $etl->{run}->{options}->{databin_only} == 0) - && (!defined($etl->{run}->{options}->{bam_only}) || $etl->{run}->{options}->{bam_only} == 0)) { - extractCentreonDB($etl, $etl->{run}->{etlProperties}); - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/perfdata/main.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etl/perfdata/main.pm deleted file mode 100644 index 170903907c..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etl/perfdata/main.pm +++ /dev/null @@ -1,425 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etl::perfdata::main; - -use strict; -use warnings; - -use gorgone::modules::centreon::mbi::libs::bi::Time; -use gorgone::modules::centreon::mbi::libs::bi::LiveService; -use gorgone::modules::centreon::mbi::libs::bi::MySQLTables; -use gorgone::modules::centreon::mbi::libs::Utils; -use gorgone::standard::constants qw(:all); - -my ($biTables, $utils, $liveService, $time); - -sub initVars { - my ($etl) = @_; - - $biTables = gorgone::modules::centreon::mbi::libs::bi::MySQLTables->new($etl->{run}->{messages}, $etl->{run}->{dbbi_centstorage_con}); - $utils = gorgone::modules::centreon::mbi::libs::Utils->new($etl->{run}->{messages}); - $liveService = gorgone::modules::centreon::mbi::libs::bi::LiveService->new($etl->{run}->{messages}, $etl->{run}->{dbbi_centstorage_con}); - $time = gorgone::modules::centreon::mbi::libs::bi::Time->new($etl->{run}->{messages}, $etl->{run}->{dbbi_centstorage_con}); -} - -sub emptyTableForRebuild { - my ($etl, %options) = @_; - - my $sql = [ [ '[CREATE] Deleting table [' . $options{name} . ']', 'DROP TABLE IF EXISTS `' . $options{name} . '`' ] ]; - - my $structure = $biTables->dumpTableStructure($options{name}); - $structure =~ s/KEY.*\(\`$options{column}\`\)\,//g; - $structure =~ s/KEY.*\(\`$options{column}\`\)//g; - $structure =~ s/\,[\n\s+]+\)/\n\)/g; - - if (defined($options{start})) { - $structure =~ s/\n.*PARTITION.*//g; - $structure =~ s/\,[\n\s]+\)/\)/; - $structure .= ' PARTITION BY RANGE(`' . $options{column} . '`) ('; - - my $partitionsPerf = $utils->getRangePartitionDate($options{start}, $options{end}); - - my $append = ''; - foreach (@$partitionsPerf) { - $structure .= $append . "PARTITION p" . $_->{name} . " VALUES LESS THAN (" . $_->{epoch} . ")"; - $append = ','; - } - $structure .= ');'; - } - - push @$sql, - [ '[CREATE] Add table [' . $options{name} . ']', $structure ], - [ "[INDEXING] Adding index [idx_$options{name}_$options{column}] on table [$options{name}]", "ALTER TABLE `$options{name}` ADD INDEX `idx_$options{name}_$options{column}` (`$options{column}`)" ]; - - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[0]}, { type => 'sql', db => 'centstorage', sql => $sql }; -} - -sub deleteEntriesForRebuild { - my ($etl, %options) = @_; - - my $sql = []; - if (!$biTables->isTablePartitioned($options{name})) { - push @$sql, - [ - "[PURGE] Delete table [$options{name}] from $options{start} to $options{end}", - "DELETE FROM $options{name} WHERE time_id >= " . $utils->getDateEpoch($options{start}) . " AND time_id < " . $utils->getDateEpoch($options{end}) - ]; - } else { - my $structure = $biTables->dumpTableStructure($options{name}); - my $partitionsPerf = $utils->getRangePartitionDate($options{start}, $options{end}); - foreach (@$partitionsPerf) { - if ($structure =~ /p$_->{name}/m) { - push @$sql, - [ - "[PURGE] Truncate partition $_->{name} on table [$options{name}]", - "ALTER TABLE $options{name} TRUNCATE PARTITION p$_->{name}" - ]; - } else { - push @$sql, - [ - '[PARTITIONS] Add partition [p' . $_->{name} . '] on table [' . $options{name} . ']', - "ALTER TABLE `$options{name}` ADD PARTITION (PARTITION `p$_->{name}` VALUES LESS THAN(" . $_->{epoch} . "))" - ]; - } - } - } - - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[0]}, { type => 'sql', db => 'centstorage', sql => $sql }; -} - -sub purgeTables { - my ($etl, $periods) = @_; - - my ($daily_start, $daily_end) = ($periods->{'perfdata.daily'}->{'start'}, $periods->{'perfdata.daily'}->{'end'}); - my ($hourly_start, $hourly_end) = ($periods->{'perfdata.hourly'}->{'start'}, $periods->{'perfdata.hourly'}->{'end'}); - - #To prevent from purging monthly data when the no-purge rebuild is made inside one month - my $firstDayOfMonth = $daily_start; - my $firstDayOfMonthEnd = $daily_end; - my $startAndEndSameMonth = 0; - $firstDayOfMonth =~ s/([1-2][0-9]{3})\-([0-1][0-9])\-[0-3][0-9]/$1\-$2\-01/; - $firstDayOfMonthEnd =~ s/([1-2][0-9]{3})\-([0-1][0-9])\-[0-3][0-9]/$1\-$2\-01/; - - if ($firstDayOfMonth eq $firstDayOfMonthEnd) { - $startAndEndSameMonth = 1; - } - - if ($etl->{run}->{options}->{nopurge} == 1) { - # deleting data that will be rewritten - if ($etl->{run}->{etlProperties}->{'perfdata.granularity'} ne 'hour' && (!defined($etl->{run}->{options}->{month_only}) || $etl->{run}->{options}->{month_only} == 0)) { - if ((!defined($etl->{run}->{options}->{centile_only}) || $etl->{run}->{options}->{centile_only} == 0)) { - deleteEntriesForRebuild($etl, name => 'mod_bi_metricdailyvalue', start => $daily_start, end => $daily_end); - - if ($etl->{run}->{etlProperties}->{'perfdata.granularity'} ne "day" && (!defined($etl->{run}->{options}->{month_only}) || $etl->{run}->{options}->{month_only} == 0)) { - deleteEntriesForRebuild($etl, name => 'mod_bi_metrichourlyvalue', start => $hourly_start, end => $hourly_end); - } - - #Deleting monthly data only if start and end are not in the same month - if (!$startAndEndSameMonth) { - deleteEntriesForRebuild($etl, name => 'mod_bi_metricmonthcapacity', start => $firstDayOfMonth, end => $daily_end); - } - } - - if ((!defined($etl->{run}->{options}->{no_centile}) || $etl->{run}->{options}->{no_centile} == 0)) { - if (defined($etl->{run}->{etlProperties}->{'centile.day'}) && $etl->{run}->{etlProperties}->{'centile.day'} eq '1') { - deleteEntriesForRebuild($etl, name => 'mod_bi_metriccentiledailyvalue', start => $daily_start, end => $daily_end); - } - if (defined($etl->{run}->{etlProperties}->{'centile.week'}) && $etl->{run}->{etlProperties}->{'centile.week'} eq '1') { - deleteEntriesForRebuild($etl, name => 'mod_bi_metriccentileweeklyvalue', start => $daily_start, end => $daily_end); - } - - if (defined($etl->{run}->{etlProperties}->{'centile.month'}) && $etl->{run}->{etlProperties}->{'centile.month'} eq '1' && !$startAndEndSameMonth) { - deleteEntriesForRebuild($etl, name => 'mod_bi_metriccentilemonthlyvalue', start => $firstDayOfMonth, end => $daily_end); - } - } - } - } else { - # deleting and recreating tables, recreating partitions for daily and hourly tables - if ($etl->{run}->{etlProperties}->{'perfdata.granularity'} ne "hour" && (!defined($etl->{run}->{options}->{month_only}) || $etl->{run}->{options}->{month_only} == 0)) { - if ((!defined($etl->{run}->{options}->{centile_only}) || $etl->{run}->{options}->{centile_only} == 0)) { - emptyTableForRebuild($etl, name => 'mod_bi_metricdailyvalue', column => 'time_id', start => $daily_start, end => $daily_end); - - emptyTableForRebuild($etl, name => 'mod_bi_metricmonthcapacity', column => 'time_id'); - } - - if ((!defined($etl->{run}->{options}->{no_centile}) || $etl->{run}->{options}->{no_centile} == 0)) { - #Managing Daily Centile table - if (defined($etl->{run}->{etlProperties}->{'centile.day'}) && $etl->{run}->{etlProperties}->{'centile.day'} eq '1') { - emptyTableForRebuild($etl, name => 'mod_bi_metriccentiledailyvalue', column => 'time_id', start => $daily_start, end => $daily_end); - } - #Managing Weekly Centile table - if (defined($etl->{run}->{etlProperties}->{'centile.week'}) && $etl->{run}->{etlProperties}->{'centile.week'} eq '1') { - emptyTableForRebuild($etl, name => 'mod_bi_metriccentileweeklyvalue', column => 'time_id', start => $daily_start, end => $daily_end); - } - #Managing Monthly Centile table - if (defined($etl->{run}->{etlProperties}->{'centile.month'}) && $etl->{run}->{etlProperties}->{'centile.month'} eq '1') { - emptyTableForRebuild($etl, name => 'mod_bi_metriccentilemonthlyvalue', column => 'time_id', start => $daily_start, end => $daily_end); - } - } - } - - if ($etl->{run}->{etlProperties}->{'perfdata.granularity'} ne "day" && - (!defined($etl->{run}->{options}->{month_only}) || $etl->{run}->{options}->{month_only} == 0) && - (!defined($etl->{run}->{options}->{no_centile}) || $etl->{run}->{options}->{no_centile} == 0)) { - emptyTableForRebuild($etl, name => 'mod_bi_metrichourlyvalue', column => 'time_id', start => $hourly_start, end => $hourly_end); - } - } -} - -sub processDay { - my ($etl, $liveServices, $start, $end) = @_; - - if ($etl->{run}->{etlProperties}->{'perfdata.granularity'} eq 'hour' || - (defined($etl->{run}->{options}->{month_only}) && $etl->{run}->{options}->{month_only} == 1)) { - return 1; - } - - my ($currentDayId, $currentDayUtime) = $time->getEntryID($start); - - if ((!defined($etl->{run}->{options}->{centile_only}) || $etl->{run}->{options}->{centile_only} == 0)) { - while (my ($liveServiceName, $liveServiceId) = each (%$liveServices)) { - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[1]}, { - type => 'perfdata_day', - liveserviceName => $liveServiceName, - liveserviceId => $liveServiceId, - start => $start, - end => $end - }; - } - } - - if ((!defined($etl->{run}->{options}->{no_centile}) || $etl->{run}->{options}->{no_centile} == 0)) { - if (defined($etl->{run}->{etlProperties}->{'centile.include.servicecategories'}) && $etl->{run}->{etlProperties}->{'centile.include.servicecategories'} ne '') { - if (defined($etl->{run}->{etlProperties}->{'centile.day'}) && $etl->{run}->{etlProperties}->{'centile.day'} eq '1') { - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[2]}, { - type => 'centile_day', - start => $start, - end => $end - }; - } - if (defined($etl->{run}->{etlProperties}->{'centile.week'}) && $etl->{run}->{etlProperties}->{'centile.week'} eq '1') { - if ($utils->getDayOfWeek($end) eq $etl->{run}->{etlProperties}->{'centile.weekFirstDay'}) { - processWeek($etl, $end); - } - } - } - } -} - -sub processWeek { - my ($etl, $date) = @_; - - my $start = $utils->subtractDateDays($date, 7); - my $end = $utils->subtractDateDays($date, 1); - - $time->insertTimeEntriesForPeriod($start, $end); - - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[2]}, { - type => 'centile_week', - start => $start, - end => $end - }; -} - -sub processMonth { - my ($etl, $liveServices, $date) = @_; - - my $start = $utils->subtractDateMonths($date, 1); - my $end = $utils->subtractDateDays($date, 1); - - $time->insertTimeEntriesForPeriod($start, $end); - - my ($previousMonthStartTimeId, $previousMonthStartUtime) = $time->getEntryID($start); - my ($previousMonthEndTimeId, $previousMonthEndUtime) = $time->getEntryID($end); - - if (!defined($etl->{run}->{etlProperties}->{'capacity.include.servicecategories'}) || $etl->{run}->{etlProperties}->{'capacity.include.servicecategories'} eq "" - || !defined($etl->{run}->{etlProperties}->{'capacity.include.liveservices'}) || $etl->{run}->{etlProperties}->{'capacity.include.liveservices'} eq "") { - $etl->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $etl->{run}->{token}, data => { messages => [ ['I', "[SCHEDULER][PERFDATA] Skipping month: [" . $start . "] to [" . $end . "]" ] ] }); - return ; - } - - if ((!defined($etl->{run}->{options}->{centile_only}) || $etl->{run}->{options}->{centile_only} == 0) && - $etl->{run}->{etlProperties}->{'perfdata.granularity'} ne 'hour') { - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[2]}, { - type => 'perfdata_month', - start => $start, - end => $end - }; - } - - if ((!defined($etl->{run}->{options}->{no_centile}) || $etl->{run}->{options}->{no_centile} == 0) && - $etl->{run}->{etlProperties}->{'centile.month'} && $etl->{run}->{etlProperties}->{'perfdata.granularity'} ne 'hour') { - if (defined($etl->{run}->{etlProperties}->{'centile.include.servicecategories'}) && $etl->{run}->{etlProperties}->{'centile.include.servicecategories'} ne '') { - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[2]}, { - type => 'centile_month', - start => $start, - end => $end - }; - } - } -} - -sub processHours { - my ($etl, $start, $end) = @_; - - if ($etl->{run}->{etlProperties}->{'perfdata.granularity'} eq 'day' || - (defined($etl->{run}->{options}->{month_only}) && $etl->{run}->{options}->{month_only} == 1) || - (defined($etl->{run}->{options}->{centile_only}) && $etl->{run}->{options}->{centile_only} == 1)) { - return 1; - } - - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[2]}, { - type => 'perfdata_hour', - start => $start, - end => $end - }; -} - -sub processDayAndMonthAgregation { - my ($etl, $liveServices, $start, $end) = @_; - - processDay($etl, $liveServices, $start, $end); - my ($year, $mon, $day) = split ("-", $end); - if ($day == 1) { - processMonth($etl, $liveServices, $end); - } -} - -sub dailyProcessing { - my ($etl, $liveServices) = @_; - - # getting yesterday start and end date to process yesterday data - my ($start, $end) = $utils->getYesterdayTodayDate(); - # daily mod_bi_time table filling - $time->insertTimeEntriesForPeriod($start, $end); - - my ($epoch, $partName) = $utils->getDateEpoch($end); - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[0]}, { - type => 'sql', - db => 'centstorage', - sql => [ - [ - '[PARTITIONS] Add partition [p' . $partName . '] on table [mod_bi_metricdailyvalue]', - "ALTER TABLE `mod_bi_metricdailyvalue` ADD PARTITION (PARTITION `p$partName` VALUES LESS THAN(" . $epoch . "))" - ] - ] - }; - if ($etl->{run}->{etlProperties}->{'perfdata.granularity'} ne 'day') { - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[0]}, { - type => 'sql', - db => 'centstorage', - sql => [ - [ - '[PARTITIONS] Add partition [p' . $partName . '] on table [mod_bi_metrichourlyvalue]', - "ALTER TABLE `mod_bi_metrichourlyvalue` ADD PARTITION (PARTITION `p$partName` VALUES LESS THAN(" . $epoch . "))" - ] - ] - }; - } - if (defined($etl->{run}->{etlProperties}->{'centile.day'}) && $etl->{run}->{etlProperties}->{'centile.day'} eq '1') { - push @{$etl->{run}->{schedule}->{perfdata}->{stages}->[0]}, { - type => 'sql', - db => 'centstorage', - sql => [ - [ - '[PARTITIONS] Add partition [p' . $partName . '] on table [mod_bi_metriccentiledailyvalue]', - "ALTER TABLE `mod_bi_metriccentiledailyvalue` ADD PARTITION (PARTITION `p$partName` VALUES LESS THAN(" . $epoch . "))" - ] - ] - }; - } - - # processing agregation by month. If the day is the first day of the month, also processing agregation by month - processDayAndMonthAgregation($etl, $liveServices, $start, $end); - - # processing agregation by hour - processHours($etl, $start, $end); -} - -sub rebuildProcessing { - my ($etl, $liveServices) = @_; - - # getting rebuild period by granularity of perfdata from data retention rules - my $periods = $etl->{etlProp}->getRetentionPeriods(); - - my ($start, $end); - if ($etl->{run}->{options}->{start} ne '' && $etl->{run}->{options}->{end} ne '') { - ($start, $end) = ($etl->{run}->{options}->{start}, $etl->{run}->{options}->{end}); - while (my ($key, $values) = each %$periods) { - $values->{start} = $etl->{run}->{options}->{start}; - $values->{end} = $etl->{run}->{options}->{end}; - } - } else { - # getting max perfdata retention period to fill mod_bi_time - ($start, $end) = $etl->{etlProp}->getMaxRetentionPeriodFor('perfdata'); - } - - # insert entries into table mod_bi_time - $time->insertTimeEntriesForPeriod($start, $end); - - purgeTables($etl, $periods); - - # rebuilding statistics by day and by month - ($start, $end) = ($periods->{'perfdata.daily'}->{start}, $periods->{'perfdata.daily'}->{end}); - - my $days = $utils->getRangePartitionDate($start, $end); - foreach (@$days) { - $end = $_->{date}; - processDayAndMonthAgregation($etl, $liveServices, $start, $end); - $start = $end; - } - - # rebuilding statistics by hour - ($start, $end) = ($periods->{'perfdata.hourly'}->{start}, $periods->{'perfdata.hourly'}->{'end'}); - - $days = $utils->getRangePartitionDate($start, $end); - foreach (@$days) { - $end = $_->{date}; - processHours($etl, $start, $end); - $start = $end; - } -} - -sub prepare { - my ($etl) = @_; - - initVars($etl); - - if (!defined($etl->{run}->{etlProperties}->{'statistics.type'}) || $etl->{run}->{etlProperties}->{'statistics.type'} eq "availability") { - $etl->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $etl->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][PERFDATA] Performance statistics calculation disabled' ] ] }); - return ; - } - - if ((!defined($etl->{run}->{options}->{no_centile}) || $etl->{run}->{options}->{no_centile} == 0) && - defined($etl->{run}->{etlProperties}->{'centile.include.servicecategories'}) and $etl->{run}->{etlProperties}->{'centile.include.servicecategories'} eq '') { - $etl->send_log(code => GORGONE_MODULE_CENTREON_MBIETL_PROGRESS, token => $etl->{run}->{token}, data => { messages => [ ['I', '[SCHEDULER][PERFDATA] No service categories selected for centile calculation - centile agregation will not be calculated' ] ] }); - } - - my $liveServiceList = $liveService->getLiveServicesByNameForTpIds($etl->{run}->{etlProperties}->{'liveservices.perfdata'}); - - if ($etl->{run}->{options}->{daily} == 1) { - dailyProcessing($etl, $liveServiceList); - } elsif ($etl->{run}->{options}->{rebuild} == 1) { - rebuildProcessing($etl, $liveServiceList); - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/class.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/class.pm deleted file mode 100644 index 9ba89780db..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/class.pm +++ /dev/null @@ -1,326 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etlworkers::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::http::http; -use JSON::XS; -use Try::Tiny; -use gorgone::modules::centreon::mbi::etlworkers::import::main; -use gorgone::modules::centreon::mbi::etlworkers::dimensions::main; -use gorgone::modules::centreon::mbi::etlworkers::event::main; -use gorgone::modules::centreon::mbi::etlworkers::perfdata::main; -use gorgone::modules::centreon::mbi::libs::Messages; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{pool_id} = $options{pool_id}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[nodes] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub db_connections { - my ($self, %options) = @_; - - if (!defined($self->{dbmon_centstorage_con}) || $self->{dbmon_centstorage_con}->sameParams(%{$options{dbmon}->{centstorage}}) == 0) { - $self->{dbmon_centstorage_con} = gorgone::class::db->new( - type => 'mysql', - force => 2, - logger => $self->{logger}, - die => 1, - %{$options{dbmon}->{centstorage}} - ); - } - if (!defined($self->{dbbi_centstorage_con}) || $self->{dbbi_centstorage_con}->sameParams(%{$options{dbbi}->{centstorage}}) == 0) { - $self->{dbbi_centstorage_con} = gorgone::class::db->new( - type => 'mysql', - force => 2, - logger => $self->{logger}, - die => 1, - %{$options{dbbi}->{centstorage}} - ); - } - - if (!defined($self->{dbmon_centreon_con}) || $self->{dbmon_centreon_con}->sameParams(%{$options{dbmon}->{centreon}}) == 0) { - $self->{dbmon_centreon_con} = gorgone::class::db->new( - type => 'mysql', - force => 2, - logger => $self->{logger}, - die => 1, - %{$options{dbmon}->{centreon}} - ); - } - if (!defined($self->{dbbi_centreon_con}) || $self->{dbbi_centreon_con}->sameParams(%{$options{dbbi}->{centreon}}) == 0) { - $self->{dbbi_centreon_con} = gorgone::class::db->new( - type => 'mysql', - force => 2, - logger => $self->{logger}, - die => 1, - %{$options{dbbi}->{centreon}} - ); - } -} - -sub action_centreonmbietlworkersimport { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{messages} = gorgone::modules::centreon::mbi::libs::Messages->new(); - my $code = GORGONE_ACTION_FINISH_OK; - - try { - $self->db_connections( - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi} - ); - if ($options{data}->{content}->{params}->{type} == 1) { - gorgone::modules::centreon::mbi::etlworkers::import::main::sql($self, params => $options{data}->{content}->{params}); - } elsif ($options{data}->{content}->{params}->{type} == 2) { - gorgone::modules::centreon::mbi::etlworkers::import::main::command($self, params => $options{data}->{content}->{params}); - } elsif ($options{data}->{content}->{params}->{type} == 3) { - gorgone::modules::centreon::mbi::etlworkers::import::main::load($self, params => $options{data}->{content}->{params}); - } - } catch { - $code = GORGONE_ACTION_FINISH_KO; - $self->{messages}->writeLog('ERROR', $_, 1); - }; - - $self->send_log( - code => $code, - token => $options{token}, - data => { - messages => $self->{messages}->getLogs() - } - ); -} - -sub action_centreonmbietlworkersdimensions { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{messages} = gorgone::modules::centreon::mbi::libs::Messages->new(); - my $code = GORGONE_ACTION_FINISH_OK; - - try { - $self->db_connections( - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi} - ); - - gorgone::modules::centreon::mbi::etlworkers::dimensions::main::execute( - $self, - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi}, - params => $options{data}->{content}->{params}, - etlProperties => $options{data}->{content}->{etlProperties}, - options => $options{data}->{content}->{options} - ); - } catch { - $code = GORGONE_ACTION_FINISH_KO; - $self->{messages}->writeLog('ERROR', $_, 1); - }; - - $self->send_log( - code => $code, - token => $options{token}, - data => { - messages => $self->{messages}->getLogs() - } - ); -} - -sub action_centreonmbietlworkersevent { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{messages} = gorgone::modules::centreon::mbi::libs::Messages->new(); - my $code = GORGONE_ACTION_FINISH_OK; - - try { - $self->db_connections( - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi} - ); - if ($options{data}->{content}->{params}->{type} eq 'sql') { - gorgone::modules::centreon::mbi::etlworkers::event::main::sql($self, params => $options{data}->{content}->{params}); - } elsif ($options{data}->{content}->{params}->{type} eq 'events') { - gorgone::modules::centreon::mbi::etlworkers::event::main::events( - $self, - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi}, - etlProperties => $options{data}->{content}->{etlProperties}, - params => $options{data}->{content}->{params}, - options => $options{data}->{content}->{options} - ); - } elsif ($options{data}->{content}->{params}->{type} =~ /^availability_/) { - gorgone::modules::centreon::mbi::etlworkers::event::main::availability( - $self, - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi}, - etlProperties => $options{data}->{content}->{etlProperties}, - params => $options{data}->{content}->{params} - ); - } - } catch { - $code = GORGONE_ACTION_FINISH_KO; - $self->{messages}->writeLog('ERROR', $_, 1); - }; - - $self->send_log( - code => $code, - token => $options{token}, - data => { - messages => $self->{messages}->getLogs() - } - ); -} - -sub action_centreonmbietlworkersperfdata { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{messages} = gorgone::modules::centreon::mbi::libs::Messages->new(); - my $code = GORGONE_ACTION_FINISH_OK; - - try { - $self->db_connections( - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi} - ); - - if ($options{data}->{content}->{params}->{type} eq 'sql') { - gorgone::modules::centreon::mbi::etlworkers::perfdata::main::sql($self, params => $options{data}->{content}->{params}); - } elsif ($options{data}->{content}->{params}->{type} =~ /^perfdata_/) { - gorgone::modules::centreon::mbi::etlworkers::perfdata::main::perfdata( - $self, - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi}, - etlProperties => $options{data}->{content}->{etlProperties}, - params => $options{data}->{content}->{params}, - options => $options{data}->{content}->{options}, - pool_id => $self->{pool_id} - ); - } elsif ($options{data}->{content}->{params}->{type} =~ /^centile_/) { - gorgone::modules::centreon::mbi::etlworkers::perfdata::main::centile( - $self, - dbmon => $options{data}->{content}->{dbmon}, - dbbi => $options{data}->{content}->{dbbi}, - etlProperties => $options{data}->{content}->{etlProperties}, - params => $options{data}->{content}->{params}, - pool_id => $self->{pool_id} - ); - } - } catch { - $code = GORGONE_ACTION_FINISH_KO; - $self->{messages}->writeLog('ERROR', $_, 1); - }; - - $self->send_log( - code => $code, - token => $options{token}, - data => { - messages => $self->{messages}->getLogs() - } - ); -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[" . $connector->{module_id} . "] $$ has quit"); - exit(0); - } - - $connector->event(); -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-' . $self->{module_id} . '-' . $self->{pool_id}, - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'CENTREONMBIETLWORKERSREADY', - data => { - pool_id => $self->{pool_id} - } - }); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/dimensions/main.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/dimensions/main.pm deleted file mode 100644 index f0206a4c2f..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/dimensions/main.pm +++ /dev/null @@ -1,263 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etlworkers::dimensions::main; - -use strict; -use warnings; - -use IO::Socket::INET; - -use gorgone::modules::centreon::mbi::libs::centreon::Host; -use gorgone::modules::centreon::mbi::libs::centreon::HostGroup; -use gorgone::modules::centreon::mbi::libs::centreon::HostCategory; -use gorgone::modules::centreon::mbi::libs::centreon::ServiceCategory; -use gorgone::modules::centreon::mbi::libs::centreon::Service; -use gorgone::modules::centreon::mbi::libs::centreon::Timeperiod; -use gorgone::modules::centreon::mbi::libs::bi::BIHost; -use gorgone::modules::centreon::mbi::libs::bi::BIHostGroup; -use gorgone::modules::centreon::mbi::libs::bi::BIHostCategory; -use gorgone::modules::centreon::mbi::libs::bi::BIServiceCategory; -use gorgone::modules::centreon::mbi::libs::bi::BIService; -use gorgone::modules::centreon::mbi::libs::bi::BIMetric; -use gorgone::modules::centreon::mbi::libs::bi::Time; -use gorgone::modules::centreon::mbi::libs::bi::LiveService; -use gorgone::modules::centreon::mbi::libs::bi::DataQuality; - -my ($time, $liveService, $host, $service); -my ($hostBI, $biHost, $hostCentreon, $biService, $timePeriod, $biMetric); -my ($biHostgroup, $biServicecategory, $biHostcategory, $hostgroup, $servicecategory, $hostcategory, $biDataQuality); - -# Initialize objects for program -sub initVars { - my ($etlwk, %options) = @_; - - # instance of - $host = gorgone::modules::centreon::mbi::libs::centreon::Host->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $hostcategory = gorgone::modules::centreon::mbi::libs::centreon::HostCategory->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $servicecategory = gorgone::modules::centreon::mbi::libs::centreon::ServiceCategory->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $hostgroup = gorgone::modules::centreon::mbi::libs::centreon::HostGroup->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $service = gorgone::modules::centreon::mbi::libs::centreon::Service->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $timePeriod = gorgone::modules::centreon::mbi::libs::centreon::Timeperiod->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $biHost = gorgone::modules::centreon::mbi::libs::bi::BIHost->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $biHostgroup = gorgone::modules::centreon::mbi::libs::bi::BIHostGroup->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $biHostcategory = gorgone::modules::centreon::mbi::libs::bi::BIHostCategory->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $biServicecategory = gorgone::modules::centreon::mbi::libs::bi::BIServiceCategory->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $biService = gorgone::modules::centreon::mbi::libs::bi::BIService->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $time = gorgone::modules::centreon::mbi::libs::bi::Time->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $liveService = gorgone::modules::centreon::mbi::libs::bi::LiveService->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $biMetric = gorgone::modules::centreon::mbi::libs::bi::BIMetric->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $biDataQuality = gorgone::modules::centreon::mbi::libs::bi::DataQuality->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); -} - -# temporary method to list liveservices for job configuration in Centreon -sub copyLiveServicesToMonitoringDB { - my ($etlwk, %options) = @_; - - return if ($etlwk->{dbmon_centstorage_con}->sameParams(%{$options{dbbi}->{centstorage}}) == 1); - - $etlwk->{dbmon_centstorage_con}->query({ query => "TRUNCATE TABLE mod_bi_liveservice" }); - my $sth = $etlwk->{dbbi_centstorage_con}->query({ query => "SELECT id, name, timeperiod_id FROM mod_bi_liveservice" }); - while (my $row = $sth->fetchrow_hashref()) { - my $insertQuery = "INSERT INTO mod_bi_liveservice (id, name, timeperiod_id) VALUES (". - $row->{'id'} . ",'" . $row->{name} . "'," . $row->{timeperiod_id} . ")"; - $etlwk->{dbmon_centstorage_con}->query({ query => $insertQuery }); - } -} - -sub truncateDimensionTables { - my ($etlwk, %options) = @_; - - if ($options{options}->{rebuild} == 1 && $options{options}->{nopurge} == 0) { - $biHostgroup->truncateTable(); - $biHostcategory->truncateTable(); - $biServicecategory->truncateTable(); - $biHost->truncateTable(); - $biService->truncateTable(); - $biMetric->truncateTable(); - $time->truncateTable(); - $liveService->truncateTable(); - } -} - -sub denormalizeDimensionsFromCentreon { - my ($etlwk, %options) = @_; - - #set etlProperties for all dimensions object to be able to use it when filtering on hg/hc/sc - $host->setEtlProperties($options{etlProperties}); - $hostcategory->setEtlProperties($options{etlProperties}); - $servicecategory->setEtlProperties($options{etlProperties}); - $hostgroup->setEtlProperties($options{etlProperties}); - $service->setEtlProperties($options{etlProperties}); - - $etlwk->{messages}->writeLog("INFO", "Getting host properties from Centreon database"); - my $rows = $host->getHostGroupAndCategories(); - $etlwk->{messages}->writeLog("INFO", "Updating host dimension in Centstorage"); - if ($options{options}->{rebuild} == 1 && $options{options}->{nopurge} == 0) { - $biHost->insert($rows); - } else { - $biHost->update($rows, $options{etlProperties}->{'tmp.storage.memory'}); - } - - $etlwk->{messages}->writeLog("INFO", "Getting hostgroup properties from Centreon database"); - $rows = $hostgroup->getAllEntries(); - $etlwk->{messages}->writeLog("INFO", "Updating hostgroup dimension in Centstorage"); - $biHostgroup->insert($rows); - - $etlwk->{messages}->writeLog("INFO", "Getting hostcategories properties from Centreon database"); - $rows = $hostcategory->getAllEntries(); - $etlwk->{messages}->writeLog("INFO", "Updating hostcategories dimension in Centstorage"); - $biHostcategory->insert($rows); - - $etlwk->{messages}->writeLog("INFO", "Getting servicecategories properties from Centreon database"); - $rows = $servicecategory->getAllEntries(); - $etlwk->{messages}->writeLog("INFO", "Updating servicecategories dimension in Centstorage"); - $biServicecategory->insert($rows); - $etlwk->{messages}->writeLog("INFO", "Getting service properties from Centreon database"); - - my $hostRows = $biHost->getHostsInfo(); - my $serviceRows = $service->getServicesWithHostAndCategory($hostRows); - $etlwk->{messages}->writeLog("INFO", "Updating service dimension in Centstorage"); - if ($options{options}->{rebuild} == 1 && $options{options}->{nopurge} == 0) { - $biService->insert($serviceRows); - } else { - $biService->update($serviceRows, $options{etlProperties}->{'tmp.storage.memory'}); - } - - if (!defined($options{etlProperties}->{'statistics.type'}) || $options{etlProperties}->{'statistics.type'} ne 'availability') { - $etlwk->{messages}->writeLog("INFO", "Updating metric dimension in Centstorage"); - if ($options{options}->{rebuild} == 1 && $options{options}->{nopurge} == 0) { - $biMetric->insert(); - } else { - $biMetric->update($options{etlProperties}->{'tmp.storage.memory'}); - } - } - - # Getting live services to calculate reporting by time range - $etlwk->{messages}->writeLog("INFO", "Updating liveservice dimension in Centstorage"); - - my $timeperiods = $timePeriod->getPeriods($options{etlProperties}->{'liveservices.availability'}); - $liveService->insertList($timeperiods); - $timeperiods = $timePeriod->getPeriods($options{etlProperties}->{'liveservices.perfdata'}); - $liveService->insertList($timeperiods); - $timeperiods = $timePeriod->getCentilePeriods(); - $liveService->insertList($timeperiods); -} - -sub insertCentileParamToBIStorage{ - my ($etlwk, %options) = @_; - - my %result; - my $sth; - - #Insert potential missing time periods related to centile calculation in mod_bi_liveservices - $sth = $etlwk->{dbbi_centreon_con}->query({ query => "SELECT tp_id, tp_name FROM timeperiod WHERE tp_id IN (SELECT timeperiod_id FROM mod_bi_options_centiles)" }); - while (my $row = $sth->fetchrow_hashref()) { - $result{$row->{tp_id}} = $row->{tp_name}; - } - - #If not time period is found in centile configuration, exit the function - if (%result eq 0){ - $etlwk->{messages}->writeLog("INFO", "No configuration found for centile calculation"); - return; - } - $etlwk->{messages}->writeLog("INFO", "Updating centile properties"); - - my $timeperiods = $timePeriod->getPeriods(\%result); - $liveService->insertList($timeperiods); - - #In case of rebuild, delete all centile parameters - if ($options{options}->{rebuild} == 1){ - $etlwk->{dbbi_centstorage_con}->query({ query => "TRUNCATE TABLE mod_bi_centiles" }); - } - $sth = $etlwk->{dbbi_centreon_con}->query({ query => "select * from mod_bi_options_centiles" }); - while (my $row = $sth->fetchrow_hashref()) { - my ($tpName,$liveServiceId) = $liveService->getLiveServicesByNameForTpId($row->{'timeperiod_id'}); - my $insertQuery = "INSERT IGNORE INTO mod_bi_centiles (id, centile_param, liveservice_id,tp_name) VALUES (".$row->{'id'}.",'".$row->{'centile_param'}."',".$liveServiceId.",'".$tpName."')"; - $etlwk->{dbbi_centstorage_con}->query({ query => $insertQuery }); - } -} - -sub copyCentileToMonitoringDB { - my ($etlwk, %options) = @_; - - return if ($etlwk->{dbmon_centstorage_con}->sameParams(%{$options{dbbi}->{centstorage}}) == 1); - - $etlwk->{dbmon_centstorage_con}->query({ query => "TRUNCATE TABLE mod_bi_centiles" }); - my $sth = $etlwk->{dbbi_centstorage_con}->query({ query => "SELECT id, centile_param, liveservice_id, tp_name FROM mod_bi_centiles" }); - while (my $row = $sth->fetchrow_hashref()) { - my $insertQuery = "INSERT INTO mod_bi_centiles (id, centile_param, liveservice_id,tp_name) VALUES (". - $row->{id} . ",'" . $row->{centile_param} . "'," . $row->{liveservice_id} . ",'" . $row->{tp_name} . "')"; - $etlwk->{dbmon_centstorage_con}->query({ query => $insertQuery }); - } -} - -sub startCbisAclSync{ - my ($etlwk, %options) = @_; - - # create a connecting socket - my $socket = new IO::Socket::INET( - PeerHost => 'localhost', - PeerPort => '1234', - Proto => 'tcp' - ); - - if (!$socket){ - $etlwk->{messages}->writeLog("WARNING", "Can't start ACL synchronization, make sure CBIS is started on port 1234"); - return 0; - } - #die "[ERROR] Cannot connect to CBIS on port 1234" unless $socket; - # XML ACL request - my $req = "\n". - "\n". - " \n". - " \n". - " \n". - "\n"; - $etlwk->{messages}->writeLog("INFO", "Send ACL synchronization signal to CBIS"); - my $size = $socket->send($req); - - # notify server that request has been sent - shutdown($socket, 1); - - # receive a response of up to 1024 characters from server - my $response = ""; - $socket->recv($response, 1024); - $socket->close(); -} - -sub execute { - my ($etlwk, %options) = @_; - - initVars($etlwk, %options); - - $biDataQuality->searchAndDeleteDuplicateEntries(); - if (!defined($options{options}->{centile}) || $options{options}->{centile} == 0) { - truncateDimensionTables($etlwk, %options); - denormalizeDimensionsFromCentreon($etlwk, %options); - copyLiveServicesToMonitoringDB($etlwk, %options); - } - - insertCentileParamToBIStorage($etlwk, %options); - copyCentileToMonitoringDB($etlwk, %options); - startCbisAclSync($etlwk, %options); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/event/main.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/event/main.pm deleted file mode 100644 index b83dd818a5..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/event/main.pm +++ /dev/null @@ -1,259 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etlworkers::event::main; - -use strict; -use warnings; -use gorgone::modules::centreon::mbi::libs::centreon::Timeperiod; -use gorgone::modules::centreon::mbi::libs::bi::HostAvailability; -use gorgone::modules::centreon::mbi::libs::bi::ServiceAvailability; -use gorgone::modules::centreon::mbi::libs::bi::HGMonthAvailability; -use gorgone::modules::centreon::mbi::libs::bi::HGServiceMonthAvailability; -use gorgone::modules::centreon::mbi::libs::bi::Time; -use gorgone::modules::centreon::mbi::libs::bi::MySQLTables; -use gorgone::modules::centreon::mbi::libs::bi::BIHostStateEvents; -use gorgone::modules::centreon::mbi::libs::bi::BIServiceStateEvents; -use gorgone::modules::centreon::mbi::libs::bi::LiveService; -use gorgone::modules::centreon::mbi::libs::centstorage::HostStateEvents; -use gorgone::modules::centreon::mbi::libs::centstorage::ServiceStateEvents; -use gorgone::modules::centreon::mbi::libs::Utils; -use gorgone::standard::misc; - -my ($utils, $time, $tablesManager, $timePeriod); -my ($hostAv, $serviceAv); -my ($hgAv, $hgServiceAv); -my ($biHostEvents, $biServiceEvents); -my ($hostEvents, $serviceEvents); -my ($liveService); - -sub initVars { - my ($etlwk, %options) = @_; - - $utils = gorgone::modules::centreon::mbi::libs::Utils->new($etlwk->{messages}); - $timePeriod = gorgone::modules::centreon::mbi::libs::centreon::Timeperiod->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $time = gorgone::modules::centreon::mbi::libs::bi::Time->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $tablesManager = gorgone::modules::centreon::mbi::libs::bi::MySQLTables->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $biHostEvents = gorgone::modules::centreon::mbi::libs::bi::BIHostStateEvents->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}, $timePeriod); - $biServiceEvents = gorgone::modules::centreon::mbi::libs::bi::BIServiceStateEvents->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}, $timePeriod); - $liveService = gorgone::modules::centreon::mbi::libs::bi::LiveService->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $hostEvents = gorgone::modules::centreon::mbi::libs::centstorage::HostStateEvents->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}, $biHostEvents, $timePeriod); - $serviceEvents = gorgone::modules::centreon::mbi::libs::centstorage::ServiceStateEvents->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}, $biServiceEvents, $timePeriod); - $hostAv = gorgone::modules::centreon::mbi::libs::bi::HostAvailability->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $serviceAv = gorgone::modules::centreon::mbi::libs::bi::ServiceAvailability->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $hgAv = gorgone::modules::centreon::mbi::libs::bi::HGMonthAvailability->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $hgServiceAv = gorgone::modules::centreon::mbi::libs::bi::HGServiceMonthAvailability->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); -} - -sub sql { - my ($etlwk, %options) = @_; - - return if (!defined($options{params}->{sql})); - - foreach (@{$options{params}->{sql}}) { - $etlwk->{messages}->writeLog('INFO', $_->[0]); - if ($options{params}->{db} eq 'centstorage') { - $etlwk->{dbbi_centstorage_con}->query({ query => $_->[1] }); - } elsif ($options{params}->{db} eq 'centreon') { - $etlwk->{dbbi_centreon_con}->query({ query => $_->[1] }); - } - } -} - -sub processEventsHosts { - my ($etlwk, %options) = @_; - - my $mode = 'daily'; - if ($options{options}->{rebuild} == 1) { - $tablesManager->emptyTableForRebuild($biHostEvents->getName(), $tablesManager->dumpTableStructure($biHostEvents->getName()), $biHostEvents->getTimeColumn()); - $mode = 'rebuild'; - } else { - $biHostEvents->deleteUnfinishedEvents(); - } - - if ($options{options}->{rebuild} == 1) { - $tablesManager->dropIndexesFromReportingTable('mod_bi_hoststateevents'); - } - - #Agreggate events by TP and store them into a temporary table (mod_bi_hoststateevents_tmp) - $etlwk->{messages}->writeLog("INFO", "[HOST] Processing host events"); - $hostEvents->agreggateEventsByTimePeriod( - $options{etlProperties}->{'liveservices.availability'}, - $options{start}, - $options{end}, - $options{liveServices}, - $mode - ); - - #Dump the result of aggregated data join to dimensions and load this to the final mod_bi_hoststateevents table - my $request = "INSERT INTO mod_bi_hoststateevents "; - $request .= " SELECT id, t1.modbiliveservice_id, t1.state, t1.start_time, t1.end_time, t1.duration, t1.sla_duration,"; - $request .= " t1.ack_time, t1.last_update from mod_bi_hoststateevents_tmp t1"; - $request .= " INNER JOIN mod_bi_tmp_today_hosts t2 on t1.host_id = t2.host_id"; - - $etlwk->{messages}->writeLog("INFO", "[HOST] Loading calculated events in reporting table"); - $etlwk->{dbbi_centstorage_con}->query({ query => $request }); - - if ($options{options}->{rebuild} == 1 && $options{options}->{rebuild} == 0) { - $etlwk->{messages}->writeLog("DEBUG", "[HOST] Creating index"); - $etlwk->{dbbi_centstorage_con}->query({ query => 'ALTER TABLE mod_bi_hoststateevents ADD INDEX `modbihost_id` (`modbihost_id`,`modbiliveservice_id`,`state`,`start_time`,`end_time`)' }); - $etlwk->{dbbi_centstorage_con}->query({ query => 'ALTER TABLE mod_bi_hoststateevents ADD INDEX `state` (`state`,`modbiliveservice_id`,`start_time`,`end_time`)' }); - $etlwk->{dbbi_centstorage_con}->query({ query => 'ALTER TABLE mod_bi_hoststateevents ADD INDEX `idx_mod_bi_hoststateevents_end_time` (`end_time`)' }); - } -} - -sub processEventsServices { - my ($etlwk, %options) = @_; - - my $mode = 'daily'; - if ($options{options}->{rebuild} == 1) { - $tablesManager->emptyTableForRebuild($biServiceEvents->getName(), $tablesManager->dumpTableStructure($biServiceEvents->getName()), $biServiceEvents->getTimeColumn()); - $mode = 'rebuild'; - } else { - $biServiceEvents->deleteUnfinishedEvents(); - } - - if ($options{options}->{rebuild} == 1) { - $tablesManager->dropIndexesFromReportingTable('mod_bi_servicestateevents'); - } - - #Agreggate events by TP and store them into a temporary table (mod_bi_hoststateevents_tmp) - $etlwk->{messages}->writeLog("INFO", "[SERVICE] Processing service events"); - $serviceEvents->agreggateEventsByTimePeriod( - $options{etlProperties}->{'liveservices.availability'}, - $options{start}, - $options{end}, - $options{liveServices}, - $mode - ); - - #Dump the result of aggregated data join to dimensions and load this to the final mod_bi_hoststateevents table - my $request = "INSERT INTO mod_bi_servicestateevents "; - $request .= " SELECT id,t1.modbiliveservice_id,t1.state,t1.start_time,t1.end_time,t1.duration,t1.sla_duration,"; - $request .= " t1.ack_time,t1.last_update FROM mod_bi_servicestateevents_tmp t1 INNER JOIN mod_bi_tmp_today_services t2 "; - $request .= " ON t1.host_id = t2.host_id AND t1.service_id = t2.service_id"; - - $etlwk->{messages}->writeLog("INFO", "[SERVICE] Loading calculated events in reporting table"); - $etlwk->{dbbi_centstorage_con}->query({ query => $request }); - - if ($options{options}->{rebuild} == 1 && $options{options}->{rebuild} == 0) { - $etlwk->{messages}->writeLog("DEBUG", "[SERVICE] Creating index"); - $etlwk->{dbbi_centstorage_con}->query({ query => 'ALTER TABLE mod_bi_servicestateevents ADD INDEX `modbiservice_id` (`modbiservice_id`,`modbiliveservice_id`,`state`,`start_time`,`end_time`)' }); - $etlwk->{dbbi_centstorage_con}->query({ query => 'ALTER TABLE mod_bi_servicestateevents ADD INDEX `state` (`state`,`modbiliveservice_id`,`start_time`,`end_time`)' }); - $etlwk->{dbbi_centstorage_con}->query({ query => 'ALTER TABLE mod_bi_servicestateevents ADD INDEX `idx_mod_bi_servicestateevents_end_time` (`end_time`)' }); - } -} - -sub events { - my ($etlwk, %options) = @_; - - initVars($etlwk, %options); - - my ($startTimeId, $startUtime) = $time->getEntryID($options{params}->{start}); - my ($endTimeId, $endUtime) = $time->getEntryID($options{params}->{end}); - - my $liveServices = $liveService->getLiveServicesByTpId(); - - if (defined($options{params}->{hosts}) && $options{params}->{hosts} == 1) { - processEventsHosts($etlwk, start => $startUtime, end => $endUtime, liveServices => $liveServices, %options); - } elsif (defined($options{params}->{services}) && $options{params}->{services} == 1) { - processEventsServices($etlwk, start => $startUtime, end => $endUtime, liveServices => $liveServices, %options); - } -} - -sub availabilityDayHosts { - my ($etlwk, %options) = @_; - - $etlwk->{messages}->writeLog("INFO", "[AVAILABILITY] Processing hosts day: $options{params}->{start} => $options{params}->{end} [$options{params}->{liveserviceName}]"); - my $ranges = $timePeriod->getTimeRangesForDay($options{startWeekDay}, $options{params}->{liveserviceName}, $options{startUtime}); - my $dayEvents = $biHostEvents->getDayEvents($options{startUtime}, $options{endUtime}, $options{params}->{liveserviceId}, $ranges); - $hostAv->insertStats($dayEvents, $options{startTimeId}, $options{params}->{liveserviceId}); -} - -sub availabilityDayServices { - my ($etlwk, %options) = @_; - - $etlwk->{messages}->writeLog("INFO", "[AVAILABILITY] Processing services day: $options{params}->{start} => $options{params}->{end} [$options{params}->{liveserviceName}]"); - my $ranges = $timePeriod->getTimeRangesForDay($options{startWeekDay}, $options{params}->{liveserviceName}, $options{startUtime}); - my $dayEvents = $biServiceEvents->getDayEvents($options{startUtime}, $options{endUtime}, $options{params}->{liveserviceId}, $ranges); - $serviceAv->insertStats($dayEvents, $options{startTimeId}, $options{params}->{liveserviceId}); -} - -sub availabilityMonthHosts { - my ($etlwk, %options) = @_; - - $etlwk->{messages}->writeLog("INFO", "[AVAILABILITY] Processing services month: $options{params}->{start} => $options{params}->{end}"); - my $data = $hostAv->getHGMonthAvailability($options{params}->{start}, $options{params}->{end}, $biHostEvents); - $hgAv->insertStats($options{startTimeId}, $data); -} - -sub availabilityMonthServices { - my ($etlwk, %options) = @_; - - $etlwk->{messages}->writeLog("INFO", "[AVAILABILITY] Processing hosts month: $options{params}->{start} => $options{params}->{end}"); - my $data = $serviceAv->getHGMonthAvailability_optimised($options{params}->{start}, $options{params}->{end}, $biServiceEvents); - $hgServiceAv->insertStats($options{startTimeId}, $data); -} - -sub availability { - my ($etlwk, %options) = @_; - - initVars($etlwk, %options); - - my ($startTimeId, $startUtime) = $time->getEntryID($options{params}->{start}); - my ($endTimeId, $endUtime) = $time->getEntryID($options{params}->{end}); - my $startWeekDay = $utils->getDayOfWeek($options{params}->{start}); - - if ($options{params}->{type} eq 'availability_day_hosts') { - availabilityDayHosts( - $etlwk, - startTimeId => $startTimeId, - startUtime => $startUtime, - endTimeId => $endTimeId, - endUtime => $endUtime, - startWeekDay => $startWeekDay, - %options - ); - } elsif ($options{params}->{type} eq 'availability_day_services') { - availabilityDayServices( - $etlwk, - startTimeId => $startTimeId, - startUtime => $startUtime, - endTimeId => $endTimeId, - endUtime => $endUtime, - startWeekDay => $startWeekDay, - %options - ); - } elsif ($options{params}->{type} eq 'availability_month_services') { - availabilityMonthServices( - $etlwk, - startTimeId => $startTimeId, - %options - ); - } elsif ($options{params}->{type} eq 'availability_month_hosts') { - availabilityMonthHosts( - $etlwk, - startTimeId => $startTimeId, - %options - ); - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/hooks.pm deleted file mode 100644 index b286e7192a..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/hooks.pm +++ /dev/null @@ -1,236 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etlworkers::hooks; - -use warnings; -use strict; -use JSON::XS; -use gorgone::class::core; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::modules::centreon::mbi::etlworkers::class; - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'mbi-etlworkers'; -use constant EVENTS => [ - { event => 'CENTREONMBIETLWORKERSIMPORT' }, - { event => 'CENTREONMBIETLWORKERSDIMENSIONS' }, - { event => 'CENTREONMBIETLWORKERSEVENT' }, - { event => 'CENTREONMBIETLWORKERSPERFDATA' }, - { event => 'CENTREONMBIETLWORKERSREADY' } -]; - -my $config_core; -my $config; - -my $pools = {}; -my $pools_pid = {}; -my $rr_current = 0; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - - $config->{pool} = defined($config->{pool}) && $config->{pool} =~ /(\d+)/ ? $1 : 8; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - for my $pool_id (1..$config->{pool}) { - create_child(dbh => $options{dbh}, pool_id => $pool_id, logger => $options{logger}); - } -} - -sub routing { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - $options{logger}->writeLogError("[" . NAME . "] Cannot decode json data: " . $options{frame}->getLastError()); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => NAME . ' - cannot decode json' }, - json_encode => 1 - }); - return undef; - } - - if ($options{action} eq 'CENTREONMBIETLWORKERSREADY') { - if (defined($data->{pool_id})) { - $pools->{ $data->{pool_id} }->{ready} = 1; - } - return undef; - } - - my $pool_id = rr_pool(); - if (!defined($pool_id)) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => NAME . ' - no pool ready' }, - json_encode => 1 - }); - return undef; - } - - my $identity = 'gorgone-' . NAME . '-' . $pool_id; - - $options{gorgone}->send_internal_message( - identity => $identity, - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - foreach my $pool_id (keys %$pools) { - if (defined($pools->{$pool_id}->{running}) && $pools->{$pool_id}->{running} == 1) { - $options{logger}->writeLogDebug("[" . NAME . "] Send TERM signal for pool '" . $pool_id . "'"); - CORE::kill('TERM', $pools->{$pool_id}->{pid}); - } - } -} - -sub kill { - my (%options) = @_; - - foreach (keys %$pools) { - if ($pools->{$_}->{running} == 1) { - $options{logger}->writeLogDebug("[" . NAME . "] Send KILL signal for pool '" . $_ . "'"); - CORE::kill('KILL', $pools->{$_}->{pid}); - } - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check_create_child { - my (%options) = @_; - - return if ($stop == 1); - - # Check if we need to create a child - for my $pool_id (1..$config->{pool}) { - if (!defined($pools->{$pool_id})) { - create_child(dbh => $options{dbh}, pool_id => $pool_id, logger => $options{logger}); - } - } -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($pools_pid->{$pid})); - - # If someone dead, we recreate - my $pool_id = $pools_pid->{$pid}; - delete $pools->{$pools_pid->{$pid}}; - delete $pools_pid->{$pid}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(dbh => $options{dbh}, pool_id => $pool_id, logger => $options{logger}); - } - } - - check_create_child(dbh => $options{dbh}, logger => $options{logger}); - - foreach (keys %$pools) { - $count++ if ($pools->{$_}->{running} == 1); - } - - return ($count, 1); -} - -sub broadcast { - my (%options) = @_; - - foreach my $pool_id (keys %$pools) { - next if ($pools->{$pool_id}->{ready} != 1); - - $options{gorgone}->send_internal_message( - identity => 'gorgone-' . NAME . '-' . $pool_id, - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); - } -} - -# Specific functions -sub rr_pool { - my (%options) = @_; - - my ($loop, $i) = ($config->{pool}, 0); - while ($i <= $loop) { - $rr_current = $rr_current % $config->{pool}; - if ($pools->{$rr_current + 1}->{ready} == 1) { - $rr_current++; - return $rr_current; - } - $rr_current++; - $i++; - } - - return undef; -} - -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[" . NAME . "] Create module '" . NAME . "' child process for pool id '" . $options{pool_id} . "'"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-' . NAME; - my $module = gorgone::modules::centreon::mbi::etlworkers::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - pool_id => $options{pool_id}, - container_id => $options{pool_id} - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[" . NAME . "] PID $child_pid (gorgone-" . NAME . ") for pool id '" . $options{pool_id} . "'"); - $pools->{$options{pool_id}} = { pid => $child_pid, ready => 0, running => 1 }; - $pools_pid->{$child_pid} = $options{pool_id}; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/import/main.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/import/main.pm deleted file mode 100644 index 2430aea722..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/import/main.pm +++ /dev/null @@ -1,86 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etlworkers::import::main; - -use strict; -use warnings; -use gorgone::standard::misc; -use File::Basename; - -sub sql { - my ($etlwk, %options) = @_; - - return if (!defined($options{params}->{sql})); - - foreach (@{$options{params}->{sql}}) { - $etlwk->{messages}->writeLog('INFO', $_->[0]); - if ($options{params}->{db} eq 'centstorage') { - $etlwk->{dbbi_centstorage_con}->query({ query => $_->[1] }); - } elsif ($options{params}->{db} eq 'centreon') { - $etlwk->{dbbi_centreon_con}->query({ query => $_->[1] }); - } - } -} - -sub command { - my ($etlwk, %options) = @_; - - return if (!defined($options{params}->{command}) || $options{params}->{command} eq ''); - - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => $options{params}->{command}, - timeout => 7200, - wait_exit => 1, - redirect_stderr => 1, - logger => $options{logger} - ); - - if ($error != 0) { - die $options{params}->{message} . ": execution failed: $stdout"; - } - - $etlwk->{messages}->writeLog('INFO', $options{params}->{message}); - $etlwk->{logger}->writeLogDebug("[mbi-etlworkers] succeeded command (code: $return_code): $stdout"); -} - -sub load { - my ($etlwk, %options) = @_; - - return if (!defined($options{params}->{file})); - - my ($file, $dir) = File::Basename::fileparse($options{params}->{file}); - - if (! -d "$dir" && ! -w "$dir") { - $etlwk->{messages}->writeLog('ERROR', "Cannot write into directory " . $dir); - } - - command($etlwk, params => { command => $options{params}->{dump}, message => $options{params}->{message} }); - - if ($options{params}->{db} eq 'centstorage') { - $etlwk->{dbbi_centstorage_con}->query({ query => $options{params}->{load} }); - } elsif ($options{params}->{db} eq 'centreon') { - $etlwk->{dbbi_centreon_con}->query({ query => $options{params}->{load} }); - } - - unlink($options{params}->{file}); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/perfdata/main.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/perfdata/main.pm deleted file mode 100644 index ead6bbd9c6..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/etlworkers/perfdata/main.pm +++ /dev/null @@ -1,190 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::etlworkers::perfdata::main; - -use strict; -use warnings; - -use gorgone::modules::centreon::mbi::libs::centreon::Timeperiod; -use gorgone::modules::centreon::mbi::libs::centreon::CentileProperties; -use gorgone::modules::centreon::mbi::libs::bi::LiveService; -use gorgone::modules::centreon::mbi::libs::bi::Time; -use gorgone::modules::centreon::mbi::libs::Utils; -use gorgone::modules::centreon::mbi::libs::centstorage::Metrics; -use gorgone::modules::centreon::mbi::libs::bi::MetricDailyValue; -use gorgone::modules::centreon::mbi::libs::bi::MetricHourlyValue; -use gorgone::modules::centreon::mbi::libs::bi::MetricCentileValue; -use gorgone::modules::centreon::mbi::libs::bi::MetricMonthCapacity; -use gorgone::standard::misc; - -my ($utils, $time, $timePeriod, $centileProperties, $liveService); -my ($metrics); -my ($dayAgregates, $hourAgregates, $centileAgregates, $metricMonthCapacity); - -sub initVars { - my ($etlwk, %options) = @_; - - $timePeriod = gorgone::modules::centreon::mbi::libs::centreon::Timeperiod->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $centileProperties = gorgone::modules::centreon::mbi::libs::centreon::CentileProperties->new($etlwk->{messages}, $etlwk->{dbbi_centreon_con}); - $liveService = gorgone::modules::centreon::mbi::libs::bi::LiveService->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $time = gorgone::modules::centreon::mbi::libs::bi::Time->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - $utils = gorgone::modules::centreon::mbi::libs::Utils->new($etlwk->{messages}); - $metrics = gorgone::modules::centreon::mbi::libs::centstorage::Metrics->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}, $options{pool_id}); - $dayAgregates = gorgone::modules::centreon::mbi::libs::bi::MetricDailyValue->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}, $options{pool_id}); - $hourAgregates = gorgone::modules::centreon::mbi::libs::bi::MetricHourlyValue->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}, $options{pool_id}); - $metricMonthCapacity = gorgone::modules::centreon::mbi::libs::bi::MetricMonthCapacity->new($etlwk->{messages}, $etlwk->{dbbi_centstorage_con}); - - $centileAgregates = gorgone::modules::centreon::mbi::libs::bi::MetricCentileValue->new( - logger => $etlwk->{messages}, - centstorage => $etlwk->{dbbi_centstorage_con}, - centreon => $etlwk->{dbbi_centreon_con}, - time => $time, - centileProperties => $centileProperties, - timePeriod => $timePeriod, - liveService => $liveService - ); -} - -sub sql { - my ($etlwk, %options) = @_; - - return if (!defined($options{params}->{sql})); - - foreach (@{$options{params}->{sql}}) { - $etlwk->{messages}->writeLog('INFO', $_->[0]); - if ($options{params}->{db} eq 'centstorage') { - $etlwk->{dbbi_centstorage_con}->query({ query => $_->[1] }); - } elsif ($options{params}->{db} eq 'centreon') { - $etlwk->{dbbi_centreon_con}->query({ query => $_->[1] }); - } - } -} - -sub perfdataDay { - my ($etlwk, %options) = @_; - - my ($currentDayId, $currentDayUtime) = $time->getEntryID($options{params}->{start}); - my $ranges = $timePeriod->getTimeRangesForDayByDateTime( - $options{params}->{liveserviceName}, - $options{params}->{start}, - $utils->getDayOfWeek($options{params}->{start}) - ); - if (scalar(@$ranges)) { - $etlwk->{messages}->writeLog("INFO", "[PERFDATA] Processing day: $options{params}->{start} => $options{params}->{end} [$options{params}->{liveserviceName}]"); - $metrics->getMetricsValueByDay($ranges, $options{etlProperties}->{'tmp.storage.memory'}); - $dayAgregates->insertValues($options{params}->{liveserviceId}, $currentDayId); - } -} - -sub perfdataMonth { - my ($etlwk, %options) = @_; - - my ($previousMonthStartTimeId, $previousMonthStartUtime) = $time->getEntryID($options{params}->{start}); - my ($previousMonthEndTimeId, $previousMonthEndUtime) = $time->getEntryID($options{params}->{end}); - - $etlwk->{messages}->writeLog("INFO", "[PERFDATA] Processing month: $options{params}->{start} => $options{params}->{end}"); - my $data = $dayAgregates->getMetricCapacityValuesOnPeriod($previousMonthStartTimeId, $previousMonthEndTimeId, $options{etlProperties}); - $metricMonthCapacity->insertStats($previousMonthStartTimeId, $data); -} - -sub perfdataHour { - my ($etlwk, %options) = @_; - - $etlwk->{messages}->writeLog("INFO", "[PERFDATA] Processing hours: $options{params}->{start} => $options{params}->{end}"); - - $metrics->getMetricValueByHour($options{params}->{start}, $options{params}->{end}, $options{etlProperties}->{'tmp.storage.memory'}); - $hourAgregates->insertValues(); -} - -sub perfdata { - my ($etlwk, %options) = @_; - - initVars($etlwk, %options); - - if ($options{params}->{type} eq 'perfdata_day') { - perfdataDay($etlwk, %options); - } elsif ($options{params}->{type} eq 'perfdata_month') { - perfdataMonth($etlwk, %options); - } elsif ($options{params}->{type} eq 'perfdata_hour') { - perfdataHour($etlwk, %options); - } -} - -sub centileDay { - my ($etlwk, %options) = @_; - - my ($currentDayId) = $time->getEntryID($options{params}->{start}); - - my $metricsId = $centileAgregates->getMetricsCentile(etlProperties => $options{etlProperties}); - $centileAgregates->calcMetricsCentileValueMultipleDays( - metricsId => $metricsId, - start => $options{params}->{start}, - end => $options{params}->{end}, - granularity => 'day', - timeId => $currentDayId - ); -} - -sub centileMonth { - my ($etlwk, %options) = @_; - - my ($previousMonthStartTimeId) = $time->getEntryID($options{params}->{start}); - - my $metricsId = $centileAgregates->getMetricsCentile(etlProperties => $options{etlProperties}); - $centileAgregates->calcMetricsCentileValueMultipleDays( - metricsId => $metricsId, - start => $options{params}->{start}, - end => $options{params}->{end}, - granularity => 'month', - timeId => $previousMonthStartTimeId - ); -} - -sub centileWeek { - my ($etlwk, %options) = @_; - - my ($currentDayId) = $time->getEntryID($options{params}->{start}); - - my $metricsId = $centileAgregates->getMetricsCentile(etlProperties => $options{etlProperties}); - $centileAgregates->calcMetricsCentileValueMultipleDays( - metricsId => $metricsId, - start => $options{params}->{start}, - end => $options{params}->{end}, - granularity => 'week', - timeId => $currentDayId - ); -} - -sub centile { - my ($etlwk, %options) = @_; - - initVars($etlwk, %options); - - if ($options{params}->{type} eq 'centile_day') { - centileDay($etlwk, %options); - } elsif ($options{params}->{type} eq 'centile_month') { - centileMonth($etlwk, %options); - } elsif ($options{params}->{type} eq 'centile_week') { - centileWeek($etlwk, %options); - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/Messages.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/Messages.pm deleted file mode 100644 index 52fa032ae4..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/Messages.pm +++ /dev/null @@ -1,55 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::Messages; - -sub new { - my $class = shift; - my $self = {}; - - $self->{messages} = []; - - bless $self, $class; - return $self; -} - -sub writeLog { - my ($self, $severity, $message, $nodie) = @_; - - $severity = lc($severity); - - my %severities = ('debug' => 'D', 'info' => 'I', 'warning' => 'I', 'error' => 'E', 'fatal' => 'F'); - if ($severities{$severity} eq 'E' || $severities{$severity} eq 'F') { - die $message if (!defined($nodie) || $nodie == 0); - } - - push @{$self->{messages}}, [$severities{$severity}, $message]; -} - -sub getLogs { - my ($self) = @_; - - return $self->{messages}; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/Utils.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/Utils.pm deleted file mode 100644 index ef2a404d3d..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/Utils.pm +++ /dev/null @@ -1,251 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; -use POSIX; -use Time::Local; -use Tie::File; -use DateTime; - -package gorgone::modules::centreon::mbi::libs::Utils; - -sub new { - my $class = shift; - my $self = {}; - bless $self, $class; - - $self->{logger} = shift; - $self->{tz} = DateTime::TimeZone->new(name => 'local')->name(); - return $self; -} - -sub checkBasicOptions { - my ($self, $options) = @_; - - # check execution mode daily to extract yesterday data or rebuild to get more historical data - if (($options->{daily} == 0 && $options->{rebuild} == 0 && (!defined($options->{create_tables}) || $options->{create_tables} == 0) && (!defined($options->{centile}) || $options->{centile} == 0)) - || ($options->{daily} == 1 && $options->{rebuild} == 1)) { - $self->{logger}->writeLogError("Specify one execution method. Check program help for more informations"); - return 1; - } - - # check if options are set correctly for rebuild mode - if (($options->{rebuild} == 1 || (defined($options->{create_tables}) && $options->{create_tables} == 1)) - && ($options->{start} ne '' && $options->{end} eq '') - || ($options->{start} eq '' && $options->{end} ne '')) { - $self->{logger}->writeLogError("Specify both options --start and --end or neither of them to use default data retention options"); - return 1; - } - # check start and end dates format - if ($options->{rebuild} == 1 && $options->{start} ne '' && $options->{end} ne '' - && !$self->checkDateFormat($options->{start}, $options->{end})) { - $self->{logger}->writeLogError("Verify period start or end date format"); - return 1; - } - - return 0; -} - -sub buildCliMysqlArgs { - my ($self, $con) = @_; - - my $args = '-u "' . $con->{user} . '" ' . - '-p"' . $con->{password} . '" ' . - '-h "' . $con->{host} . '" ' . - '-P ' . $con->{port}; - return $args; -} - -sub getYesterdayTodayDate { - my ($self) = @_; - - my $dt = DateTime->from_epoch( - epoch => time(), - time_zone => $self->{tz} - ); - - my $month = $dt->month(); - $month = '0' . $month if ($month < 10); - my $day = $dt->day(); - $day = '0' . $day if ($day < 10); - my $today = $dt->year() . '-' . $month . '-' . $day; - - $dt->subtract(days => 1); - $month = $dt->month(); - $month = '0' . $month if ($month < 10); - $day = $dt->day(); - $day = '0' . $day if ($day < 10); - my $yesterday = $dt->year() . '-' . $month . '-' . $day; - - return ($yesterday, $today); -} - -sub subtractDateMonths { - my ($self, $date, $num) = @_; - - if ($date !~ /(\d{4})-(\d{2})-(\d{2})/) { - $self->{logger}->writeLog('ERROR', "Verify date format"); - } - - my $dt = DateTime->new(year => $1, month => $2, day => $3, hour => 0, minute => 0, second => 0, time_zone => $self->{tz})->subtract(months => $num); - - my $month = $dt->month(); - $month = '0' . $month if ($month < 10); - my $day = $dt->day(); - $day = '0' . $day if ($day < 10); - return $dt->year() . '-' . $month . '-' . $day; -} - -sub subtractDateDays { - my ($self, $date, $num) = @_; - - if ($date !~ /(\d{4})-(\d{2})-(\d{2})/) { - $self->{logger}->writeLog('ERROR', "Verify date format"); - } - - my $dt = DateTime->new(year => $1, month => $2, day => $3, hour => 0, minute => 0, second => 0, time_zone => $self->{tz})->subtract(days => $num); - - my $month = $dt->month(); - $month = '0' . $month if ($month < 10); - my $day = $dt->day(); - $day = '0' . $day if ($day < 10); - return $dt->year() . '-' . $month . '-' . $day; -} - -sub getDayOfWeek { - my ($self, $date) = @_; - - if ($date !~ /(\d{4})-(\d{2})-(\d{2})/) { - $self->{logger}->writeLog('ERROR', "Verify date format"); - } - - return lc(DateTime->new(year => $1, month => $2, day => $3, hour => 0, minute => 0, second => 0, time_zone => $self->{tz})->day_name()); -} - -sub getDateEpoch { - my ($self, $date) = @_; - - if ($date !~ /(\d{4})-(\d{2})-(\d{2})/) { - $self->{logger}->writeLog('ERROR', "Verify date format"); - } - - my $epoch = DateTime->new(year => $1, month => $2, day => $3, hour => 0, minute => 0, second => 0, time_zone => $self->{tz})->epoch(); - $date =~ s/-//g; - - return wantarray ? ($epoch, $date) : $epoch; -} - -sub getRangePartitionDate { - my ($self, $start, $end) = @_; - - if ($start !~ /(\d{4})-(\d{2})-(\d{2})/) { - $self->{logger}->writeLog('ERROR', "Verify period start format"); - } - my $dt1 = DateTime->new(year => $1, month => $2, day => $3, hour => 0, minute => 0, second => 0, time_zone => $self->{tz}); - - if ($end !~ /(\d{4})-(\d{2})-(\d{2})/) { - $self->{logger}->writeLog('ERROR', "Verify period end format"); - } - my $dt2 = DateTime->new(year => $1, month => $2, day => $3, hour => 0, minute => 0, second => 0, time_zone => $self->{tz}); - - my $epoch = $dt1->epoch(); - my $epoch_end = $dt2->epoch(); - if ($epoch_end <= $epoch) { - $self->{logger}->writeLog('ERROR', "Period end date is older"); - } - - my $partitions = []; - while ($epoch < $epoch_end) { - $dt1->add(days => 1); - - $epoch = $dt1->epoch(); - my $month = $dt1->month(); - $month = '0' . $month if ($month < 10); - my $day = $dt1->day(); - $day = '0' . $day if ($day < 10); - - push @$partitions, { - name => $dt1->year() . $month . $day, - date => $dt1->year() . '-' . $month . '-' . $day, - epoch => $epoch - }; - } - - return $partitions; -} - -sub checkDateFormat { - my ($self, $start, $end) = @_; - - if (defined($start) && $start =~ /[1-2][0-9]{3}\-[0-1][0-9]\-[0-3][0-9]/ - && defined($end) && $end =~ /[1-2][0-9]{3}\-[0-1][0-9]\-[0-3][0-9]/) { - return 1; - } - return 0; -} - -sub getRebuildPeriods { - my ($self, $start, $end) = @_; - - my ($day,$month,$year) = (localtime($start))[3,4,5]; - $start = POSIX::mktime(0,0,0,$day,$month,$year,0,0,-1); - my $previousDay = POSIX::mktime(0,0,0,$day - 1,$month,$year,0,0,-1); - my @days = (); - while ($start < $end) { - # if there is few hour gap (time change : winter/summer), we also readjust it - if ($start == $previousDay) { - $start = POSIX::mktime(0,0,0, ++$day, $month, $year,0,0,-1); - } - my $dayEnd = POSIX::mktime(0, 0, 0, ++$day, $month, $year, 0, 0, -1); - - my %period = ("start" => $start, "end" => $dayEnd); - $days[scalar(@days)] = \%period; - $previousDay = $start; - $start = $dayEnd; - } - return (\@days); -} - -#parseFlatFile (file, key,value) : replace a line with a key by a value (entire line) to the specified file -sub parseAndReplaceFlatFile{ - my $self = shift; - my $file = shift; - my $key = shift; - my $value = shift; - - if (!-e $file) { - $self->{logger}->writeLog('ERROR', "File missing [".$file."]. Make sure you installed all the pre-requisites before executing this script"); - } - - tie my @flatfile, 'Tie::File', $file or die $!; - - foreach my $line(@flatfile) - { - if( $line =~ m/$key/ ) { - my $previousLine = $line; - $line =~ s/$key/$value/g; - $self->{logger}->writeLog('DEBUG', "[".$file."]"); - $self->{logger}->writeLog('DEBUG', "Replacing [".$previousLine."] by [".$value."]"); - } - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHost.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHost.pm deleted file mode 100644 index 5ba2c40e66..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHost.pm +++ /dev/null @@ -1,233 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::BIHost; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{"today_table"} = "mod_bi_tmp_today_hosts"; - $self->{"tmp_comp"} = "mod_bi_tmp_hosts"; - $self->{"tmp_comp_storage"} = "mod_bi_tmp_hosts_storage"; - $self->{"table"} = "mod_bi_hosts"; - bless $self, $class; - return $self; -} - -sub getHostsInfo { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "SELECT `id`, `host_id`, `host_name`, `hc_id`, `hc_name`, `hg_id`, `hg_name`"; - $query .= " FROM `".$self->{"today_table"}."`"; - my $sth = $db->query({ query => $query }); - my %result = (); - while (my $row = $sth->fetchrow_hashref()) { - if (defined($result{$row->{'host_id'}})) { - my $tab_ref = $result{$row->{'host_id'}}; - my @tab = @$tab_ref; - push @tab , $row->{"host_id"}.";".$row->{"host_name"}.";". - $row->{"hg_id"}.";".$row->{"hg_name"}.";". - $row->{"hc_id"}.";".$row->{"hc_name"}; - $result{$row->{'host_id'}} = \@tab; - }else { - my @tab = ($row->{"host_id"}.";".$row->{"host_name"}.";". - $row->{"hg_id"}.";".$row->{"hg_name"}.";". - $row->{"hc_id"}.";".$row->{"hc_name"}); - $result{$row->{'host_id'}} = \@tab; - } - } - $sth->finish(); - return (\%result); -} - -sub insert { - my $self = shift; - my $data = shift; - my $db = $self->{"centstorage"}; - $self->insertIntoTable("".$self->{"table"}."", $data); - $self->createTempTodayTable("false"); - my $fields = "id, host_name, host_id, hc_id, hc_name, hg_id, hg_name"; - my $query = "INSERT INTO ".$self->{"today_table"}." (".$fields.")"; - $query .= " SELECT ".$fields." FROM ".$self->{"table"}." "; - $db->query({ query => $query }); -} - -sub update { - my ($self, $data, $useMemory) = @_; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - $self->createTempComparisonTable($useMemory); - $self->insertIntoTable($self->{"tmp_comp"}, $data); - $self->createTempStorageTable($useMemory); - $self->joinNewAndCurrentEntries(); - $self->insertNewEntries(); - $db->query({ query => "DROP TABLE `".$self->{"tmp_comp_storage"}."`" }); - $self->createTempTodayTable("false"); - $self->insertTodayEntries(); - $db->query({ query => "DROP TABLE `".$self->{"tmp_comp"}."`" }); -} - -sub insertIntoTable { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my $table = shift; - my $data = shift; - my $query = "INSERT INTO `".$table."`". - " (`host_id`, `host_name`, `hg_id`, `hg_name`, `hc_id`, `hc_name`)". - " VALUES (?,?,?,?,?,?)"; - my $sth = $db->prepare($query); - my $inst = $db->getInstance; - $inst->begin_work; - my $counter = 0; - - foreach (@$data) { - my ($host_id, $host_name, $hg_id, $hg_name, $hc_id, $hc_name) = split(";", $_); - $sth->bind_param(1, $host_id); - $sth->bind_param(2, $host_name); - $sth->bind_param(3, $hg_id); - $sth->bind_param(4, $hg_name); - $sth->bind_param(5, $hc_id); - $sth->bind_param(6, $hc_name); - $sth->execute; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", $self->{"table"}." insertion execute error : ".$inst->errstr); - } - if ($counter >= 1000) { - $counter = 0; - $inst->commit; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", $self->{"table"}." insertion commit error : ".$inst->errstr); - } - $inst->begin_work; - } - $counter++; - } - $inst->commit; -} - -sub createTempComparisonTable { - my ($self, $useMemory) = @_; - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE IF EXISTS `" . $self->{"tmp_comp"} . "`" }); - my $query = "CREATE TABLE `".$self->{"tmp_comp"}."` ("; - $query .= "`host_id` int(11) NOT NULL,`host_name` varchar(255) NOT NULL,"; - $query .= "`hc_id` int(11) DEFAULT NULL, `hc_name` varchar(255) NOT NULL,"; - $query .= "`hg_id` int(11) DEFAULT NULL, `hg_name` varchar(255) NOT NULL"; - if (defined($useMemory) && $useMemory eq "true") { - $query .= ") ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - }else { - $query .= ") ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $query }); -} - -sub createTempStorageTable { - my ($self,$useMemory) = @_; - my $db = $self->{"centstorage"}; - - $db->query({ query => "DROP TABLE IF EXISTS `" . $self->{"tmp_comp_storage"} . "`" }); - my $query = "CREATE TABLE `".$self->{"tmp_comp_storage"}."` ("; - $query .= "`id` INT NOT NULL,"; - $query .= "`host_id` int(11) NOT NULL,`host_name` varchar(255) NOT NULL,"; - $query .= "`hc_id` int(11) DEFAULT NULL, `hc_name` varchar(255) NOT NULL,"; - $query .= "`hg_id` int(11) DEFAULT NULL, `hg_name` varchar(255) NOT NULL,"; - $query .= " KEY `id` (`id`)"; - if (defined($useMemory) && $useMemory eq "true") { - $query .= ") ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - }else { - $query .= ") ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $query }); -} - -sub createTempTodayTable { - my ($self,$useMemory) = @_; - my $db = $self->{"centstorage"}; - - $db->query({ query => "DROP TABLE IF EXISTS `".$self->{"today_table"}."`" }); - my $query = "CREATE TABLE `".$self->{"today_table"}."` ("; - $query .= "`id` INT NOT NULL,"; - $query .= "`host_id` int(11) NOT NULL,`host_name` varchar(255) NOT NULL,"; - $query .= "`hc_id` int(11) DEFAULT NULL, `hc_name` varchar(255) NOT NULL,"; - $query .= "`hg_id` int(11) DEFAULT NULL, `hg_name` varchar(255) NOT NULL,"; - $query .= " KEY `id` (`host_id`)"; - if (defined($useMemory) && $useMemory eq "true") { - $query .= ") ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - }else { - $query .= ") ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $query }); -} - -sub joinNewAndCurrentEntries { - my ($self) = @_; - my $db = $self->{"centstorage"}; - - my $query = "INSERT INTO ".$self->{"tmp_comp_storage"}. " (id, host_name, host_id, hc_id, hc_name, hg_id, hg_name)"; - $query .= " SELECT IFNULL(h.id, 0), t.host_name, t.host_id, t.hc_id, t.hc_name, t.hg_id, t.hg_name FROM ".$self->{"tmp_comp"}." t"; - $query .= " LEFT JOIN ".$self->{"table"}." h USING (host_name, host_id, hc_id, hc_name, hg_id, hg_name)"; - $db->query({ query => $query }); -} - -sub insertNewEntries { - my ($self) = @_; - my $db = $self->{"centstorage"}; - my $fields = "host_name, host_id, hc_id, hc_name, hg_id, hg_name"; - my $query = " INSERT INTO `".$self->{"table"}."` (".$fields.") "; - $query .= " SELECT ".$fields." FROM ".$self->{"tmp_comp_storage"}; - $query .= " WHERE id = 0"; - $db->query({ query => $query }); -} - -sub insertTodayEntries { - my ($self) = @_; - my $db = $self->{"centstorage"}; - my $fields = "host_name, host_id, hc_id, hc_name, hg_id, hg_name"; - my $query = "INSERT INTO ".$self->{"today_table"}." (id, host_name, host_id, hc_id, hc_name, hg_id, hg_name)"; - $query .= " SELECT h.id, t.host_name, t.host_id, t.hc_id, t.hc_name, t.hg_id, t.hg_name FROM ".$self->{"tmp_comp"}." t"; - $query .= " JOIN ".$self->{"table"}." h USING (host_name, host_id, hc_id, hc_name, hg_id, hg_name)"; - $db->query({ query => $query }); -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - - $db->query({ query => "TRUNCATE TABLE `".$self->{"table"}."`" }); - $db->query({ query => "ALTER TABLE `".$self->{"table"}."` AUTO_INCREMENT=1" }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostCategory.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostCategory.pm deleted file mode 100644 index ad0a4442b6..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostCategory.pm +++ /dev/null @@ -1,129 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::BIHostCategory; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - bless $self, $class; - return $self; -} - -sub getAllEntries { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "SELECT `hc_id`, `hc_name`"; - $query .= " FROM `mod_bi_hostcategories`"; - my $sth = $db->query({ query => $query }); - my @entries = (); - while (my $row = $sth->fetchrow_hashref()) { - push @entries, $row->{"hc_id"}.";".$row->{"hc_name"}; - } - $sth->finish(); - return (\@entries); -} - -sub getEntryIds { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "SELECT `id`, `hc_id`, `hc_name`"; - $query .= " FROM `mod_bi_hostcategories`"; - my $sth = $db->query({ query => $query }); - my %entries = (); - while (my $row = $sth->fetchrow_hashref()) { - $entries{$row->{"hc_id"}.";".$row->{"hc_name"}} = $row->{"id"}; - } - $sth->finish(); - return (\%entries); -} - -sub entryExists { - my $self = shift; - my ($value, $entries) = (shift, shift); - foreach(@$entries) { - if ($value eq $_) { - return 1; - } - } - return 0; -} -sub insert { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my $data = shift; - my $query = "INSERT INTO `mod_bi_hostcategories`". - " (`hc_id`, `hc_name`)". - " VALUES (?,?)"; - my $sth = $db->prepare($query); - my $inst = $db->getInstance; - $inst->begin_work; - my $counter = 0; - - my $existingEntries = $self->getAllEntries; - foreach (@$data) { - if (!$self->entryExists($_, $existingEntries)) { - my ($hc_id, $hc_name) = split(";", $_); - $sth->bind_param(1, $hc_id); - $sth->bind_param(2, $hc_name); - $sth->execute; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", "hostcategories insertion execute error : ".$inst->errstr); - } - if ($counter >= 1000) { - $counter = 0; - $inst->commit; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", "hostcategories insertion commit error : ".$inst->errstr); - } - $inst->begin_work; - } - $counter++; - } - } - $inst->commit; -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "TRUNCATE TABLE `mod_bi_hostcategories`"; - $db->query({ query => $query }); - $db->query({ query => "ALTER TABLE `mod_bi_hostcategories` AUTO_INCREMENT=1" }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostGroup.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostGroup.pm deleted file mode 100644 index f5cdcf21b5..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostGroup.pm +++ /dev/null @@ -1,131 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::BIHostGroup; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - bless $self, $class; - return $self; -} - - -sub getAllEntries { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "SELECT `id`, `hg_id`, `hg_name`"; - $query .= " FROM `mod_bi_hostgroups`"; - my $sth = $db->query({ query => $query }); - my @entries = (); - while (my $row = $sth->fetchrow_hashref()) { - push @entries, $row->{"hg_id"}.";".$row->{"hg_name"}; - } - $sth->finish(); - return (\@entries); -} - -sub getEntryIds { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "SELECT `id`, `hg_id`, `hg_name`"; - $query .= " FROM `mod_bi_hostgroups`"; - my $sth = $db->query({ query => $query }); - my %entries = (); - while (my $row = $sth->fetchrow_hashref()) { - $entries{$row->{"hg_id"}.";".$row->{"hg_name"}} = $row->{"id"}; - } - $sth->finish(); - return (\%entries); -} - -sub entryExists { - my $self = shift; - my ($value, $entries) = (shift, shift); - foreach(@$entries) { - if ($value eq $_) { - return 1; - } - } - return 0; -} -sub insert { - my $self = shift; - - my $db = $self->{centstorage}; - my $logger = $self->{logger}; - my $data = shift; - my $query = "INSERT INTO `mod_bi_hostgroups`". - " (`hg_id`, `hg_name`)". - " VALUES (?,?)"; - my $sth = $db->prepare($query); - my $inst = $db->getInstance(); - $inst->begin_work(); - my $counter = 0; - - my $existingEntries = $self->getAllEntries(); - foreach (@$data) { - if (!$self->entryExists($_, $existingEntries)) { - my ($hg_id, $hg_name) = split(";", $_); - $sth->bind_param(1, $hg_id); - $sth->bind_param(2, $hg_name); - $sth->execute; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", "hostgroups insertion execute error : ".$inst->errstr); - } - if ($counter >= 1000) { - $counter = 0; - $inst->commit; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", "hostgroups insertion commit error : ".$inst->errstr); - } - $inst->begin_work; - } - $counter++; - } - } - $inst->commit(); -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "TRUNCATE TABLE `mod_bi_hostgroups`"; - $db->query({ query => $query }); - $db->query({ query => "ALTER TABLE `mod_bi_hostgroups` AUTO_INCREMENT=1" }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostStateEvents.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostStateEvents.pm deleted file mode 100644 index e89e20bf06..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIHostStateEvents.pm +++ /dev/null @@ -1,243 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::BIHostStateEvents; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - $self->{'timeperiod'} = shift; - $self->{'bind_counter'} = 0; - $self->{'statement'} = undef; - $self->{'name'} = "mod_bi_hoststateevents"; - $self->{'tmp_name'} = "mod_bi_hoststateevents_tmp"; - $self->{'timeColumn'} = "end_time"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub createTempBIEventsTable{ - my ($self) = @_; - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE IF EXISTS `mod_bi_hoststateevents_tmp`" }); - my $createTable = " CREATE TABLE `mod_bi_hoststateevents_tmp` ("; - $createTable .= " `host_id` int(11) NOT NULL,"; - $createTable .= " `modbiliveservice_id` tinyint(4) NOT NULL,"; - $createTable .= " `state` tinyint(4) NOT NULL,"; - $createTable .= " `start_time` int(11) NOT NULL,"; - $createTable .= " `end_time` int(11) DEFAULT NULL,"; - $createTable .= " `duration` int(11) NOT NULL,"; - $createTable .= " `sla_duration` int(11) NOT NULL,"; - $createTable .= " `ack_time` int(11) DEFAULT NULL,"; - $createTable .= " `last_update` tinyint(4) NOT NULL DEFAULT '0',"; - $createTable .= " KEY `modbihost_id` (`host_id`)"; - $createTable .= " ) ENGINE=InnoDB DEFAULT CHARSET=utf8"; - $db->query({ query => $createTable }); -} - -sub prepareTempQuery { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "INSERT INTO `".$self->{'tmp_name'}."`". - " (`host_id`, `modbiliveservice_id`,". - " `state`, `start_time`, `sla_duration`,". - " `end_time`, `ack_time`, `last_update`, `duration`) ". - " VALUES (?,?,?,?,?,?,?,?, TIMESTAMPDIFF(SECOND, FROM_UNIXTIME(?), FROM_UNIXTIME(?)))"; - $self->{'statement'} = $db->prepare($query); - $self->{'dbinstance'} = $db->getInstance; - ($self->{'dbinstance'})->begin_work; -} - -sub prepareQuery { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "INSERT INTO `".$self->{'name'}."`". - " (`modbihost_id`, `modbiliveservice_id`,". - " `state`, `start_time`, `sla_duration`,". - " `end_time`, `ack_time`, `last_update`, `duration`) ". - " VALUES (?,?,?,?,?,?,?,?, TIMESTAMPDIFF(SECOND, FROM_UNIXTIME(?), FROM_UNIXTIME(?)))"; - $self->{'statement'} = $db->prepare($query); - $self->{'dbinstance'} = $db->getInstance; - ($self->{'dbinstance'})->begin_work; -} - -sub bindParam { - my ($self, $row) = @_; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my $size = scalar(@$row); - my $sth = $self->{'statement'}; - for (my $i = 0; $i < $size; $i++) { - $sth->bind_param($i + 1, $row->[$i]); - } - $sth->bind_param($size+1, $row->[3]); - $sth->bind_param($size+2, $row->[5]); - ($self->{'statement'})->execute; - if (defined(($self->{'dbinstance'})->errstr)) { - $logger->writeLog("FATAL", $self->{'name'}." insertion execute error : ".($self->{'dbinstance'})->errstr); - } - if ($self->{'bind_counter'} >= 1000) { - $self->{'bind_counter'} = 0; - ($self->{'dbinstance'})->commit; - if (defined(($self->{'dbinstance'})->errstr)) { - $logger->writeLog("FATAL", $self->{'name'}." insertion commit error : ".($self->{'dbinstance'})->errstr); - } - ($self->{'dbinstance'})->begin_work; - } - $self->{'bind_counter'} += 1; - -} - -sub getDayEvents { - my $self = shift; - my $db = $self->{"centstorage"}; - my $timeperiod = $self->{'timeperiod'}; - my ($start, $end, $liveserviceId, $ranges) = @_; - my %results = (); - - my $query = "SELECT start_time, end_time, state, modbihost_id"; - $query .= " FROM `" . $self->{name} . "`"; - $query .= " WHERE `start_time` < ".$end.""; - $query .= " AND `end_time` > ".$start.""; - $query .= " AND `state` in (0,1,2)"; - $query .= " AND modbiliveservice_id = ".$liveserviceId; - my $sth = $db->query({ query => $query }); - - #For each events, for the current day, calculate statistics for the day - my $rows = []; - while (my $row = ( - shift(@$rows) || - shift(@{$rows = $sth->fetchall_arrayref(undef,10_000) || []}) ) - ) { - my $entryID = $row->[3]; - - my ($started, $ended) = (0, 0); - my $rangeSize = scalar(@$ranges); - my $eventDuration = 0; - for(my $count = 0; $count < $rangeSize; $count++) { - my $currentStart = $row->[0]; - my $currentEnd = $row->[1]; - - my $range = $ranges->[$count]; - my ($rangeStart, $rangeEnd) = ($range->[0], $range->[1]); - if ($currentStart < $rangeEnd && $currentEnd > $rangeStart) { - if ($currentStart < $rangeStart) { - $currentStart = $rangeStart; - }elsif ($count == 0) { - $started = 1; - } - if ($currentEnd > $rangeEnd) { - $currentEnd = $rangeEnd; - }elsif ($count == $rangeSize - 1) { - $ended = 1; - } - $eventDuration += $currentEnd - $currentStart; - } - } - if (!defined($results{$entryID})) { - my @tab = (0, 0, 0, 0, 0, 0, 0); - - #New version - sync with tables in database - # 0: UP, 1: DOWN time, 2: Unreachable time , 3 : DOWN alerts opened - # 4: Down time alerts closed, 5: unreachable alerts started, 6 : unreachable alerts ended - $results{$entryID} = \@tab; - } - - my $stats = $results{$entryID}; - my $state = $row->[2]; - - if ($state == 0) { - $stats->[0] += $eventDuration; - }elsif ($state == 1) { - $stats->[1] += $eventDuration; - $stats->[3] += $started; - $stats->[4] += $ended; - }elsif ($state == 2) { - $stats->[2] += $eventDuration; - $stats->[5] += $started; - $stats->[6] += $ended; - } - - $results{$entryID} = $stats; - } - - return (\%results); -} - -#Deprecated -sub getNbEvents { - my ($self, $start, $end, $groupId, $catId, $liveServiceID) = @_; - my $db = $self->{"centstorage"}; - - my $query = "SELECT count(state) as nbEvents, state"; - $query .= " FROM mod_bi_hosts h, ".$self->{'name'}." e"; - $query .= " WHERE h.hg_id = ".$groupId." AND h.hc_id=".$catId; - $query .= " AND h.id = e.modbihost_id"; - $query .= " AND e.modbiliveservice_id=".$liveServiceID; - $query .= " AND start_time < UNIX_TIMESTAMP('".$end."')"; - $query .= " AND end_time > UNIX_TIMESTAMP('".$start."')"; - $query .= " AND state in (1,2)"; - $query .= " GROUP BY state"; - my $sth = $db->query({ query => $query }); - - my ($downEvents, $unrEvents) = (undef, undef); - while (my $row = $sth->fetchrow_hashref()) { - if ($row->{'state'} == 1) { - $downEvents = $row->{'nbEvents'}; - }else { - $unrEvents = $row->{'nbEvents'}; - } - } - return ($downEvents, $unrEvents); -} - -sub deleteUnfinishedEvents { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "DELETE FROM `mod_bi_hoststateevents`"; - $query .= " WHERE last_update = 1 OR end_time is null"; - $db->query({ query => $query }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIMetric.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIMetric.pm deleted file mode 100644 index 55269e07ba..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIMetric.pm +++ /dev/null @@ -1,199 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::BIMetric; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - - $self->{logger} = shift; - $self->{centstorage} = shift; - if (@_) { - $self->{centreon} = shift; - } - $self->{today_table} = "mod_bi_tmp_today_servicemetrics"; - $self->{tmpTable} = "mod_bi_tmp_servicemetrics"; - $self->{CRC32} = "mod_bi_tmp_servicemetrics_crc32"; - $self->{table} = "mod_bi_servicemetrics"; - - bless $self, $class; - return $self; -} - -sub insert { - my $self = shift; - my $db = $self->{centstorage}; - - $self->insertMetricsIntoTable("mod_bi_servicemetrics"); - $self->createTodayTable("false"); - my $query = "INSERT INTO ".$self->{today_table}. " (id, metric_id, metric_name, sc_id,hg_id,hc_id)"; - $query .= " SELECT id, metric_id, metric_name,sc_id,hg_id,hc_id FROM " . $self->{table} . " "; - $db->query({ query => $query }); -} - -sub update { - my ($self,$useMemory) = @_; - - my $db = $self->{centstorage}; - - $self->createTempTable($useMemory); - $self->insertMetricsIntoTable($self->{tmpTable}); - $self->createCRC32Table(); - $self->insertNewEntries(); - $self->createCRC32Table(); - $self->createTodayTable("false"); - $self->insertTodayEntries(); - $db->query({ query => "DROP TABLE `".$self->{"tmpTable"}."`" }); - $db->query({ query => "DROP TABLE `".$self->{"CRC32"}."`" }); -} - -sub insertMetricsIntoTable { - my $self = shift; - my $db = $self->{"centstorage"}; - my $table = shift; - my $query = "INSERT INTO `".$table."` (`metric_id`, `metric_name`, `metric_unit`, `service_id`, `service_description`,"; - $query .= " `sc_id`, `sc_name`, `host_id`, `host_name`, `hc_id`, `hc_name`, `hg_id`, `hg_name`)"; - $query .= " SELECT `metric_id`, `metric_name`, `unit_name`, s.`service_id`, s.`service_description`, "; - $query .= " s.`sc_id`, s.`sc_name`, s.`host_id`, s.`host_name`, `hc_id`, `hc_name`, `hg_id`, `hg_name`"; - $query .= " FROM `mod_bi_tmp_today_services` s, `metrics` m, `index_data` i"; - $query .= " WHERE i.id = m.index_id and i.host_id=s.host_id and i.service_id=s.service_id"; - $query .= " group by s.hg_id, s.hc_id, s.sc_id, m.index_id, m.metric_id"; - my $sth = $db->query({ query => $query }); - return $sth; -} - -sub createTempTable { - my ($self, $useMemory) = @_; - - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE IF EXISTS `".$self->{"tmpTable"}."`" }); - my $query = "CREATE TABLE `".$self->{"tmpTable"}."` ("; - $query .= "`metric_id` int(11) NOT NULL,`metric_name` varchar(255) NOT NULL,`metric_unit` char(32) DEFAULT NULL,"; - $query .= "`service_id` int(11) NOT NULL,`service_description` varchar(255) DEFAULT NULL,"; - $query .= "`sc_id` int(11) DEFAULT NULL,`sc_name` varchar(255) DEFAULT NULL,"; - $query .= "`host_id` int(11) DEFAULT NULL,`host_name` varchar(255) DEFAULT NULL,"; - $query .= "`hc_id` int(11) DEFAULT NULL,`hc_name` varchar(255) DEFAULT NULL,"; - $query .= "`hg_id` int(11) DEFAULT NULL,`hg_name` varchar(255) DEFAULT NULL"; - if (defined($useMemory) && $useMemory eq "true") { - $query .= ") ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - }else { - $query .= ") ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $query }); -} - -sub createCRC32Table { - my ($self) = @_; - my $db = $self->{"centstorage"}; - - $db->query({ query => "DROP TABLE IF EXISTS `".$self->{"CRC32"}."`" }); - my $query = "CREATE TABLE `".$self->{"CRC32"}."` CHARSET=utf8 COLLATE=utf8_general_ci"; - $query .= " SELECT `id`, CRC32(CONCAT_WS('-', COALESCE(metric_id, '?'),"; - $query .= " COALESCE(service_id, '?'),COALESCE(service_description, '?'),"; - $query .= " COALESCE(host_id, '?'),COALESCE(host_name, '?'), COALESCE(sc_id, '?'),COALESCE(sc_name, '?'),"; - $query .= " COALESCE(hc_id, '?'),COALESCE(hc_name, '?'), COALESCE(hg_id, '?'),COALESCE(hg_name, '?'))) as mycrc"; - $query .= " FROM ".$self->{"table"}; - $db->query({ query => $query }); - $query = "ALTER TABLE `".$self->{"CRC32"}."` ADD INDEX (`mycrc`)"; - $db->query({ query => $query }); -} - -sub insertNewEntries { - my ($self) = @_; - my $db = $self->{"centstorage"}; - my $fields = "metric_id, metric_name, metric_unit, service_id, service_description, host_name, host_id, sc_id, sc_name, hc_id, hc_name, hg_id, hg_name"; - my $tmpTableFields = "tmpTable.metric_id, tmpTable.metric_name,tmpTable.metric_unit,"; - $tmpTableFields .= " tmpTable.service_id, tmpTable.service_description, tmpTable.host_name, tmpTable.host_id, tmpTable.sc_id,"; - $tmpTableFields .= "tmpTable.sc_name, tmpTable.hc_id, tmpTable.hc_name, tmpTable.hg_id, tmpTable.hg_name"; - my $query = " INSERT INTO `".$self->{"table"}."` (".$fields.") "; - $query .= " SELECT ".$tmpTableFields." FROM ".$self->{"tmpTable"}." as tmpTable"; - $query .= " LEFT JOIN (".$self->{"CRC32"}. " INNER JOIN ".$self->{"table"}." as finalTable using (id))"; - $query .= " ON CRC32(CONCAT_WS('-', COALESCE(tmpTable.metric_id, '?'), COALESCE(tmpTable.service_id, '?'),COALESCE(tmpTable.service_description, '?'),"; - $query .= " COALESCE(tmpTable.host_id, '?'),COALESCE(tmpTable.host_name, '?'), COALESCE(tmpTable.sc_id, '?'),COALESCE(tmpTable.sc_name, '?'),"; - $query .= " COALESCE(tmpTable.hc_id, '?'),COALESCE(tmpTable.hc_name, '?'), COALESCE(tmpTable.hg_id, '?'),COALESCE(tmpTable.hg_name, '?'))) = mycrc"; - $query .= " AND tmpTable.metric_id=finalTable.metric_id"; - $query .= " AND tmpTable.service_id=finalTable.service_id AND tmpTable.service_description=finalTable.service_description"; - $query .= " AND tmpTable.host_id=finalTable.host_id AND tmpTable.host_name=finalTable.host_name"; - $query .= " AND tmpTable.sc_id=finalTable.sc_id AND tmpTable.sc_name=finalTable.sc_name"; - $query .= " AND tmpTable.hc_id=finalTable.hc_id AND tmpTable.hc_name=finalTable.hc_name"; - $query .= " AND tmpTable.hg_id=finalTable.hg_id AND tmpTable.hg_name=finalTable.hg_name"; - $query .= " WHERE finalTable.id is null"; - $db->query({ query => $query }); -} - -sub createTodayTable { - my ($self,$useMemory) = @_; - my $db = $self->{"centstorage"}; - - $db->query({ query => "DROP TABLE IF EXISTS `".$self->{"today_table"}."`" }); - my $query = "CREATE TABLE `" . $self->{"today_table"} . "` ("; - $query .= "`id` INT NOT NULL,"; - $query .= "`metric_id` int(11) NOT NULL,"; - $query .= "`metric_name` varchar(255) NOT NULL,"; - $query .= "`sc_id` int(11) NOT NULL,"; - $query .= "`hg_id` int(11) NOT NULL,"; - $query .= "`hc_id` int(11) NOT NULL,"; - $query .= " KEY `metric_id` (`metric_id`),"; - $query .= " KEY `schghc_id` (`sc_id`,`hg_id`,`hc_id`)"; - if (defined($useMemory) && $useMemory eq "true") { - $query .= ") ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - }else { - $query .= ") ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $query }); -} - -sub insertTodayEntries { - my ($self) = @_; - my $db = $self->{"centstorage"}; - my $query = "INSERT INTO ".$self->{"today_table"}. " (id, metric_id, metric_name, sc_id,hg_id,hc_id)"; - $query .= " SELECT finalTable.id, finalTable.metric_id, finalTable.metric_name, finalTable.sc_id, finalTable.hg_id, finalTable.hc_id FROM ".$self->{"tmpTable"}." t"; - $query .= " LEFT JOIN (".$self->{"CRC32"}." INNER JOIN ".$self->{"table"}." finalTable USING (id))"; - $query .= " ON CRC32(CONCAT_WS('-', COALESCE(t.metric_id, '?'), COALESCE(t.service_id, '?'),COALESCE(t.service_description, '?'),"; - $query .= " COALESCE(t.host_id, '?'),COALESCE(t.host_name, '?'), COALESCE(t.sc_id, '?'),COALESCE(t.sc_name, '?'),"; - $query .= " COALESCE(t.hc_id, '?'),COALESCE(t.hc_name, '?'), COALESCE(t.hg_id, '?'),COALESCE(t.hg_name, '?'))) = mycrc"; - $query .= " AND finalTable.metric_id=t.metric_id"; - $query .= " AND finalTable.service_id=t.service_id AND finalTable.service_description=t.service_description "; - $query .= " AND finalTable.host_id=t.host_id AND finalTable.host_name=t.host_name "; - $query .= " AND finalTable.sc_id=t.sc_id AND finalTable.sc_name=t.sc_name "; - $query .= " AND finalTable.hc_id=t.hc_id AND finalTable.hc_name=t.hc_name "; - $query .= " AND finalTable.hg_id=t.hg_id AND finalTable.hg_name=t.hg_name "; - $db->query({ query => $query }); -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "TRUNCATE TABLE `".$self->{"table"}."`"; - $db->query({ query => $query }); - $db->query({ query => "ALTER TABLE `".$self->{"table"}."` AUTO_INCREMENT=1" }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIService.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIService.pm deleted file mode 100644 index 981f5663bd..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIService.pm +++ /dev/null @@ -1,221 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::BIService; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{"today_table"} = "mod_bi_tmp_today_services"; - $self->{"tmpTable"} = "mod_bi_tmp_services"; - $self->{"CRC32"} = "mod_bi_tmp_services_crc32"; - $self->{"table"} = "mod_bi_services"; - - bless $self, $class; - return $self; -} - -sub insert { - my $self = shift; - my $data = shift; - my $db = $self->{"centstorage"}; - $self->insertIntoTable($self->{"table"}, $data); - $self->createTodayTable("false"); - my $fields = "id, service_id, service_description, host_name, host_id, sc_id, sc_name, hc_id, hc_name, hg_id, hg_name"; - my $query = "INSERT INTO ".$self->{"today_table"}. "(".$fields.")"; - $query .= " SELECT ".$fields." FROM ".$self->{"table"}; - $db->query({ query => $query }); -} - -sub update { - my ($self, $data, $useMemory) = @_; - my $db = $self->{"centstorage"}; - - $self->createTempTable($useMemory); - $self->insertIntoTable($self->{"tmpTable"}, $data); - $self->createCRC32Table(); - $self->insertNewEntries(); - $self->createCRC32Table(); - $self->createTodayTable("false"); - $self->insertTodayEntries(); - $db->query({ query => "DROP TABLE `".$self->{"tmpTable"}."`" }); - $db->query({ query => "DROP TABLE `".$self->{"CRC32"}."`" }); -} - -sub insertIntoTable { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my $table = shift; - my $data = shift; - my $name = shift; - my $id = shift; - my $query = "INSERT INTO `".$table."`". - " (`service_id`, `service_description`, `sc_id`, `sc_name`,". - " `host_id`, `host_name`,`hg_id`, `hg_name`, `hc_id`, `hc_name`)". - " VALUES (?,?,?,?,?,?,?,?,?,?)"; - my $sth = $db->prepare($query); - my $inst = $db->getInstance; - $inst->begin_work; - my $counter = 0; - - foreach (@$data) { - my ($service_id, $service_description, $sc_id, $sc_name, $host_id, $host_name, $hg_id, $hg_name, $hc_id, $hc_name) = split(";", $_); - $sth->bind_param(1, $service_id); - $sth->bind_param(2, $service_description); - $sth->bind_param(3, $sc_id); - $sth->bind_param(4, $sc_name); - $sth->bind_param(5, $host_id); - $sth->bind_param(6, $host_name); - $sth->bind_param(7, $hg_id); - $sth->bind_param(8, $hg_name); - $sth->bind_param(9, $hc_id); - $sth->bind_param(10, $hc_name); - $sth->execute; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", $table." insertion execute error : ".$inst->errstr); - } - if ($counter >= 1000) { - $counter = 0; - $inst->commit; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", $table." insertion commit error : ".$inst->errstr); - } - $inst->begin_work; - } - $counter++; - } - $inst->commit; -} -sub createTempTable { - my ($self, $useMemory) = @_; - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE IF EXISTS `".$self->{"tmpTable"}."`" }); - my $query = "CREATE TABLE `".$self->{"tmpTable"}."` ("; - $query .= "`service_id` int(11) NOT NULL,`service_description` varchar(255) NOT NULL,"; - $query .= "`sc_id` int(11) NOT NULL,`sc_name` varchar(255) NOT NULL,"; - $query .= "`host_id` int(11) DEFAULT NULL,`host_name` varchar(255) NOT NULL,"; - $query .= "`hc_id` int(11) DEFAULT NULL,`hc_name` varchar(255) NOT NULL,"; - $query .= "`hg_id` int(11) DEFAULT NULL,`hg_name` varchar(255) NOT NULL"; - if (defined($useMemory) && $useMemory eq "true") { - $query .= ") ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - }else { - $query .= ") ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $query }); -} - -sub createCRC32Table { - my ($self) = @_; - my $db = $self->{"centstorage"}; - - $db->query({ query => "DROP TABLE IF EXISTS `".$self->{"CRC32"}."`" }); - my $query = "CREATE TABLE `".$self->{"CRC32"}."` CHARSET=utf8 COLLATE=utf8_general_ci"; - $query .= " SELECT `id`, CRC32(CONCAT_WS('-', COALESCE(service_id, '?'),COALESCE(service_description, '?'),"; - $query .= " COALESCE(host_id, '?'),COALESCE(host_name, '?'), COALESCE(sc_id, '?'),COALESCE(sc_name, '?'),"; - $query .= " COALESCE(hc_id, '?'),COALESCE(hc_name, '?'), COALESCE(hg_id, '?'),COALESCE(hg_name, '?'))) as mycrc"; - $query .= " FROM ".$self->{"table"}; - $db->query({ query => $query }); - $query = "ALTER TABLE `".$self->{"CRC32"}."` ADD INDEX (`mycrc`)"; - $db->query({ query => $query }); -} - -sub insertNewEntries { - my ($self) = @_; - my $db = $self->{"centstorage"}; - my $fields = "service_id, service_description, host_name, host_id, sc_id, sc_name, hc_id, hc_name, hg_id, hg_name"; - my $tmpTableFields = "tmpTable.service_id, tmpTable.service_description, tmpTable.host_name, tmpTable.host_id, tmpTable.sc_id,"; - $tmpTableFields .= "tmpTable.sc_name, tmpTable.hc_id, tmpTable.hc_name, tmpTable.hg_id, tmpTable.hg_name"; - my $query = " INSERT INTO `".$self->{"table"}."` (".$fields.") "; - $query .= " SELECT ".$tmpTableFields." FROM ".$self->{"tmpTable"}." as tmpTable"; - $query .= " LEFT JOIN (".$self->{"CRC32"}. " INNER JOIN ".$self->{"table"}." as finalTable using (id))"; - $query .= " ON CRC32(CONCAT_WS('-', COALESCE(tmpTable.service_id, '?'),COALESCE(tmpTable.service_description, '?'),"; - $query .= " COALESCE(tmpTable.host_id, '?'),COALESCE(tmpTable.host_name, '?'), COALESCE(tmpTable.sc_id, '?'),COALESCE(tmpTable.sc_name, '?'),"; - $query .= " COALESCE(tmpTable.hc_id, '?'),COALESCE(tmpTable.hc_name, '?'), COALESCE(tmpTable.hg_id, '?'),COALESCE(tmpTable.hg_name, '?'))) = mycrc"; - $query .= " AND tmpTable.service_id=finalTable.service_id AND tmpTable.service_description=finalTable.service_description"; - $query .= " AND tmpTable.host_id=finalTable.host_id AND tmpTable.host_name=finalTable.host_name"; - $query .= " AND tmpTable.sc_id=finalTable.sc_id AND tmpTable.sc_name=finalTable.sc_name"; - $query .= " AND tmpTable.hc_id=finalTable.hc_id AND tmpTable.hc_name=finalTable.hc_name"; - $query .= " AND tmpTable.hg_id=finalTable.hg_id AND tmpTable.hg_name=finalTable.hg_name"; - $query .= " WHERE finalTable.id is null"; - $db->query({ query => $query }); -} - -sub createTodayTable { - my ($self,$useMemory) = @_; - my $db = $self->{"centstorage"}; - - $db->query({ query => "DROP TABLE IF EXISTS `".$self->{"today_table"}."`" }); - my $query = "CREATE TABLE `".$self->{"today_table"}."` ("; - $query .= "`id` INT NOT NULL,"; - $query .= "`service_id` int(11) NOT NULL,`service_description` varchar(255) NOT NULL,"; - $query .= "`sc_id` int(11) NOT NULL,`sc_name` varchar(255) NOT NULL,"; - $query .= "`host_id` int(11) DEFAULT NULL,`host_name` varchar(255) NOT NULL,"; - $query .= "`hc_id` int(11) DEFAULT NULL,`hc_name` varchar(255) NOT NULL,"; - $query .= "`hg_id` int(11) DEFAULT NULL,`hg_name` varchar(255) NOT NULL,"; - $query .= " KEY `host_service` (`host_id`, `service_id`)"; - if (defined($useMemory) && $useMemory eq "true") { - $query .= ") ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - }else { - $query .= ") ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $query }); -} - -sub insertTodayEntries { - my ($self) = @_; - my $db = $self->{"centstorage"}; - my $query = "INSERT INTO ".$self->{"today_table"}. " (id, service_id, service_description, host_name, host_id, sc_id, sc_name, hc_id, hc_name, hg_id, hg_name)"; - $query .= " SELECT s.id, t.service_id, t.service_description, t.host_name, t.host_id, t.sc_id, t.sc_name, t.hc_id, t.hc_name, t.hg_id, t.hg_name FROM ".$self->{"tmpTable"}." t"; - $query .= " LEFT JOIN (".$self->{"CRC32"}." INNER JOIN ".$self->{"table"}." s USING (id))"; - $query .= " ON CRC32(CONCAT_WS('-', COALESCE(t.service_id, '?'),COALESCE(t.service_description, '?'),"; - $query .= " COALESCE(t.host_id, '?'),COALESCE(t.host_name, '?'), COALESCE(t.sc_id, '?'),COALESCE(t.sc_name, '?'),"; - $query .= " COALESCE(t.hc_id, '?'),COALESCE(t.hc_name, '?'), COALESCE(t.hg_id, '?'),COALESCE(t.hg_name, '?'))) = mycrc"; - $query .= " AND s.service_id=t.service_id AND s.service_description=t.service_description "; - $query .= " AND s.host_id=t.host_id AND s.host_name=t.host_name "; - $query .= " AND s.sc_id=t.sc_id AND s.sc_name=t.sc_name "; - $query .= " AND s.hc_id=t.hc_id AND s.hc_name=t.hc_name "; - $query .= " AND s.hg_id=t.hg_id AND s.hg_name=t.hg_name "; - $db->query({ query => $query }); -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "TRUNCATE TABLE `".$self->{"table"}."`"; - $db->query({ query => $query }); - $db->query({ query => "ALTER TABLE `".$self->{"table"}."` AUTO_INCREMENT=1" }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIServiceCategory.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIServiceCategory.pm deleted file mode 100644 index 74e5d7f2e3..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIServiceCategory.pm +++ /dev/null @@ -1,128 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::BIServiceCategory; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - bless $self, $class; - return $self; -} - - -sub getAllEntries { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "SELECT `sc_id`, `sc_name`"; - $query .= " FROM `mod_bi_servicecategories`"; - my $sth = $db->query({ query => $query }); - my @entries = (); - while (my $row = $sth->fetchrow_hashref()) { - push @entries, $row->{"sc_id"}.";".$row->{"sc_name"}; - } - return (\@entries); -} - -sub getEntryIds { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "SELECT `id`, `sc_id`, `sc_name`"; - $query .= " FROM `mod_bi_servicecategories`"; - my $sth = $db->query({ query => $query }); - my %entries = (); - while (my $row = $sth->fetchrow_hashref()) { - $entries{$row->{"sc_id"}.";".$row->{"sc_name"}} = $row->{"id"}; - } - return (\%entries); -} - -sub entryExists { - my $self = shift; - my ($value, $entries) = (shift, shift); - foreach(@$entries) { - if ($value eq $_) { - return 1; - } - } - return 0; -} -sub insert { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my $data = shift; - my $query = "INSERT INTO `mod_bi_servicecategories`". - " (`sc_id`, `sc_name`)". - " VALUES (?,?)"; - my $sth = $db->prepare($query); - my $inst = $db->getInstance; - $inst->begin_work; - my $counter = 0; - - my $existingEntries = $self->getAllEntries; - foreach (@$data) { - if (!$self->entryExists($_, $existingEntries)) { - my ($sc_id, $sc_name) = split(";", $_); - $sth->bind_param(1, $sc_id); - $sth->bind_param(2, $sc_name); - $sth->execute; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", "servicecategories insertion execute error : ".$inst->errstr); - } - if ($counter >= 1000) { - $counter = 0; - $inst->commit; - if (defined($inst->errstr)) { - $logger->writeLog("FATAL", "servicecategories insertion commit error : ".$inst->errstr); - } - $inst->begin_work; - } - $counter++; - } - } - $inst->commit; -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "TRUNCATE TABLE `mod_bi_servicecategories`"; - $db->query({ query => $query }); - $db->query({ query => "ALTER TABLE `mod_bi_servicecategories` AUTO_INCREMENT=1" }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIServiceStateEvents.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIServiceStateEvents.pm deleted file mode 100644 index 567634b680..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/BIServiceStateEvents.pm +++ /dev/null @@ -1,251 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::BIServiceStateEvents; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - $self->{'timeperiod'} = shift; - $self->{'bind_counter'} = 0; - $self->{'name'} = "mod_bi_servicestateevents"; - $self->{'tmp_name'} = "mod_bi_servicestateevents_tmp"; - $self->{'timeColumn'} = "end_time"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub prepareQuery { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "INSERT INTO `".$self->{'name'}."`". - " (`modbiservice_id`, `modbiliveservice_id`,". - " `state`, `start_time`, `sla_duration`,". - " `end_time`, `ack_time`, `last_update`, `duration`) ". - " VALUES (?,?,?,?,?,?,?,?, TIMESTAMPDIFF(SECOND, FROM_UNIXTIME(?), FROM_UNIXTIME(?)))"; - $self->{'statement'} = $db->prepare($query); - $self->{'dbinstance'} = $db->getInstance; - ($self->{'dbinstance'})->begin_work; -} - -sub createTempBIEventsTable { - my ($self) = @_; - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE IF EXISTS `mod_bi_servicestateevents_tmp`" }); - my $createTable = " CREATE TABLE `mod_bi_servicestateevents_tmp` ("; - $createTable .= " `host_id` int(11) NOT NULL,"; - $createTable .= " `service_id` int(11) NOT NULL,"; - $createTable .= " `modbiliveservice_id` tinyint(4) NOT NULL,"; - $createTable .= " `state` tinyint(4) NOT NULL,"; - $createTable .= " `start_time` int(11) NOT NULL,"; - $createTable .= " `end_time` int(11) DEFAULT NULL,"; - $createTable .= " `duration` int(11) NOT NULL,"; - $createTable .= " `sla_duration` int(11) NOT NULL,"; - $createTable .= " `ack_time` int(11) DEFAULT NULL,"; - $createTable .= " `last_update` tinyint(4) DEFAULT '0',"; - $createTable .= " KEY `modbiservice_id` (`host_id`,`service_id`)"; - $createTable .= " ) ENGINE=InnoDB DEFAULT CHARSET=utf8"; - $db->query({ query => $createTable }); -} - -sub prepareTempQuery { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "INSERT INTO `".$self->{'tmp_name'}."`". - " (`host_id`,`service_id`,`modbiliveservice_id`,". - " `state`, `start_time`, `sla_duration`,". - " `end_time`, `ack_time`, `last_update`, `duration`) ". - " VALUES (?,?,?,?,?,?,?,?,?, TIMESTAMPDIFF(SECOND, FROM_UNIXTIME(?), FROM_UNIXTIME(?)))"; - $self->{'statement'} = $db->prepare($query); - $self->{'dbinstance'} = $db->getInstance; - ($self->{'dbinstance'})->begin_work; -} - -sub bindParam { - my ($self, $row) = @_; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my $size = scalar(@$row); - my $sth = $self->{'statement'}; - for (my $i = 0; $i < $size; $i++) { - $sth->bind_param($i + 1, $row->[$i]); - } - $sth->bind_param($size + 1, $row->[4]); - $sth->bind_param($size + 2, $row->[6]); - - ($self->{'statement'})->execute; - if (defined(($self->{'dbinstance'})->errstr)) { - $logger->writeLog("FATAL", $self->{'name'}." insertion execute error : ".($self->{'dbinstance'})->errstr); - } - if ($self->{'bind_counter'} >= 1000) { - $self->{'bind_counter'} = 0; - ($self->{'dbinstance'})->commit; - if (defined(($self->{'dbinstance'})->errstr)) { - $logger->writeLog("FATAL", $self->{'name'}." insertion commit error : ".($self->{'dbinstance'})->errstr); - } - ($self->{'dbinstance'})->begin_work; - } - $self->{'bind_counter'} += 1; - -} - -sub getDayEvents { - my $self = shift; - my $db = $self->{"centstorage"}; - my $timeperiod = $self->{'timeperiod'}; - my ($start, $end, $liveserviceId, $ranges) = @_; - my $liveServiceList = shift; - my %results = (); - - my $query = "SELECT start_time, end_time, state, modbiservice_id"; - $query .= " FROM `" . $self->{'name'} . "`"; - $query .= " WHERE `start_time` < " . $end; - $query .= " AND `end_time` > " . $start; - $query .= " AND `state` IN (0,1,2,3)"; - $query .= " AND modbiliveservice_id=" . $liveserviceId; - my $sth = $db->query({ query => $query }); - - if (!scalar(@$ranges)) { - return \%results; - } - - my $rows = []; - while (my $row = ( - shift(@$rows) || - shift(@{$rows = $sth->fetchall_arrayref(undef,10_000) || []}) ) - ) { - my $entryID = $row->[3]; - - my ($started, $ended) = (0,0); - my $rangeSize = scalar(@$ranges); - my $eventDuration = 0; - for (my $count = 0; $count < $rangeSize; $count++) { - my $currentStart = $row->[0]; - my $currentEnd = $row->[1]; - - my $range = $ranges->[$count]; - my ($rangeStart, $rangeEnd) = ($range->[0], $range->[1]); - if ($currentStart < $rangeEnd && $currentEnd > $rangeStart) { - if ($currentStart < $rangeStart) { - $currentStart = $rangeStart; - } elsif ($count == 0) { - $started = 1; - } - if ($currentEnd > $rangeEnd) { - $currentEnd = $rangeEnd; - } elsif ($count == $rangeSize - 1) { - $ended = 1; - } - $eventDuration += $currentEnd - $currentStart; - } - } - if (!defined($results{$entryID})) { - my @tab = (0, 0, 0, 0, 0, 0, 0, 0, 0); - - #New table - sync with the real table in centreon_storage database - # 0: OK time , 1: CRITICAL time, 2 : DEGRADED time 3 : alert_unavailable_opened - # 4: alert unavailable_closed 5 : alert_degraded_opened 6 : alertes_degraded_closed - # 7 : alert_unknown_opened 8 : alert_unknown_closed - $results{$entryID} = \@tab; - } - my $stats = $results{$entryID}; - my $state = $row->[2]; - if ($state == 0) { - $stats->[0] += $eventDuration; - } elsif ($state == 1) { - $stats->[2] += $eventDuration; - $stats->[5] += $started; - $stats->[6] += $ended; - } elsif ($state == 2) { - $stats->[1] += $eventDuration; - $stats->[3] += $started; - $stats->[4] += $ended; - } else { - $stats->[7] += $started; - $stats->[8] += $ended; - } - $results{$entryID} = $stats; - } - - return (\%results); -} - -#Deprecated -sub getNbEvents { - my ($self, $start, $end, $groupId, $hcatId, $scatId, $liveServiceID) = @_; - my $db = $self->{"centstorage"}; - - my $query = "SELECT count(state) as nbEvents, state"; - $query .= " FROM mod_bi_services s, ".$self->{'name'}." e"; - $query .= " WHERE s.hg_id = ".$groupId." AND s.hc_id=".$hcatId." AND s.sc_id=".$scatId; - $query .= " AND s.id = e.modbiservice_id"; - $query .= " AND start_time < UNIX_TIMESTAMP('".$end."')"; - $query .= " AND end_time > UNIX_TIMESTAMP('".$start."')"; - $query .= " AND e.modbiliveservice_id=".$liveServiceID; - $query .= " AND e.state in (1,2,3)"; - $query .= " GROUP BY e.state"; - my $sth = $db->query({ query => $query }); - - my ($warnEvents, $criticalEvents, $otherEvents) = (undef, undef, undef); - while (my $row = $sth->fetchrow_hashref()) { - if ($row->{'state'} == 1) { - $warnEvents = $row->{'nbEvents'}; - }elsif ($row->{'state'} == 2) { - $criticalEvents = $row->{'nbEvents'}; - }else { - $otherEvents = $row->{'nbEvents'}; - } - } - return ($warnEvents, $criticalEvents, $otherEvents); -} - -sub deleteUnfinishedEvents { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "DELETE FROM `".$self->{'name'}."`"; - $query .= " WHERE last_update = 1 OR end_time is null"; - $db->query({ query => $query }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/DBConfigParser.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/DBConfigParser.pm deleted file mode 100644 index 6c5571b480..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/DBConfigParser.pm +++ /dev/null @@ -1,85 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; -use POSIX; -use XML::LibXML; -use Data::Dumper; - -package gorgone::modules::centreon::mbi::libs::bi::DBConfigParser; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database - -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - bless $self, $class; - return $self; -} - -sub parseFile { - my $self = shift; - my $logger = $self->{"logger"}; - my $file = shift; - - my %connProfiles = (); - if (! -r $file) { - $logger->writeLog("ERROR", "Cannot read file ".$file); - } - my $parser = XML::LibXML->new(); - my $root = $parser->parse_file($file); - foreach my $profile ($root->findnodes('/DataTools.ServerProfiles/profile')) { - my $base = $profile->findnodes('@name'); - - foreach my $property ($profile->findnodes('./baseproperties/property')) { - my $name = $property->findnodes('@name')->to_literal; - my $value = $property->findnodes('@value')->to_literal; - if ($name eq 'odaURL') { - if ($value =~ /jdbc\:[a-z]+\:\/\/([^:]*)(\:\d+)?\/(.*)/) { - $connProfiles{$base."_host"} = $1; - if(defined($2) && $2 ne ''){ - $connProfiles{$base."_port"} = $2; - $connProfiles{$base."_port"} =~ s/\://; - }else{ - $connProfiles{$base."_port"} = '3306'; - } - $connProfiles{$base."_db"} = $3; - $connProfiles{$base."_db"} =~ s/\?autoReconnect\=true//; - } - } - if ($name eq 'odaUser') { - $connProfiles{$base."_user"} = sprintf('%s',$value); - } - if ($name eq 'odaPassword') { - $connProfiles{$base."_pass"} = sprintf('%s', $value); - } - } - } - - return (\%connProfiles); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/DataQuality.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/DataQuality.pm deleted file mode 100644 index f9f87a3672..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/DataQuality.pm +++ /dev/null @@ -1,99 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::DataQuality; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database - -sub new { - my $class = shift; - my $self = {}; - - $self->{logger} = shift; - $self->{centreon} = shift; - bless $self, $class; - return $self; -} - -sub searchAndDeleteDuplicateEntries { - my $self = shift; - - $self->{logger}->writeLog("INFO", "Searching for duplicate host/service entries"); - my $relationIDS = $self->getDuplicateRelations(); - if (@$relationIDS) { - $self->deleteDuplicateEntries($relationIDS); - } -} - -# return table of IDs to delete -sub getDuplicateRelations { - my $self = shift; - - my @relationIDS; - #Get duplicated relations and exclude BAM or Metaservices data - my $duplicateEntriesQuery = "SELECT host_host_id, service_service_id, count(*) as nbRelations ". - "FROM host_service_relation t1, host t2 WHERE t1.host_host_id = t2.host_id ". - "AND t2.host_name not like '_Module%' group by host_host_id, service_service_id HAVING COUNT(*) > 1"; - - my $sth = $self->{centreon}->query({ query => $duplicateEntriesQuery }); - while (my $row = $sth->fetchrow_hashref()) { - if (defined($row->{host_host_id})) { - $self->{logger}->writeLog( - "WARNING", - "Found the following duplicate data (host-service) : " . $row->{host_host_id}." - ".$row->{service_service_id}." - Cleaning data" - ); - #Get all relation IDs related to duplicated data - my $relationIdQuery = "SELECT hsr_id from host_service_relation ". - "WHERE host_host_id = ".$row->{host_host_id}." AND service_service_id = ".$row->{service_service_id}; - my $sth2 = $self->{centreon}->query({ query => $relationIdQuery }); - while (my $hsr = $sth2->fetchrow_hashref()) { - if (defined($hsr->{hsr_id})) { - push(@relationIDS,$hsr->{hsr_id}); - } - } - $self->deleteDuplicateEntries(\@relationIDS); - @relationIDS = (); - } - } - return (\@relationIDS); -} - -# Delete N-1 duplicate entry -sub deleteDuplicateEntries { - my $self = shift; - - my @relationIDS = @{$_[0]}; - #WARNING : very important so at least 1 relation is kept - pop @relationIDS; - foreach (@relationIDS) { - my $idToDelete = $_; - my $deleteQuery = "DELETE FROM host_service_relation WHERE hsr_id = ".$idToDelete; - $self->{centreon}->query({ query => $deleteQuery }) - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Dumper.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Dumper.pm deleted file mode 100644 index 198c52cc99..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Dumper.pm +++ /dev/null @@ -1,132 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::Dumper; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{'tempFolder'} = "/tmp/"; - bless $self, $class; - return $self; -} - -sub setStorageDir { - my $self = shift; - my $logger = $self->{'logger'}; - my $tempFolder = shift; - - if (!defined($tempFolder)) { - $logger->writeLog("ERROR", "Temporary storage folder is not defined"); - } - if (! -d $tempFolder && ! -w $tempFolder) { - $logger->writeLog("ERROR", "Cannot write into directory ".$tempFolder); - } - if ($tempFolder !~ /\/$/) { - $tempFolder .= "/"; - } - $self->{'tempFolder'} = $tempFolder; -} - -# Dump data in a MySQL table. (db connection,table name, [not mandatory] start column, end column,start date,end date,exclude end time?) -# and return the file name created -# Ex $file = $dumper->dumpData($hostCentreon, 'toto', 'data_start', 'date_end', '2015-01-02', '2015-02-01', 0); -sub dumpData { - my $self = shift; - my $db = $self->{"centstorage"}; - my ($hostCentreon, $tableName) = (shift, shift); - my ($day,$month,$year,$hour,$min) = (localtime(time))[3,4,5,2,1]; - my $fileName = $self->{'tempFolder'}.$tableName; - my $query = "SELECT * FROM ".$tableName." "; - my $logger = $self->{'logger'}; - if (@_) { - my ($startColumn, $endColumn, $startTime, $endTime, $excludeEndTime) = @_; - $query .= " WHERE ".$startColumn." >= UNIX_TIMESTAMP('".$startTime."') "; - if ($excludeEndTime == 0) { - $query .= "AND ".$endColumn." <= UNIX_TIMESTAMP('".$endTime."')"; - }else { - $query .= "AND ".$endColumn." < UNIX_TIMESTAMP('".$endTime."')"; - } - } - my @loadCmdArgs = ('mysql', "-q", "-u", $hostCentreon->{'Censtorage_user'}, "-p".$hostCentreon->{'Censtorage_pass'}, - "-h", $hostCentreon->{'Censtorage_host'}, $hostCentreon->{'Censtorage_db'}, - "-e", $query.">".$fileName); - system("mysql -q -u".$hostCentreon->{'Censtorage_user'}." -p".$hostCentreon->{'Censtorage_pass'}." -P".$hostCentreon->{'Censtorage_port'}." -h".$hostCentreon->{'Censtorage_host'}. - " ".$hostCentreon->{'Censtorage_db'}." -e \"".$query."\" > ".$fileName); - $logger->writeLog("DEBUG","mysql -q -u".$hostCentreon->{'Censtorage_user'}." -p".$hostCentreon->{'Censtorage_pass'}." -P".$hostCentreon->{'Censtorage_port'}." -h".$hostCentreon->{'Censtorage_host'}. - " ".$hostCentreon->{'Censtorage_db'}." -e \"".$query."\" > ".$fileName); - return ($fileName); -} - -sub dumpRequest{ - my $self = shift; - my $db = $self->{"centstorage"}; - my ($hostCentreon, $requestName,$query) = (shift, shift,shift); - my $fileName = $self->{'tempFolder'}.$requestName; - my $logger = $self->{'logger'}; - system("mysql -q -u".$hostCentreon->{'Censtorage_user'}." -p".$hostCentreon->{'Censtorage_pass'}." -h".$hostCentreon->{'Censtorage_host'}. " -P".$hostCentreon->{'Censtorage_port'}. - " ".$hostCentreon->{'Censtorage_db'}." -e \"".$query."\" > ".$fileName); - return ($fileName); -} - -sub dumpTableStructure { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{'logger'}; - my ($tableName) = (shift); - - my $sql = ""; - my $sth = $db->query({ query => "SHOW CREATE TABLE ".$tableName }); - if (my $row = $sth->fetchrow_hashref()) { - $sql = $row->{'Create Table'}; - $sql =~ s/(CONSTRAINT.*\n)//g; - $sql =~ s/(\,\n\s+\))/\)/g; - }else { - $logger->writeLog("WARNING", "Cannot get structure for table : ".$tableName); - return (undef); - } - $sth->finish; - return ($sql); -} - -sub insertData { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my ($tableName, $inFile) = (shift, shift); - my $query = "LOAD DATA INFILE '".$inFile."' INTO TABLE `".$tableName."`"; - my $sth = $db->query({ query => $query }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HGMonthAvailability.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HGMonthAvailability.pm deleted file mode 100644 index e0f3d1a82d..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HGMonthAvailability.pm +++ /dev/null @@ -1,92 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::HGMonthAvailability; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{'name'} = "mod_bi_hgmonthavailability"; - $self->{'timeColumn'} = "time_id"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - - -sub insertStats { - my $self = shift; - my ($time_id, $data) = @_; - my $insertParam = 1000; - - my $query_start = "INSERT INTO `".$self->{'name'}."`". - " (`time_id`, `modbihg_id`, `modbihc_id`, `liveservice_id`, `available`, `unavailable_time`,". - " `alert_unavailable_opened`, `alert_unavailable_closed`, ". - " `alert_unreachable_opened`, `alert_unreachable_closed`,". - " `alert_unavailable_total`, `alert_unreachable_total`,". - " `mtrs`, `mtbf`, `mtbsi`)". - " VALUES "; - my $counter = 0; - my $query = $query_start; - my $append = ''; - - foreach my $entry (@$data) { - my $size = scalar(@$entry); - $query .= $append . "($time_id"; - for (my $i = 0; $i < $size; $i++) { - $query .= ', ' . (defined($entry->[$i]) ? $entry->[$i] : 'NULL'); - } - $query .= ')'; - - $append = ','; - $counter++; - if ($counter >= $insertParam) { - $self->{centstorage}->query({ query => $query }); - $query = $query_start; - $counter = 0; - $append = ''; - } - } - $self->{centstorage}->query({ query => $query }) if ($counter > 0); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HGServiceMonthAvailability.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HGServiceMonthAvailability.pm deleted file mode 100644 index 7422107a83..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HGServiceMonthAvailability.pm +++ /dev/null @@ -1,93 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::HGServiceMonthAvailability; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{'name'} = "mod_bi_hgservicemonthavailability"; - $self->{'timeColumn'} = "time_id"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub insertStats { - my $self = shift; - my ($time_id, $data) = @_; - my $insertParam = 1000; - - my $query_start = "INSERT INTO `".$self->{'name'}."`". - " (`time_id`, `modbihg_id`, `modbihc_id`, `modbisc_id`, `liveservice_id`, `available`,". - " `unavailable_time`, `degraded_time`, `alert_unavailable_opened`, `alert_unavailable_closed`, ". - " `alert_degraded_opened`, `alert_degraded_closed`, ". - " `alert_other_opened`, `alert_other_closed`, ". - " `alert_degraded_total`, `alert_unavailable_total`,". - " `alert_other_total`, `mtrs`, `mtbf`, `mtbsi`)". - " VALUES "; - my $counter = 0; - my $query = $query_start; - my $append = ''; - - foreach my $entry (@$data) { - my $size = scalar(@$entry); - - $query .= $append . "($time_id"; - for (my $i = 0; $i < $size; $i++) { - $query .= ', ' . (defined($entry->[$i]) ? $entry->[$i] : 'NULL'); - } - $query .= ')'; - - $append = ','; - $counter++; - if ($counter >= $insertParam) { - $self->{centstorage}->query({ query => $query }); - $query = $query_start; - $counter = 0; - $append = ''; - } - } - $self->{centstorage}->query({ query => $query }) if ($counter > 0); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HostAvailability.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HostAvailability.pm deleted file mode 100644 index f908982669..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/HostAvailability.pm +++ /dev/null @@ -1,175 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; -use POSIX; -use Time::Local; - -package gorgone::modules::centreon::mbi::libs::bi::HostAvailability; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{"name"} = "mod_bi_hostavailability"; - $self->{"timeColumn"} = "time_id"; - $self->{"nbLinesInFile"} = 0; - $self->{"commitParam"} = 500000; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -#Only for daily mode -sub insertStats { - my $self = shift; - my ($data, $time_id, $liveserviceId) = @_; - my $insertParam = 10000; - - my $query_start = "INSERT INTO `" . $self->{name} . "`". - " (`modbihost_id`, `time_id`, `liveservice_id`, `available`, ". - " `unavailable`,`unreachable`, `alert_unavailable_opened`, `alert_unavailable_closed`, ". - " `alert_unreachable_opened`, `alert_unreachable_closed`) ". - " VALUES "; - my $counter = 0; - my $query = $query_start; - my $append = ''; - - while (my ($modBiHostId, $stats) = each %$data) { - my @tab = @$stats; - if ($stats->[0] + $stats->[1] + $stats->[2] == 0) { - next; - } - - $query .= $append . "($modBiHostId, $time_id, $liveserviceId"; - for (my $i = 0; $i < scalar(@$stats); $i++) { - $query .= ', ' . $stats->[$i]; - } - $query .= ')'; - - $append = ','; - $counter++; - if ($counter >= $insertParam) { - $self->{centstorage}->query({ query => $query }); - $query = $query_start; - $counter = 0; - $append = ''; - } - } - $self->{centstorage}->query({ query => $query }) if ($counter > 0); -} - -sub saveStatsInFile { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($data, $time_id, $liveserviceId,$fh) = @_; - my $query; - my $row; - - while (my ($modBiHostId, $stats) = each %$data) { - my @tab = @$stats; - if ($stats->[0]+$stats->[1]+$stats->[4] == 0) { - next; - } - - #Filling the dump file with data - $row = $modBiHostId."\t".$time_id."\t".$liveserviceId; - for (my $i = 0; $i < scalar(@$stats); $i++) { - $row.= "\t".$stats->[$i] - } - $row .= "\n"; - - #Write row into file - print $fh $row; - $self->{"nbLinesInFile"}+=1; - } -} - -sub getCurrentNbLines{ - my $self = shift; - return $self->{"nbLinesInFile"}; -} - -sub getCommitParam{ - my $self = shift; - return $self->{"commitParam"}; -} -sub setCurrentNbLines{ - my $self = shift; - my $nbLines = shift; - $self->{"nbLinesInFile"} = $nbLines; -} - -sub getHGMonthAvailability { - my ($self, $start, $end, $eventObj) = @_; - my $db = $self->{"centstorage"}; - - $self->{"logger"}->writeLog("DEBUG","[HOST] Calculating availability for hosts"); - my $query = "SELECT h.hg_id, h.hc_id, hc.id as cat_id, hg.id as group_id, ha.liveservice_id, avg(available/(available+unavailable+unreachable)) as av_percent,"; - $query .= " sum(available) as av_time, sum(unavailable) as unav_time, sum(alert_unavailable_opened) as unav_opened, sum(alert_unavailable_closed) as unav_closed,"; - $query .= " sum(alert_unreachable_opened) as unr_opened, sum(alert_unreachable_closed) as unr_closed"; - $query .= " FROM ".$self->{"name"}." ha"; - $query .= " STRAIGHT_JOIN mod_bi_time t ON (t.id = ha.time_id )"; - $query .= " STRAIGHT_JOIN mod_bi_hosts h ON (ha.modbihost_id = h.id)"; - $query .= " STRAIGHT_JOIN mod_bi_hostgroups hg ON (h.hg_name=hg.hg_name AND h.hg_id=hg.hg_id)"; - $query .= " STRAIGHT_JOIN mod_bi_hostcategories hc ON (h.hc_name=hc.hc_name AND h.hc_id=hc.hc_id)"; - $query .= " WHERE t.year = YEAR('".$start."') AND t.month = MONTH('".$start."') and t.hour=0"; - $query .= " GROUP BY h.hg_id, h.hc_id, ha.liveservice_id"; - my $sth = $db->query({ query => $query }); - - $self->{"logger"}->writeLog("DEBUG","[HOST] Calculating MTBF/MTRS/MTBSI for Host"); - my @data = (); - while (my $row = $sth->fetchrow_hashref()) { - my ($totalDownEvents, $totalUnrEvents) = $eventObj->getNbEvents($start, $end, $row->{'hg_id'}, $row->{'hc_id'}, $row->{'liveservice_id'}); - my ($mtrs, $mtbf, $mtbsi) = (undef, undef, undef); - if (defined($totalDownEvents) && $totalDownEvents != 0) { - $mtrs = $row->{'unav_time'}/$totalDownEvents; - $mtbf = $row->{'av_time'}/$totalDownEvents; - $mtbsi = ($row->{'unav_time'}+$row->{'av_time'})/$totalDownEvents; - } - my @tab = ($row->{'group_id'}, $row->{'cat_id'}, $row->{'liveservice_id'}, $row->{'av_percent'}, $row->{'unav_time'}, - $row->{'unav_opened'}, $row->{'unav_closed'}, $row->{'unr_opened'}, $row->{'unr_closed'}, - $totalDownEvents, $totalUnrEvents, $mtrs, $mtbf, $mtbsi); - push @data, \@tab; - } - - return \@data; -} -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/LiveService.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/LiveService.pm deleted file mode 100644 index 79a97c086d..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/LiveService.pm +++ /dev/null @@ -1,223 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::LiveService; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - - $self->{logger} = shift; - $self->{centstorage} = shift; - if (@_) { - $self->{centreon} = shift; - } - bless $self, $class; - return $self; -} - -sub getLiveServicesByName { - my $self = shift; - my $db = $self->{"centstorage"}; - my $name = shift; - my $interval = shift; - my $query = "SELECT `id`, `name`"; - $query .= " FROM `mod_bi_liveservice`"; - $query .= " WHERE `name` like '".$name."%'"; - my $sth = $db->query({ query => $query }); - my %result = (); - while (my $row = $sth->fetchrow_hashref()) { - $result{ $row->{name} } = $row->{id}; - } - return (\%result); -} - -sub getLiveServicesByTpId { - my $self = shift; - my $db = $self->{"centstorage"}; - my $name = shift; - my $interval = shift; - my $query = "SELECT `id`, `timeperiod_id`"; - $query .= " FROM `mod_bi_liveservice` "; - my $sth = $db->query({ query => $query }); - my %result = (); - while (my $row = $sth->fetchrow_hashref()) { - $result{$row->{'timeperiod_id'}} = $row->{"id"}; - } - return (\%result); -} - -sub getLiveServicesByNameForTpId { - my $self = shift; - my $db = $self->{"centstorage"}; - my $tpId = shift; - my $query = "SELECT `id`, `name`"; - $query .= " FROM `mod_bi_liveservice` "; - $query .= "WHERE timeperiod_id = ".$tpId; - my $sth = $db->query({ query => $query }); - my ($name, $id); - - while (my $row = $sth->fetchrow_hashref()) { - ($name, $id) = ($row->{'name'}, $row->{'id'}); - } - return ($name,$id); -} - -sub getLiveServiceIdsInString { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{'logger'}; - my $ids = shift; - - my $idStr = ""; - - my $query = "SELECT `id`"; - $query .= " FROM mod_bi_liveservice"; - $query .= " WHERE timeperiod_id IN (".$ids.")"; - my $sth = $db->query({ query => $query }); - my %result = (); - while (my $row = $sth->fetchrow_hashref()) { - $idStr .= $row->{'id'}.","; - } - $idStr =~ s/\,$//; - return $idStr; -} - -sub getLiveServicesByNameForTpIds { - my $self = shift; - my $db = $self->{"centstorage"}; - my $ids = shift; - - my $idStr = ""; - - foreach my $key (keys %$ids) { - if ($idStr eq "") { - $idStr .= $key; - }else { - $idStr .= ",".$key; - } - } - if ($idStr eq "") { - $self->{logger}->writeLog("ERROR", "Select a timeperiod in the ETL configuration menu"); - } - my $query = "SELECT `id`, `name`"; - $query .= " FROM mod_bi_liveservice"; - $query .= " WHERE timeperiod_id IN (".$idStr.")"; - my $sth = $db->query({ query => $query }); - my %result = (); - while (my $row = $sth->fetchrow_hashref()) { - $result{ $row->{name} } = $row->{id}; - } - return \%result; -} - -sub getTimeperiodName { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $id = shift; - my $query = "SELECT name FROM mod_bi_liveservice WHERE timeperiod_id=".$id; - my $sth = $db->query({ query => $query }); - my $name = ""; - if (my $row = $sth->fetchrow_hashref()) { - $name = $row->{'name'}; - } - return($name); -} - -sub getTimeperiodId { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $name = shift; - my $query = "SELECT timeperiod_id FROM mod_bi_liveservice WHERE name='".$name."'"; - my $sth = $db->query({ query => $query }); - my $id = 0; - if (my $row = $sth->fetchrow_hashref()) { - $id = $row->{'timeperiod_id'}; - } - return($id); -} - -sub insert { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $name = shift; - my $id = shift; - my $query = "INSERT INTO `mod_bi_liveservice` (`name`, `timeperiod_id`) VALUES ('".$name."', ".$id.")"; - my $sth = $db->query({ query => $query }); -} - -sub insertList { - my $self = shift; - my $db = $self->{"centstorage"}; - my $list = shift; - - while (my ($id, $name) = each %$list) { - my $tpName = $self->getTimeperiodName($id); - my $tpId = $self->getTimeperiodId($name); - if ($tpName ne "" && $name ne $tpName) { - $self->updateById($id, $name); - }elsif ($tpId > 0 && $tpId != $id) { - $self->update($name, $id); - }elsif ($tpId == 0 && $tpName eq "") { - $self->insert($name, $id); - } - } -} - -sub update { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $name = shift; - my $id = shift; - my $query = "UPDATE `mod_bi_liveservice` SET `timeperiod_id`=".$id." WHERE name='".$name."'"; - $db->query({ query => $query }); -} - -sub updateById { - my $self = shift; - my $db = $self->{"centstorage"}; - - my ($id, $name) = (shift, shift); - my $query = "UPDATE `mod_bi_liveservice` SET `name`='".$name."' WHERE timeperiod_id=".$id; - $db->query({ query => $query }); -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "TRUNCATE TABLE `mod_bi_liveservice`"; - $db->query({ query => $query }); - $db->query({ query => "ALTER TABLE `mod_bi_liveservice` AUTO_INCREMENT=1" }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Loader.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Loader.pm deleted file mode 100644 index 6f4c7b421c..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Loader.pm +++ /dev/null @@ -1,121 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; -use POSIX; - -package gorgone::modules::centreon::mbi::libs::bi::Loader; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{'tempFolder'} = "/tmp/"; - bless $self, $class; - return $self; -} - -sub setStorageDir { - my $self = shift; - my $logger = $self->{'logger'}; - my $tempFolder = shift; - if (!defined($tempFolder)) { - $logger->writeLog("ERROR", "Temporary storage folder is not defined"); - } - if (! -d $tempFolder && ! -w $tempFolder) { - $logger->writeLog("ERROR", "Cannot write into directory ".$tempFolder); - } - if ($tempFolder !~ /\/$/) { - $tempFolder .= "/"; - } - $self->{'tempFolder'} = $tempFolder; -} -sub getStorageDir { - my $self = shift; - return $self->{'tempFolder'}; -} -sub loadData { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($tableName, $inFile) = (shift, shift); - my $query = "LOAD DATA LOCAL INFILE '".$inFile."' INTO TABLE `".$tableName."` CHARACTER SET UTF8 IGNORE 1 LINES"; - my $sth = $db->query({ query => $query }); -} -sub disableKeys { - my $self = shift; - my $db = $self->{"centstorage"}; - my $tableName = shift; - my $query = "ALTER TABLE `".$tableName."` DISABLE KEYS"; - my $sth = $db->query({ query => $query }); -} - -sub enableKeys { - my $self = shift; - my $db = $self->{"centstorage"}; - my $tableName = shift; - my $query = "ALTER TABLE `".$tableName."` ENABLE KEYS"; - my $sth = $db->query({ query => $query }); -} - -sub dumpTableStructure { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{'logger'}; - my ($tableName) = (shift); - - my $sql = ""; - my $sth = $db->query({ query => "SHOW CREATE TABLE ".$tableName }); - if (my $row = $sth->fetchrow_hashref()) { - $sql = $row->{'Create Table'}; - }else { - $logger->writeLog("WARNING", "Cannot get structure for table : ".$tableName); - return (undef); - } - $sth->finish; - return ($sql); -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - my $tableName = shift; - my $query = "TRUNCATE TABLE `".$tableName."`"; - my $sth = $db->query({ query => $query }); -} -sub dropTable { - my $self = shift; - my $db = $self->{"centstorage"}; - my $tableName = shift; - my $query = "DROP TABLE IF EXISTS `".$tableName."`"; - my $sth = $db->query({ query => $query }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricCentileValue.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricCentileValue.pm deleted file mode 100644 index a4348a7ce1..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricCentileValue.pm +++ /dev/null @@ -1,182 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::MetricCentileValue; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centstorage: Instance of centreonDB class for connection to Centreon database -# $centreon: Instance of centreonDB class for connection to Centstorage database -sub new { - my ($class, %options) = (shift, @_); - my $self = {}; - $self->{logger} = $options{logger}; - $self->{centstorage} = $options{centstorage}; - $self->{centreon} = $options{centreon}; - $self->{time} = $options{time}; - $self->{centileProperties} = $options{centileProperties}; - $self->{timePeriod} = $options{timePeriod}; - $self->{liveService} = $options{liveService}; - - $self->{today_servicemetrics} = "mod_bi_tmp_today_servicemetrics"; #BIMetric -> createTodayTable - - #Daily values - $self->{name} = "mod_bi_metriccentiledailyvalue"; - - #Week values - $self->{name_week} = "mod_bi_metriccentileweeklyvalue"; - - #Month values - $self->{name_month} = "mod_bi_metriccentilemonthlyvalue"; - - $self->{timeColumn} = "time_id"; - bless $self, $class; - return $self; -} - -#getName($granularity) : "month","week" -sub getName { - my $self = shift; - my $granularity = shift; - my $name = $self->{name}; - - if (defined($granularity) && ($granularity eq "month" || $granularity eq "week")) { - my $key = 'name_' . $granularity; - $name = $self->{$key}; - } - return $name; -} - -sub getTmpName { - my ($self, $granularity) = @_; - my $name = $self->{tmp_name}; - if (defined $granularity && ($granularity eq "month" || $granularity eq "week")) { - my $key = 'tmp_name_' . $granularity; - $name = $self->{$key}; - } - - return $name; -} - -sub getTimeColumn { - my $self = shift; - - return $self->{timeColumn}; -} - -sub getMetricsCentile { - my ($self, %options) = @_; - - my $results = {}; - my $centileServiceCategories = $options{etlProperties}->{'centile.include.servicecategories'}; - my $query = 'SELECT id, metric_id FROM ' . $self->{today_servicemetrics} . ' sm ' . - ' WHERE sm.sc_id IN (' . $centileServiceCategories . ')'; - my $sth = $self->{centstorage}->query({ query => $query }); - while (my $row = $sth->fetchrow_arrayref()) { - $results->{$$row[1]} = [] if (!defined($results->{$$row[1]})); - push @{$results->{$$row[1]}}, $$row[0]; - } - - return $results; -} - -sub getTimePeriodQuery { - my ($self, %options) = @_; - - my $subQuery = ''; - # Get the time period to apply to each days of the period given in parameter - my $totalDays = $self->{time}->getTotalDaysInPeriod($options{start}, $options{end}) + 1; # +1 because geTotalDaysInPeriod return the number of day between start 00:00 and end 00:00 - my $counter = 1; - my $currentStart = $options{start}; - my $append = ''; - while ($counter <= $totalDays) { - my $rangeDay = $self->{timePeriod}->getTimeRangesForDayByDateTime($options{liveServiceName}, $currentStart, $self->{time}->getDayOfWeek($currentStart)); - if (scalar($rangeDay)) { - my @tabPeriod = @$rangeDay; - my ($start_date, $end_date); - my $tabSize = scalar(@tabPeriod); - for (my $count = 0; $count < $tabSize; $count++) { - my $range = $tabPeriod[$count]; - if ($count == 0) { - $start_date = $range->[0]; - } - if ($count == $tabSize - 1) { - $end_date = $range->[1]; - } - $subQuery .= $append . "(ctime >= UNIX_TIMESTAMP(" . ($range->[0]) . ") AND ctime < UNIX_TIMESTAMP(" . ($range->[1]) . "))"; - $append = ' OR '; - } - } - $currentStart = $self->{time}->addDateInterval($currentStart, 1, "DAY"); - $counter++; - } - - return $subQuery; -} - -sub calcMetricsCentileValueMultipleDays { - my ($self, %options) = @_; - - my $centileParam = $self->{centileProperties}->getCentileParams(); - foreach (@$centileParam) { - my ($centile, $timeperiodId) = ($_->{centile_param}, $_->{timeperiod_id}); - my ($liveServiceName, $liveServiceId) = $self->{liveService}->getLiveServicesByNameForTpId($timeperiodId); - - #Get Id for the couple centile / timeperiod - my $centileId; - my $query = "SELECT id FROM mod_bi_centiles WHERE centile_param = " . $centile . " AND liveservice_id = (SELECT id FROM mod_bi_liveservice WHERE timeperiod_id = " . $timeperiodId . ")"; - my $sth = $self->{centstorage}->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - if (defined($row->{id})) { - $centileId = $row->{id}; - } - } - - next if (!defined($centileId)); - - my $total = scalar(keys %{$options{metricsId}}); - $self->{logger}->writeLog("INFO", "Processing " . $options{granularity} . " for Centile: [" . $options{start} . "] to [" . $options{end} . "] - " . $liveServiceName . " - " . $centile . ' (' . $total . ' metrics)'); - my $sub_query_timeperiod = $self->getTimePeriodQuery(start => $options{start}, end => $options{end}, liveServiceName => $liveServiceName); - $query = 'SELECT value FROM (SELECT value, @counter := @counter + 1 AS counter FROM (select @counter := 0) AS initvar, data_bin WHERE id_metric = ? AND (' . $sub_query_timeperiod . ') ORDER BY value ASC) AS X where counter = ceil(' . $centile . ' * @counter / 100)'; - my $sth_centile = $self->{centstorage}->prepare($query); - my $current = 1; - foreach my $metricId (keys %{$options{metricsId}}) { - $self->{logger}->writeLog("DEBUG", "Processing metric id for Centile: " . $metricId . " ($current/$total)"); - $sth_centile->execute($metricId); - my $row = $sth_centile->fetchrow_arrayref(); - $current++; - next if (!defined($row)); - - foreach (@{$options{metricsId}->{$metricId}}) { - my $query_insert = 'INSERT INTO ' . $self->getName($options{granularity}) . - '(servicemetric_id, time_id, liveservice_id, centile_value, centile_param, centile_id, total, warning_treshold, critical_treshold)' . - "SELECT '" . $_ . "', '" . $options{timeId} . "', '" . $liveServiceId . "', '" . $$row[0] . "', '" . $centile . "', '" . $centileId . "', " . - 'm.max, m.warn, m.crit FROM metrics m WHERE m.metric_id = ' . $metricId; - $self->{centstorage}->query({ query => $query_insert }); - } - } - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricDailyValue.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricDailyValue.pm deleted file mode 100644 index 55c2def7b6..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricDailyValue.pm +++ /dev/null @@ -1,146 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::MetricDailyValue; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{logger} = shift; - $self->{centstorage} = shift; - - $self->{name_minmaxavg_tmp} = 'mod_bi_tmp_minmaxavgvalue'; - $self->{name_firstlast_tmp} = 'mod_bi_tmp_firstlastvalues'; - if (@_) { - $self->{name_minmaxavg_tmp} .= $_[0]; - $self->{name_firstlast_tmp} .= $_[0]; - } - - $self->{today_servicemetrics} = "mod_bi_tmp_today_servicemetrics"; - $self->{name} = "mod_bi_metricdailyvalue"; - $self->{timeColumn} = "time_id"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub dropTempTables { - my $self = shift; - my $db = $self->{"centstorage"}; - my $query = "DROP TABLE `" . $self->{name_minmaxavg_tmp} . "`"; - $db->query({ query => $query }); - $query = "DROP TABLE `" . $self->{name_firstlast_tmp} . "`"; - $db->query({ query => $query }); -} - -sub insertValues { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my $liveServiceId = shift; - my $timeId = shift; - - my $query = "INSERT INTO " . $self->{"name"}; - $query .= " SELECT sm.id as servicemetric_id, '".$timeId."', ".$liveServiceId." as liveservice_id,"; - $query .= " mmavt.avg_value, mmavt.min_value, mmavt.max_value, flvt.`first_value`, flvt.`last_value`, m.max,"; - $query .= " m.warn, m.crit"; - $query .= " FROM " . $self->{name_minmaxavg_tmp} . " mmavt"; - $query .= " JOIN (metrics m, " . $self->{'today_servicemetrics'} . " sm)"; - $query .= " ON (mmavt.id_metric = m.metric_id and mmavt.id_metric = sm.metric_id)"; - $query .= " LEFT JOIN " . $self->{name_firstlast_tmp} . " flvt ON (mmavt.id_metric = flvt.id_metric)"; - $db->query({ query => $query }); - - $self->dropTempTables(); -} - -sub getMetricCapacityValuesOnPeriod { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($start_time_id, $end_time_id, $etlProperties) = @_; - - my $query = " SELECT servicemetric_id, liveservice_id, "; - $query .= " `first_value`, total"; - $query .= " FROM mod_bi_liveservice l, mod_bi_servicemetrics m, ".$self->{"name"}." v"; - $query .= " WHERE timeperiod_id IN (".$etlProperties->{'capacity.include.liveservices'}.")"; - $query .= " AND l.id = v.liveservice_id"; - $query .= " AND time_id = ".$start_time_id; - if (defined($etlProperties->{'capacity.exclude.metrics'}) && $etlProperties->{'capacity.exclude.metrics'} ne "") { - $query .= " AND metric_name NOT IN (".$etlProperties->{'capacity.exclude.metrics'}.")"; - } - $query .= " AND sc_id IN (".$etlProperties->{'capacity.include.servicecategories'}.")"; - $query .= " AND v.servicemetric_id = m.id"; - $query .= " GROUP BY servicemetric_id, liveservice_id"; - my $sth = $db->query({ query => $query }); - my %data = (); - while (my $row = $sth->fetchrow_hashref()) { - my @table = ($row->{"servicemetric_id"}, $row->{"liveservice_id"}, $row->{first_value}, $row->{"total"}); - $data{$row->{"servicemetric_id"}.";".$row->{"liveservice_id"}} = \@table; - } - - $query = " SELECT servicemetric_id, liveservice_id, "; - $query .= "`last_value`, total"; - $query .= " FROM mod_bi_liveservice l, mod_bi_servicemetrics m, ".$self->{"name"}." v"; - $query .= " WHERE timeperiod_id IN (".$etlProperties->{'capacity.include.liveservices'}.")"; - $query .= " AND l.id = v.liveservice_id"; - $query .= " AND time_id = ".$end_time_id; - if (defined($etlProperties->{'capacity.exclude.metrics'}) && $etlProperties->{'capacity.exclude.metrics'} ne "") { - $query .= " AND metric_name NOT IN (".$etlProperties->{'capacity.exclude.metrics'}.")"; - } - $query .= " AND sc_id IN (".$etlProperties->{'capacity.include.servicecategories'}.")"; - $query .= " AND v.servicemetric_id = m.id"; - $query .= " GROUP BY servicemetric_id, liveservice_id"; - - $sth = $db->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - my $entry = $data{$row->{servicemetric_id} . ';' . $row->{liveservice_id}}; - if (defined($entry)) { - $entry->[4] = $row->{last_value}; - $entry->[5] = $row->{total}; - } else { - my @table; - $table[0] = $row->{servicemetric_id}; - $table[1] = $row->{liveservice_id}; - $table[4] = $row->{last_value}; - $table[5] = $row->{total}; - $data{$row->{servicemetric_id} . ';' . $row->{liveservice_id}} = \@table; - } - } - return \%data; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricHourlyValue.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricHourlyValue.pm deleted file mode 100644 index a28483544d..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricHourlyValue.pm +++ /dev/null @@ -1,72 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::MetricHourlyValue; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{logger} = shift; - $self->{centstorage} = shift; - - $self->{name_minmaxavg_tmp} = 'mod_bi_tmp_minmaxavgvalue'; - if (@_) { - $self->{name_minmaxavg_tmp} .= $_[0]; - } - - $self->{servicemetrics} = "mod_bi_tmp_today_servicemetrics"; - $self->{name} = "mod_bi_metrichourlyvalue"; - $self->{timeColumn} = "time_id"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub insertValues { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my $query = "INSERT INTO ".$self->{"name"}; - $query .= " SELECT sm.id as servicemetric_id, t.id as time_id, mmavt.avg_value, mmavt.min_value, mmavt.max_value, m.max , m.warn, m.crit"; - $query .= " FROM " . $self->{name_minmaxavg_tmp} . " mmavt"; - $query .= " JOIN (metrics m, " . $self->{servicemetrics} . " sm, mod_bi_time t)"; - $query .= " ON (mmavt.id_metric = m.metric_id and mmavt.id_metric = sm.metric_id AND mmavt.valueTime = t.dtime)"; - $db->query({ query => $query }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricMonthCapacity.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricMonthCapacity.pm deleted file mode 100644 index 9740d0c69f..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MetricMonthCapacity.pm +++ /dev/null @@ -1,89 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::MetricMonthCapacity; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{"name"} = "mod_bi_metricmonthcapacity"; - $self->{"timeColumn"} = "time_id"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub insertStats { - my $self = shift; - my $db = $self->{centstorage}; - my ($time_id, $data) = @_; - my $insertParam = 5000; - - my $query_start = "INSERT INTO `" . $self->{name} . "`". - "(`time_id`, `servicemetric_id`, `liveservice_id`,". - " `first_value`, `first_total`, `last_value`, `last_total`)". - " VALUES "; - my $counter = 0; - my $query = $query_start; - my $append = ''; - - while (my ($key, $entry) = each %$data) { - $query .= $append . "($time_id"; - - for (my $i = 0; $i <= 5; $i++) { - $query .= ', ' . (defined($entry->[$i]) ? $entry->[$i] : 'NULL'); - } - $query .= ')'; - - $append = ','; - $counter++; - if ($counter >= $insertParam) { - $db->query({ query => $query }); - $query = $query_start; - $counter = 0; - $append = ''; - } - } - $db->query({ query => $query }) if ($counter > 0); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MySQLTables.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MySQLTables.pm deleted file mode 100644 index 05638b625d..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/MySQLTables.pm +++ /dev/null @@ -1,307 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::libs::bi::MySQLTables; - -use strict; -use warnings; -use POSIX; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - - $self->{logger} = shift; - $self->{centstorage} = shift; - if (@_) { - $self->{centreon} = shift; - } - bless $self, $class; - return $self; -} - -sub tableExists { - my $self = shift; - - my ($name) = (shift); - my $statement = $self->{centstorage}->query({ query => "SHOW TABLES LIKE '".$name."'" }); - - if (!(my @row = $statement->fetchrow_array())) { - return 0; - } else { - return 1; - } -} - -sub createTable { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($name, $structure, $mode) = @_; - my $statement = $db->query({ query => "SHOW TABLES LIKE '".$name."'" }); - if (!$self->tableExists($name)) { - if (defined($structure)) { - $logger->writeLog("DEBUG", "[CREATE] table [".$name."]"); - $db->query({ query => $structure }); - return 0; - }else { - $logger->writeLog("FATAL", "[CREATE] Cannot find table [".$name."] structure"); - } - } - return 1; -} - -sub dumpTableStructure { - my $self = shift; - my ($tableName) = (shift); - - my $sql = ""; - my $sth = $self->{centstorage}->query({ query => "SHOW CREATE TABLE " . $tableName }); - if (my $row = $sth->fetchrow_hashref()) { - $sql = $row->{'Create Table'}; - $sql =~ s/(CONSTRAINT.*\n)//g; - $sql =~ s/(\,\n\s+\))/\)/g; - }else { - die "Cannot get structure for table : ".$tableName; - } - return ($sql); -} - -# create table data_bin with partitions -sub createParts { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my ($start, $end, $tableStructure, $tableName, $column) = @_; - if (!defined($tableStructure)) { - $logger->writeLog("FATAL", "[CREATE] Cannot find table [".$tableName."] structure"); - } - if ($self->tableExists($tableName)) { - return 1; - } - $tableStructure =~ s/\n.*PARTITION.*//g; - $tableStructure =~ s/\,[\n\s]+\)/\)/; - $tableStructure .= " PARTITION BY RANGE(`".$column."`) ("; - my $timeObj = Time->new($logger,$db); - my $runningStart = $timeObj->addDateInterval($start, 1, "DAY"); - while ($timeObj->compareDates($end, $runningStart) > 0) { - my @partName = split (/\-/, $runningStart); - $tableStructure .= "PARTITION p" . $partName[0] . $partName[1] . $partName[2] . " VALUES LESS THAN (FLOOR(UNIX_TIMESTAMP('".$runningStart."'))),"; - $runningStart= $timeObj->addDateInterval($runningStart, 1, "DAY"); - } - my @partName = split (/\-/, $runningStart); - $tableStructure .= "PARTITION p".$partName[0].$partName[1].$partName[2]." VALUES LESS THAN (FLOOR(UNIX_TIMESTAMP('".$runningStart."'))));"; - $logger->writeLog("DEBUG", "[CREATE] table partitionned [".$tableName."] min value: ".$start.", max value: ".$runningStart.", range: 1 DAY\n"); - $db->query({ query => $tableStructure }); - return 0; -} - -sub updateParts { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($rangeEnd, $tableName) = @_; - my $timeObj = Time->new($logger,$db); - - my $isPartitioned = $self->isTablePartitioned($tableName); - if (!$isPartitioned) { - $logger->writeLog("WARNING", "[UPDATE PARTS] partitioning is not activated for table [".$tableName."]"); - } else { - my $range = $self->getLastPartRange($tableName); - $range = $timeObj->addDateInterval($range, 1, "DAY"); - while ($timeObj->compareDates($rangeEnd, $range) >= 0) { - $logger->writeLog("DEBUG", "[UPDATE PARTS] Updating partitions for table [".$tableName."] (last range : ".$range.")"); - my @partName = split (/\-/, $range); - my $query = "ALTER TABLE `".$tableName."` ADD PARTITION (PARTITION `p".$partName[0].$partName[1].$partName[2]."` VALUES LESS THAN(FLOOR(UNIX_TIMESTAMP('".$range."'))))"; - $db->query({ query => $query }); - $range = $timeObj->addDateInterval($range, 1, "DAY"); - } - } -} - -sub isTablePartitioned { - my $self = shift; - my $tableName = shift; - my $db = $self->{"centstorage"}; - - my $sth = $db->query({ query => "SHOW TABLE STATUS LIKE '".$tableName."'" }); - if (my $row = $sth->fetchrow_hashref()) { - my $createOptions = $row->{"Create_options"}; - if (defined($createOptions) && $createOptions =~ m/partitioned/i) { - return 1; - } elsif (!defined($createOptions) || $createOptions !~ m/partitioned/i) { - return 0; - } - } - die "[TABLE STATUS CHECK] Cannot check if table is partitioned [".$tableName."]"; -} - -sub getLastPartRange { - my $self = shift; - my $tableName = shift; - - my $query = "SHOW CREATE TABLE $tableName"; - - my $partName; - my $sth = $self->{centstorage}->query({ query => $query }); - if (my $row = $sth->fetchrow_hashref()) { - while ($row->{'Create Table'} =~ /PARTITION.*?p(\d{4})(\d{2})(\d{2}).*?VALUES LESS THAN \([0-9]+?\)/g) { - $partName = "$1-$2-$3"; - } - } - - if (!defined($partName)) { - die "[UPDATE PARTS] Cannot find table [data_bin] in database"; - } - - return $partName; -} - -sub deleteEntriesForRebuild { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($start, $end, $tableName) = @_; - - if (!$self->isTablePartitioned($tableName)) { - $db->query({ query => "DELETE FROM ".$tableName." WHERE time_id >= UNIX_TIMESTAMP('".$start."') AND time_id < UNIX_TIMESTAMP('".$end."')" }); - } else { - my $query = "SELECT partition_name FROM information_schema.partitions "; - $query .= "WHERE table_name='".$tableName."' AND table_schema='".$db->db."'"; - $query .= " AND CONVERT(PARTITION_DESCRIPTION, SIGNED INTEGER) > UNIX_TIMESTAMP('".$start."')"; - $query .= " AND CONVERT(PARTITION_DESCRIPTION, SIGNED INTEGER) <= UNIX_TIMESTAMP('".$end."')"; - my $sth = $db->query({ query => $query }); - while(my $row = $sth->fetchrow_hashref()) { - $db->query({ query => "ALTER TABLE ".$tableName." TRUNCATE PARTITION ".$row->{'partition_name'} }); - } - $self->updateParts($end, $tableName); - } -} - -sub emptyTableForRebuild { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my $tableName = shift; - my $structure = shift; - my $column = shift; - - $structure =~ s/KEY.*\(\`$column\`\)\,//g; - $structure =~ s/KEY.*\(\`$column\`\)//g; - $structure =~ s/\,[\n\s+]+\)/\n\)/g; - if (!defined($_[0]) || !$self->isPartitionEnabled()) { - $db->query({ query => "DROP TABLE IF EXISTS ".$tableName }); - $db->query({ query => $structure }); - } else { - my ($start, $end) = @_; - $db->query({ query => "DROP TABLE IF EXISTS ".$tableName }); - $self->createParts($start, $end, $structure, $tableName, $column); - } - $db->query({ query => "ALTER TABLE `".$tableName."` ADD INDEX `idx_".$tableName."_".$column."` (`".$column."`)" }); -} - -sub dailyPurge { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my ($retentionDate, $tableName, $column) = @_; - if (!$self->isTablePartitioned($tableName)) { - $db->query({ query => "DELETE FROM `".$tableName."` WHERE ".$column." < UNIX_TIMESTAMP('".$retentionDate."')" }); - } else { - my $query = "SELECT GROUP_CONCAT(partition_name SEPARATOR ',') as partition_names FROM information_schema.partitions "; - $query .= "WHERE table_name='".$tableName."' AND table_schema='".$db->db."'"; - $query .= " AND CONVERT(PARTITION_DESCRIPTION, SIGNED INTEGER) < UNIX_TIMESTAMP('".$retentionDate."')"; - my $sth = $db->query({ query => $query }); - if(my $row = $sth->fetchrow_hashref()) { - if (defined($row->{'partition_names'}) && $row->{'partition_names'} ne "") { - $db->query({ query => "ALTER TABLE ".$tableName." DROP PARTITION ".$row->{'partition_names'} }); - } - } - } -} - -sub checkPartitionContinuity { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($table) = @_; - my $message = ""; - my $query = "select CONVERT(1+datediff(curdate(),(select from_unixtime(PARTITION_DESCRIPTION) from information_schema.partitions"; - $query .= " where table_schema = '".$db->{"db"}."' and table_name = '".$table."' and PARTITION_ORDINAL_POSITION=1)), SIGNED INTEGER) as nbDays,"; - $query .= " CONVERT(PARTITION_ORDINAL_POSITION, SIGNED INTEGER) as ordinalPosition "; - $query .= " from information_schema.partitions where table_schema = '".$db->{"db"}."' and table_name = '".$table."' order by PARTITION_ORDINAL_POSITION desc limit 1 "; - my $sth = $db->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - my $nbDays = int($row->{'nbDays'}); - my $ordinalPosition = int($row->{'ordinalPosition'}); - my $dif = int($nbDays - $ordinalPosition); - if($dif > 0){ - $message .= "[".$table.", last partition:".$self->checkLastTablePartition($table)." missing ".$dif." part.]"; - } - } - $sth->finish; - return($message); -} - -sub checkLastTablePartition{ - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($table) = @_; - my $message = ""; - my $query = "select from_unixtime(PARTITION_DESCRIPTION) as last_partition, IF(from_unixtime(PARTITION_DESCRIPTION)=CURDATE() AND HOUR(from_unixtime(PARTITION_DESCRIPTION))=0,1,0) as partition_uptodate "; - $query .="from information_schema.partitions where table_schema = '".$db->{"db"}."'"; - $query .= "and table_name = '".$table."'order by PARTITION_ORDINAL_POSITION desc limit 1"; - my $sth = $db->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - if($row->{'partition_uptodate'} == 0){ - $message = $row->{'last_partition'}; - } - } - $sth->finish; - return($message); -} - -sub dropIndexesFromReportingTable { - my $self = shift; - my $table = shift; - my $db = $self->{"centstorage"}; - my $indexes = $db->query({ query => "SHOW INDEX FROM ".$table }); - my $previous = ""; - while (my $row = $indexes->fetchrow_hashref()) { - if ($row->{"Key_name"} ne $previous) { - if (lc($row->{"Key_name"}) eq lc("PRIMARY")) { - $db->query({ query => "ALTER TABLE `".$table."` DROP PRIMARY KEY" }); - } else { - $db->query({ query => "ALTER TABLE `".$table."` DROP INDEX ".$row->{"Key_name"} }); - } - } - $previous = $row->{"Key_name"}; - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/ServiceAvailability.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/ServiceAvailability.pm deleted file mode 100644 index dee44a610b..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/ServiceAvailability.pm +++ /dev/null @@ -1,237 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::bi::ServiceAvailability; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{"name"} = "mod_bi_serviceavailability"; - $self->{"timeColumn"} = "time_id"; - $self->{"nbLinesInFile"} = 0; - $self->{"commitParam"} = 500000; - bless $self, $class; - return $self; -} - -sub getName { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub saveStatsInFile { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($data, $time_id, $liveserviceId,$fh) = @_; - my $query; - my $row; - - while (my ($modBiServiceId, $stats) = each %$data) { - my @tab = @$stats; - if ($stats->[0]+$stats->[1]+$stats->[2] == 0) { - next; - } - - #Filling the dump file with data - $row = $modBiServiceId."\t".$time_id."\t".$liveserviceId; - for (my $i = 0; $i < scalar(@$stats); $i++) { - $row.= "\t".$stats->[$i] - } - $row .= "\n"; - - #Write row into file - print $fh $row; - $self->{"nbLinesInFile"}++; - } -} - -sub insertStats { - my $self = shift; - my ($data, $time_id, $liveserviceId) = @_; - my $insertParam = 10000; - my $query_start = "INSERT INTO `" . $self->{name} . "`". - " (`modbiservice_id`, `time_id`, `liveservice_id`, `available`, ". - " `unavailable`, `degraded`, `alert_unavailable_opened`, `alert_unavailable_closed`, ". - " `alert_degraded_opened`, `alert_degraded_closed`, ". - " `alert_other_opened`, `alert_other_closed`)". - " VALUES "; - - #available+unvailable+alert_unavailable_closed - - my $counter = 0; - my $query = $query_start; - my $append = ''; - while (my ($modBiServiceId, $stats) = each %$data) { - my @tab = @$stats; - if ($stats->[0] + $stats->[1] + $stats->[2] == 0) { - next; - } - - $query .= $append . "($modBiServiceId, $time_id, $liveserviceId"; - for (my $i = 0; $i < scalar(@$stats); $i++) { - $query .= ', ' . $stats->[$i]; - } - $query .= ')'; - $append = ','; - $counter++; - - if ($counter >= $insertParam) { - $self->{centstorage}->query({ query => $query }); - $query = $query_start; - $counter = 0; - $append = ''; - } - } - - $self->{centstorage}->query({ query => $query }) if ($counter > 0); -} - -sub getCurrentNbLines { - my $self = shift; - return $self->{"nbLinesInFile"}; -} - -sub getCommitParam { - my $self = shift; - return $self->{"commitParam"}; -} - -sub setCurrentNbLines { - my $self = shift; - my $nbLines = shift; - $self->{"nbLinesInFile"} = $nbLines; -} - -sub getHGMonthAvailability { - my ($self, $start, $end, $eventObj) = @_; - my $db = $self->{"centstorage"}; - - my $query = "SELECT s.hg_id, s.hc_id, s.sc_id, sa.liveservice_id,"; - $query .= " hc.id as hcat_id, hg.id as group_id, sc.id as scat_id,"; - $query .= " avg((available+degraded)/(available+unavailable+degraded)) as av_percent,"; - $query .= " sum(available) as av_time, sum(unavailable) as unav_time, sum(degraded) as degraded_time,"; - $query .= " sum(alert_unavailable_opened) as unav_opened,sum(alert_unavailable_closed) as unav_closed,"; - $query .= " sum(alert_degraded_opened) as deg_opened,sum(alert_degraded_closed) as deg_closed,"; - $query .= " sum(alert_other_opened) as other_opened,sum(alert_other_closed) as other_closed "; - $query .= " FROM ".$self->{'name'}." sa"; - $query .= " STRAIGHT_JOIN mod_bi_time t ON (t.id = sa.time_id )"; - $query .= " STRAIGHT_JOIN mod_bi_services s ON (sa.modbiservice_id = s.id)"; - $query .= " STRAIGHT_JOIN mod_bi_hostgroups hg ON (s.hg_name=hg.hg_name AND s.hg_id=hg.hg_id)"; - $query .= " STRAIGHT_JOIN mod_bi_hostcategories hc ON (s.hc_name=hc.hc_name AND s.hc_id=hc.hc_id)"; - $query .= " STRAIGHT_JOIN mod_bi_servicecategories sc ON (s.sc_id=sc.sc_id AND s.sc_name=sc.sc_name)"; - $query .= " WHERE t.year = YEAR('".$start."') AND t.month = MONTH('".$start."') and t.hour=0"; - $query .= " GROUP BY s.hg_id, s.hc_id, s.sc_id, sa.liveservice_id"; - my $sth = $db->query({ query => $query }); - - my @data = (); - while (my $row = $sth->fetchrow_hashref()) { - my ($totalwarnEvents, $totalCritEvents, $totalOtherEvents) = $eventObj->getNbEvents($start, $end, $row->{'hg_id'}, $row->{'hc_id'}, $row->{'sc_id'}, $row->{'liveservice_id'}); - - my ($mtrs, $mtbf, $mtbsi) = (undef, undef, undef); - if (defined($totalCritEvents) && $totalCritEvents != 0) { - $mtrs = $row->{'unav_time'}/$totalCritEvents; - $mtbf = $row->{'av_time'}/$totalCritEvents; - $mtbsi = ($row->{'unav_time'}+$row->{'av_time'})/$totalCritEvents; - } - my @tab = ($row->{'group_id'}, $row->{'hcat_id'}, $row->{'scat_id'}, $row->{'liveservice_id'}, - $row->{'av_percent'}, $row->{'unav_time'}, $row->{'degraded_time'}, - $row->{'unav_opened'}, $row->{'unav_closed'}, $row->{'deg_opened'}, $row->{'deg_closed'}, $row->{'other_opened'}, $row->{'other_closed'}, - $totalwarnEvents, $totalCritEvents, $totalOtherEvents, $mtrs, $mtbf, $mtbsi); - push @data, \@tab; - } - return \@data; -} - -sub getHGMonthAvailability_optimised { - my ($self, $start, $end, $eventObj) = @_; - my $db = $self->{"centstorage"}; - - my $query = "SELECT * from ( SELECT s.hg_id, s.hc_id, s.sc_id, sa.liveservice_id, hc.id as hcat_id, hg.id as group_id, sc.id as scat_id,"; - $query .= "avg((available+degraded)/(available+unavailable+degraded)) as av_percent, "; - $query .= "sum(available) as av_time, sum(unavailable) as unav_time, sum(degraded) as degraded_time, "; - $query .= "sum(alert_unavailable_opened) as unav_opened,sum(alert_unavailable_closed) as unav_closed, "; - $query .= "sum(alert_degraded_opened) as deg_opened,sum(alert_degraded_closed) as deg_closed, "; - $query .= "sum(alert_other_opened) as other_opened,sum(alert_other_closed) as other_closed "; - $query .= "FROM mod_bi_serviceavailability sa "; - $query .= "STRAIGHT_JOIN mod_bi_services s ON (sa.modbiservice_id = s.id) "; - $query .= "STRAIGHT_JOIN mod_bi_hostgroups hg ON (s.hg_name=hg.hg_name AND s.hg_id=hg.hg_id) "; - $query .= "STRAIGHT_JOIN mod_bi_hostcategories hc ON (s.hc_name=hc.hc_name AND s.hc_id=hc.hc_id) "; - $query .= "STRAIGHT_JOIN mod_bi_servicecategories sc ON (s.sc_id=sc.sc_id AND s.sc_name=sc.sc_name)"; - $query .= " WHERE YEAR(from_unixtime(time_id)) = YEAR('".$start."') AND MONTH(from_unixtime(time_id)) = MONTH('".$start."') and hour(from_unixtime(time_id)) = 0 "; - $query .= "GROUP BY s.hg_id, s.hc_id, s.sc_id, sa.liveservice_id ) availability "; - $query .= "LEFT JOIN ( SELECT s.hg_id,s.hc_id,s.sc_id,e.modbiliveservice_id, "; - $query .= "SUM(IF(state=1,1,0)) as warningEvents, SUM(IF(state=2,1,0)) as criticalEvents, "; - $query .= "SUM(IF(state=3,1,0)) as unknownEvents FROM mod_bi_servicestateevents e "; - $query .= "STRAIGHT_JOIN mod_bi_services s ON (e.modbiservice_id = s.id) "; - $query .= "STRAIGHT_JOIN mod_bi_hostgroups hg ON (s.hg_name=hg.hg_name AND s.hg_id=hg.hg_id) "; - $query .= "STRAIGHT_JOIN mod_bi_hostcategories hc ON (s.hc_name=hc.hc_name AND s.hc_id=hc.hc_id) "; - $query .= "STRAIGHT_JOIN mod_bi_servicecategories sc ON (s.sc_id=sc.sc_id AND s.sc_name=sc.sc_name) "; - $query .= "AND s.id = e.modbiservice_id AND start_time < UNIX_TIMESTAMP('".$end."') "; - $query .= "AND end_time > UNIX_TIMESTAMP('".$start."') AND e.state in (1,2,3) "; - $query .= "GROUP BY s.hg_id, s.hc_id, s.sc_id, e.modbiliveservice_id ) events "; - $query .= "ON availability.hg_id = events.hg_id AND availability.hc_id = events.hc_id "; - $query .= "AND availability.sc_id = events.sc_id "; - $query .= "AND availability.liveservice_id = events.modbiliveservice_id"; - - #Fields returned : - #hg_id | hc_id | sc_id | liveservice_id | hcat_id | group_id | scat_id | av_percent | av_time | unav_time | degraded_time | - #unav_opened | unav_closed | deg_opened | deg_closed | other_opened | other_closed | hg_id | hc_id | sc_id | - #modbiliveservice_id | warningEvents | criticalEvents | unknownEvents - my $sth = $db->query({ query => $query }); - - my @data = (); - while (my $row = $sth->fetchrow_hashref()) { - my ($totalwarnEvents, $totalCritEvents, $totalUnknownEvents) = ($row->{'warningEvents'},$row->{'criticalEvents'},$row->{'unknownEvents'}); - - my ($mtrs, $mtbf, $mtbsi) = (undef, undef, undef); - if (defined($totalCritEvents) && $totalCritEvents != 0) { - $mtrs = $row->{'unav_time'}/$totalCritEvents; - $mtbf = $row->{'av_time'}/$totalCritEvents; - $mtbsi = ($row->{'unav_time'}+$row->{'av_time'})/$totalCritEvents; - } - my @tab = ($row->{'group_id'}, $row->{'hcat_id'}, $row->{'scat_id'}, $row->{'liveservice_id'}, - $row->{'av_percent'}, $row->{'unav_time'}, $row->{'degraded_time'}, - $row->{'unav_opened'}, $row->{'unav_closed'}, $row->{'deg_opened'}, $row->{'deg_closed'}, $row->{'other_opened'}, $row->{'other_closed'}, - $totalwarnEvents, $totalCritEvents, $totalUnknownEvents, $mtrs, $mtbf, $mtbsi); - push @data, \@tab; - } - return \@data; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Time.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Time.pm deleted file mode 100644 index e7f8e6dffe..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/bi/Time.pm +++ /dev/null @@ -1,264 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::libs::bi::Time; - -use strict; -use warnings; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{logger} = shift; - $self->{centstorage} = shift; - if (@_) { - $self->{centreon} = shift; - } - $self->{insertQuery} = "INSERT IGNORE INTO `mod_bi_time` (id, hour, day, month_label, month, year, week, dayofweek, utime, dtime) VALUES "; - bless $self, $class; - return $self; -} - -sub getEntriesDtime { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my ($start, $end) = @_; - my $query = "SELECT date_format('%Y-%m-%d', dtime) as dtime"; - $query .= " FROM `mod_bi_time`"; - $query .= " WHERE dtime >= '".$start."' AND dtime <'".$end."'"; - - my $sth = $db->query({ query => $query }); - my @results = (); - if (my $row = $sth->fetchrow_hashref()) { - push @results, $row->{dtime}; - } - $sth->finish(); - return (@results); -} - -sub getEntryID { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my $dtime = shift; - my ($interval, $type); - if (@_) { - $interval = shift; - $type = shift; - } - my $query = "SELECT `id`, `utime`, date_format(dtime,'%Y-%m-%d') as dtime"; - $query .= " FROM `mod_bi_time`"; - if (!defined($interval)) { - $query .= " WHERE dtime = '".$dtime."'"; - }else { - $query .= " WHERE dtime = DATE_ADD('".$dtime."', INTERVAL ".$interval." ".$type.")"; - } - my $sth = $db->query({ query => $query }); - my @results = (); - if (my $row = $sth->fetchrow_hashref()) { - $results[0] = $row->{'id'}; - $results[1] = $row->{'utime'}; - } - $sth->finish(); - if (!scalar(@results)) { - $logger->writeLog("ERROR", "Cannot get time ID for date:".$dtime); - } - return (@results); -} - -sub getDayOfWeek { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my $date = shift; - - my $sth = $db->query({ query => "SELECT LOWER(DAYNAME('".$date."')) as dayOfWeek" }); - my $dayofweek; - if (my $row = $sth->fetchrow_hashref()) { - $dayofweek = $row->{"dayOfWeek"}; - }else { - $logger->writeLog("ERROR", "TIME: Cannot get day of week for date :".$date); - } - if (!defined($dayofweek)) { - $logger->writeLog("ERROR", "TIME: day of week for date ".$date." is null"); - } - return $dayofweek; -} - -sub getYesterdayTodayDate { - my $self = shift; - - # get yesterday date. date format : YYYY-MM-DD - my $sth = $self->{centstorage}->query({ query => "SELECT CURRENT_DATE() as today, DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY) as yesterday" }); - - my $yesterday; - my $today; - if (my $row = $sth->fetchrow_hashref()) { - $yesterday = $row->{yesterday}; - $today = $row->{today}; - } else { - $self->{logger}->writeLog('ERROR', "TIME: cannot get yesterday date"); - } - if (!defined($yesterday)) { - $self->{logger}->writeLog('ERROR', "TIME: Yesterday start date is null"); - } - if (!defined($today)) { - $self->{logger}->writeLog('ERROR', "TIME: today start date is null"); - } - return ($yesterday, $today); -} - -sub addDateInterval { - my $self = shift; - my ($date, $interval, $intervalType) = @_; - - # get new date. date format : YYYY-MM-DD - my $sth = $self->{centstorage}->query({ query => "SELECT DATE_ADD('".$date."', INTERVAL ".$interval." ".$intervalType.") as newDate" }); - - my $newDate; - if (my $row = $sth->fetchrow_hashref()) { - $newDate = $row->{newDate}; - } - if (!defined($newDate)) { - $self->{logger}->writeLog('ERROR', "TIME: DATE_ADD('".$date."', INTERVAL ".$interval." ".$intervalType.") returns null value"); - } - return $newDate; -} - -sub compareDates { - my $self = shift; - my ($date1, $date2) = @_; - - my $sth = $self->{centstorage}->query({ query => "SELECT DATEDIFF('".$date1."','".$date2."') as nbDays" }); - if (my $row = $sth->fetchrow_hashref()) { - return $row->{nbDays}; - } - - $self->{logger}->writeLog('ERROR', "TIME: Cannot compare two dates : ".$date1." and ".$date2); -} - -sub insertTimeEntriesForPeriod { - my $self = shift; - my $db = $self->{"centstorage"}; - my ($start, $end) = @_; - - my $interval = $self->getTotalDaysInPeriod($start, $end) * 24; - my $counter = 0; - my $date = "ADDDATE('".$start."',INTERVAL ".$counter." HOUR)"; - my $query_suffix = ""; - while ($counter <= $interval) { - $query_suffix .= "(UNIX_TIMESTAMP(".$date."),"; - $query_suffix .= "HOUR(".$date."),"; - $query_suffix .= "DAYOFMONTH(".$date."),"; - $query_suffix .= "LOWER(DATE_FORMAT(".$date.",'%M')),"; - $query_suffix .= "MONTH(".$date."),"; - $query_suffix .= "YEAR(".$date."),"; - $query_suffix .= "WEEK(".$date.", 3),"; - $query_suffix .= "LOWER(DAYNAME(".$date.")),"; - $query_suffix .= "UNIX_TIMESTAMP(".$date."),"; - $query_suffix .= "".$date."),"; - $counter++; - $date = "ADDDATE('".$start."',INTERVAL ".$counter." HOUR)"; - if ($counter % 30 == 0) { - chop($query_suffix); - $db->query({ query => $self->{insertQuery} . $query_suffix }); - $query_suffix = ""; - } - } - chop($query_suffix); - if ($query_suffix ne "") { - $db->query({ query => $self->{insertQuery} . $query_suffix }); - } -} - -# Delete duplicated entries inserted on winter/summer time change (same timestamp for 02:00 and 03:00) -sub deleteDuplicateEntries { - my $self = shift; - my $db = $self->{"centstorage"}; - my ($start, $end) = @_; - my $query = "SELECT max(id) as id"; - $query .= " FROM mod_bi_time"; - $query .= " WHERE dtime >='".$start."'"; - $query .= " AND dtime <= '".$end."'"; - $query .= " GROUP BY utime"; - $query .= " HAVING COUNT(utime) > 1"; - my $sth = $db->query({ query => $query }); - my $ids_to_delete = ""; - while (my $row = $sth->fetchrow_hashref()) { - $ids_to_delete .= $row->{'id'}.","; - } - if ($ids_to_delete ne "") { - chop ($ids_to_delete); - $db->query({ query => "DELETE FROM mod_bi_time WHERE id IN (".$ids_to_delete.")" }); - } -} - -sub getTotalDaysInPeriod { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($start, $end) = @_; - - my $query = "SELECT DATEDIFF('".$end."', '".$start."') diff"; - my $sth = $db->query({ query => $query }); - my $diff; - if (my $row = $sth->fetchrow_hashref()) { - $diff = $row->{'diff'}; - }else { - $logger->writeLog("ERROR", "TIME : Cannot get difference between period start and end"); - } - if (!defined($diff)){ - $logger->writeLog("ERROR", "TIME : Cannot get difference between period start and end"); - } - if($diff == 0) { - $logger->writeLog("ERROR", "TIME : start date is equal to end date"); - }elsif ($diff < 0) { - $logger->writeLog("ERROR", "TIME : start date is greater than end date"); - } - return $diff; -} - -sub truncateTable { - my $self = shift; - my $db = $self->{"centstorage"}; - - my $query = "TRUNCATE TABLE `mod_bi_time`"; - $db->query({ query => $query }); - $db->query({ query => "ALTER TABLE `mod_bi_time` AUTO_INCREMENT=1" }); -} - -sub deleteEntriesForPeriod { - my $self = shift; - my $db = $self->{"centstorage"}; - my ($start, $end) = @_; - - my $query = "DELETE FROM `mod_bi_time` WHERE dtime >= '".$start."' AND dtime < '".$end."'"; - $db->query({ query => $query }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/CentileProperties.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/CentileProperties.pm deleted file mode 100644 index d0d393891c..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/CentileProperties.pm +++ /dev/null @@ -1,60 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centreon::CentileProperties; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{logger} = shift; - $self->{centreon} = shift; - if (@_) { - $self->{centstorage} = shift; - } - bless $self, $class; - return $self; -} - -sub getCentileParams { - my $self = shift; - my $centreon = $self->{centreon}; - my $logger = $self->{logger}; - - my $centileParams = []; - my $query = "SELECT `centile_param`, `timeperiod_id` FROM `mod_bi_options_centiles`"; - my $sth = $centreon->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - if (defined($row->{centile_param}) && $row->{centile_param} ne '0' && defined($row->{timeperiod_id}) && $row->{timeperiod_id} ne '0'){ - push @{$centileParams}, { centile_param => $row->{centile_param}, timeperiod_id => $row->{timeperiod_id} }; - } - } - - return $centileParams; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/ETLProperties.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/ETLProperties.pm deleted file mode 100644 index b196b8dd6e..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/ETLProperties.pm +++ /dev/null @@ -1,119 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centreon::ETLProperties; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - - $self->{logger} = shift; - $self->{centreon} = shift; - if (@_) { - $self->{centstorage} = shift; - } - bless $self, $class; - return $self; -} - -# returns two references to two hash tables => hosts indexed by id and hosts indexed by name -sub getProperties { - my $self = shift; - - my $activated = 1; - if (@_) { - $activated = 0; - } - my (%etlProperties, %dataRetention); - - my $query = "SELECT `opt_key`, `opt_value` FROM `mod_bi_options` WHERE `opt_key` like 'etl.%'"; - my $sth = $self->{centreon}->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - if ($row->{opt_key} =~ /etl.retention.(.*)/) { - $dataRetention{$1} = $row->{opt_value}; - } elsif ($row->{opt_key} =~ /etl.list.(.*)/) { - my @tab = split (/,/, $row->{opt_value}); - my %hashtab = (); - foreach(@tab) { - $hashtab{$_} = 1; - } - $etlProperties{$1} = \%hashtab; - } elsif ($row->{opt_key} =~ /etl.(.*)/) { - $etlProperties{$1} = $row->{opt_value}; - } - } - if (defined($etlProperties{'capacity.exclude.metrics'})) { - $etlProperties{'capacity.exclude.metrics'} =~ s/^/\'/; - $etlProperties{'capacity.exclude.metrics'} =~ s/$/\'/; - $etlProperties{'capacity.exclude.metrics'} =~ s/,/\',\'/; - } - - return (\%etlProperties, \%dataRetention); -} - -# returns the max retention period defined by type of statistics, monthly stats are excluded -sub getMaxRetentionPeriodFor { - my $self = shift; - my $logger = $self->{'logger'}; - - my $type = shift; - my $query = "SELECT date_format(NOW(), '%Y-%m-%d') as period_end,"; - $query .= " date_format(DATE_ADD(NOW(), INTERVAL MAX(CAST(`opt_value` as SIGNED INTEGER))*-1 DAY), '%Y-%m-%d') as period_start"; - $query .= " FROM `mod_bi_options` "; - $query .= " WHERE `opt_key` IN ('etl.retention.".$type.".hourly','etl.retention.".$type.".daily', 'etl.retention.".$type.".raw')"; - my $sth = $self->{centreon}->query({ query => $query }); - - if (my $row = $sth->fetchrow_hashref()) { - return ($row->{period_start}, $row->{period_end}); - } - - die 'Cannot get max perfdata retention period. Verify your data retention options'; -} - -# Returns a start and a end date for each retention period -sub getRetentionPeriods { - my $self = shift; - my $logger = $self->{'logger'}; - - my $query = "SELECT date_format(NOW(), '%Y-%m-%d') as period_end,"; - $query .= " date_format(DATE_ADD(NOW(), INTERVAL (`opt_value`)*-1 DAY), '%Y-%m-%d') as period_start,"; - $query .= " opt_key "; - $query .= " FROM `mod_bi_options` "; - $query .= " WHERE `opt_key` like ('etl.retention.%')"; - my $sth = $self->{centreon}->query({ query => $query }); - my %periods = (); - while (my $row = $sth->fetchrow_hashref()) { - $row->{'opt_key'} =~ s/etl.retention.//; - $periods{$row->{'opt_key'}} = { start => $row->{period_start}, end => $row->{period_end}} ; - } - if (!scalar(keys %periods)){ - $logger->writeLog("FATAL", "Cannot retention periods information. Verify your data retention options"); - } - return (\%periods); -} -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Host.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Host.pm deleted file mode 100644 index 6211e306f2..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Host.pm +++ /dev/null @@ -1,381 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::mbi::libs::centreon::Host; - -use strict; -use warnings; -use Data::Dumper; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{logger} = shift; - $self->{centreon} = shift; - $self->{etlProperties} = undef; - - if (@_) { - $self->{centstorage} = shift; - } - bless $self, $class; - return $self; -} - -#Set the etl properties as a variable of the class -sub setEtlProperties{ - my $self = shift; - $self->{etlProperties} = shift; -} - -# returns two references to two hash tables => hosts indexed by id and hosts indexed by name -sub getAllHosts { - my $self = shift; - my $centreon = $self->{centreon}; - my $activated = 1; - if (@_) { - $activated = 0; - } - my (%host_ids, %host_names); - - my $query = "SELECT `host_id`, `host_name`" . - " FROM `host`" . - " WHERE `host_register`='1'"; - if ($activated == 1) { - $query .= " AND `host_activate` ='1'"; - } - my $sth = $centreon->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - $host_ids{ $row->{host_name} } = $row->{host_id}; - $host_names{ $row->{host_id} } = $row->{host_name}; - } - return (\%host_ids, \%host_names); -} - -# Get all hosts, keys are IDs -sub getAllHostsByID { - my $self = shift; - my ($host_ids, $host_names) = $self->getAllHosts(); - return ($host_ids); -} - -# Get all hosts, keys are names -sub getAllHostsByName { - my $self = shift; - my ($host_ids, $host_names) = $self->getAllHosts(); - return ($host_names); -} - -sub loadAllCategories { - my $self = shift; - - $self->{hc} = {}; - $self->{host_hc_relations} = {}; - my $query = "SELECT hc.hc_id as category_id, hc.hc_name as category_name, host_host_id - FROM hostcategories hc, hostcategories_relation hr - WHERE hc.hc_activate = '1' AND hc.hc_id = hr.hostcategories_hc_id"; - my $sth = $self->{centreon}->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - $self->{hc}->{ $row->{category_id} } = $row->{category_name} if (!defined($self->{hc}->{ $row - ->{category_id} })); - $self->{host_hc_relations}->{ $row->{host_host_id} } = [] if (!defined($self->{host_hc_relations}->{ $row - ->{host_host_id} })); - push @{$self->{host_hc_relations}->{ $row->{host_host_id} }}, $row->{category_id}; - } -} - -sub loadAllHosts { - my $self = shift; - - $self->{hosts} = {}; - $self->{host_htpl_relations} = {}; - my $query = "SELECT h.host_id, h.host_name, host_tpl_id - FROM host h, host_template_relation htr - WHERE h.host_activate = '1' AND h.host_id = htr.host_host_id"; - my $sth = $self->{centreon}->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - $self->{hosts}->{ $row->{host_id} } = $row->{host_name} if (!defined($self->{hosts}->{ $row - ->{host_id} })); - $self->{host_htpl_relations}->{ $row->{host_id} } = [] if (!defined($self->{host_htpl_relations}->{ $row - ->{host_id} })); - push @{$self->{host_htpl_relations}->{ $row->{host_id} }}, $row->{host_tpl_id}; - } -} - -# returns host groups linked to hosts -# all hosts will be stored in a hash table -# each key of the hash table is a host id -# each key is linked to a table containing entries like : "hostgroup_id;hostgroup_name" -sub getHostGroups { - my $self = shift; - my $centreon = $self->{"centreon"}; - my $activated = 1; - my $etlProperties = $self->{'etlProperties'}; - if (@_) { - $activated = 0; - } - my %result = (); - - my $query = "SELECT `host_id`, `host_name`, `hg_id`, `hg_name`" . - " FROM `host`, `hostgroup_relation`, `hostgroup`" . - " WHERE `host_register`='1'" . - " AND `hostgroup_hg_id` = `hg_id`" . - " AND `host_id`= `host_host_id`"; - if ($activated == 1) { - $query .= " AND `host_activate` ='1'"; - } - if (!defined($etlProperties->{'dimension.all.hostgroups'}) && $etlProperties->{'dimension.hostgroups'} ne '') { - $query .= " AND `hg_id` IN (" . $etlProperties->{'dimension.hostgroups'} . ")"; - } - my $sth = $centreon->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - my $new_entry = $row->{"hg_id"} . ";" . $row->{"hg_name"}; - if (defined($result{$row->{"host_id"}})) { - my $tab_ref = $result{$row->{"host_id"}}; - my @tab = @$tab_ref; - my $exists = 0; - foreach (@tab) { - if ($_ eq $new_entry) { - $exists = 1; - last; - } - } - if (!$exists) { - push @tab, $new_entry; - } - $result{$row->{"host_id"}} = \@tab; - } else { - my @tab = ($new_entry); - $result{$row->{"host_id"}} = \@tab; - } - } - $sth->finish(); - return (\%result); -} - -#Fill a class Hash table that contains the relation between host_id and table[hc_id,hc_name] -sub getHostCategoriesWithTemplate { - my $self = shift; - my $centreon = $self->{"centreon"}; - my $activated = 1; - - #Hash : each key of the hash table is a host id - #each key is linked to a table containing entries like : "hc_id,hc_name" - my $hostCategoriesWithTemplate = $self->{'hostCategoriesWithTemplates'}; - if (@_) { - $activated = 0; - } - - my $query = "SELECT `host_id` FROM `host` WHERE `host_activate` ='1' AND `host_register` ='1'"; - - my $sth = $centreon->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - my @tab = (); - my $host_id = $row->{"host_id"}; - $self->getRecursiveCategoriesForOneHost($host_id, \@tab); - $self->getDirectLinkedCategories($host_id, \@tab); - $hostCategoriesWithTemplate->{$row->{"host_id"}} = [@tab]; - undef @tab; - } - $self->{'hostCategoriesWithTemplates'} = $hostCategoriesWithTemplate; - $sth->finish(); -} - -#Get the link between host and categories using direct link hc <> host -sub getDirectLinkedCategories { - my $self = shift; - my $host_id = shift; - my $ref_hostCat = shift; - my $centreon = $self->{"centreon"}; - my $etlProperties = $self->{"etlProperties"}; - my @tab = (); - - my $query = "SELECT `host_id`, `host_name`, `hc_id`, `hc_name`" . - " FROM `host`, `hostcategories_relation`, `hostcategories`" . - " WHERE `host_register`='1'" . - " AND `hostcategories_hc_id` = `hc_id`" . - " AND `host_id`= `host_host_id`" . - " AND `host_id`= " . $host_id . " " . - " AND `host_activate` ='1' AND hostcategories.hc_activate = '1' "; - - if (!defined($etlProperties->{'dimension.all.hostcategories'}) && $etlProperties->{'dimension.hostcategories'} - ne '') { - $query .= " AND `hc_id` IN (" . $etlProperties->{'dimension.hostcategories'} . ")"; - } - - my $sth = $centreon->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - my $new_entry = $row->{"hc_id"} . ";" . $row->{"hc_name"}; - if (!scalar(@$ref_hostCat)) { - @$ref_hostCat = ($new_entry); - } else { - @tab = @$ref_hostCat; - my $exists = 0; - foreach (@$ref_hostCat) { - if ($_ eq $new_entry) { - $exists = 1; - last; - } - } - if (!$exists) { - push @$ref_hostCat, $new_entry; - } - } - } - $sth->finish(); -} - -sub GetHostTemplateAndCategoryForOneHost { - my $self = shift; - my $host_id = shift; - - my $query = << "EOQ"; -SELECT - hhtemplates.host_id, - hhtemplates.host_name, - hhtemplates.template_id, - hhtemplates.template_name, - categories.hc_id as category_id, - categories.hc_activate as hc_activate, - categories.hc_name as category_name -FROM ( - SELECT - hst.host_id, - hst.host_name, - htpls.host_id as template_id, - htpls.host_name as template_name - FROM - host hst - JOIN - host_template_relation hst_htpl_rel - ON - hst.host_id = hst_htpl_rel.host_host_id - JOIN - host htpls - ON - hst_htpl_rel.host_tpl_id = htpls.host_id - WHERE - hst.host_activate ='1' - AND hst.host_id = $host_id -) hhtemplates -LEFT JOIN - hostcategories_relation hcs_rel - ON - hcs_rel.host_host_id = hhtemplates.template_id -LEFT JOIN - hostcategories categories - ON - hcs_rel.hostcategories_hc_id = categories.hc_id -EOQ - - return $self->{centreon}->query({ query => $query }); - -} - -#Get the link between host and categories using templates -sub getRecursiveCategoriesForOneHost { - my $self = shift; - my $host_id = shift; - my $ref_hostCat = shift; - my $etlProperties = $self->{"etlProperties"}; - - #Get all categories linked to the templates associated with the host or just template associated with host to be able to call the method recursively - my $sth = $self->GetHostTemplateAndCategoryForOneHost($host_id); - - my @hostCategoriesAllowed = split /,/, $etlProperties->{'dimension.hostcategories'}; - while (my $row = $sth->fetchrow_hashref()) { - my $new_entry; - my @tab = (); - my $categoryId = $row->{"category_id"}; - my $categoryName = $row->{"category_name"}; - my $categoryActivate = $row->{"hc_activate"}; - - #If current category is in allowed categories in ETL configuration - #add it to the categories link to the host, - #Then check for templates categories recursively - if (defined($categoryId) && defined($categoryName) && $categoryActivate == '1') { - if ((grep {$_ eq $categoryId} @hostCategoriesAllowed) - || (defined($etlProperties->{'dimension.all.hostcategories'}) - && $etlProperties->{'dimension.all.hostcategories'} ne '')) { - $new_entry = $categoryId . ";" . $categoryName; - #If no hostcat has been found for the host, create the line - if (!scalar(@$ref_hostCat)) { - @$ref_hostCat = ($new_entry); - } else { - #If the tab is not empty, check wether the combination already exists in the tab - @tab = @$ref_hostCat; - my $exists = 0; - foreach (@$ref_hostCat) { - if ($_ eq $new_entry) { - $exists = 1; - last; - } - } - #If the host category did not exist, add it to the table @$ref_hostCat - if (!$exists) { - push @$ref_hostCat, $new_entry; - } - } - } - } - $self->getRecursiveCategoriesForOneHost($row->{"template_id"}, $ref_hostCat); - } - $sth->finish(); -} - -sub getHostGroupAndCategories { - my $self = shift; - - my $hostGroups = $self->getHostGroups(); - - $self->loadAllCategories(); - $self->loadAllHosts(); - $self->getHostCategoriesWithTemplate(); - my $hostCategories = $self->{"hostCategoriesWithTemplates"}; - my @results; - - while (my ($hostId, $groups) = each(%$hostGroups)) { - my $categories_ref = $hostCategories->{$hostId}; - my @categoriesTab = (); - if (defined($categories_ref) && scalar(@$categories_ref)) { - @categoriesTab = @$categories_ref; - } - my $hostName = $self->{hosts}->{$hostId}; - foreach (@$groups) { - my $group = $_; - if (scalar(@categoriesTab)) { - foreach (@categoriesTab) { - push @results, $hostId . ';' . $hostName . ';' . $group . ';' . $_; - } - } else { - #If there is no category - push @results, $hostId . ";" . $hostName . ";" . $group . ";0;NoCategory"; - } - } - } - - return \@results; -} - -1; \ No newline at end of file diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/HostCategory.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/HostCategory.pm deleted file mode 100644 index 8751350f76..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/HostCategory.pm +++ /dev/null @@ -1,70 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centreon::HostCategory; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centreon"} = shift; - $self->{'etlProperties'} = undef; - if (@_) { - $self->{"centstorage"} = shift; - } - bless $self, $class; - return $self; -} - -#Set the etl properties as a variable of the class -sub setEtlProperties{ - my $self = shift; - $self->{'etlProperties'} = shift; -} - - -sub getAllEntries { - my $self = shift; - my $db = $self->{"centreon"}; - my $etlProperties = $self->{'etlProperties'}; - - my $query = "SELECT `hc_id`, `hc_name`"; - $query .= " FROM `hostcategories`"; - if(!defined($etlProperties->{'dimension.all.hostcategories'}) && $etlProperties->{'dimension.hostcategories'} ne ''){ - $query .= " WHERE `hc_id` IN (".$etlProperties->{'dimension.hostcategories'}.")"; - } - my $sth = $db->query({ query => $query }); - my @entries = (); - while (my $row = $sth->fetchrow_hashref()) { - push @entries, $row->{"hc_id"}.";".$row->{"hc_name"}; - } - $sth->finish(); - return (\@entries); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/HostGroup.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/HostGroup.pm deleted file mode 100644 index e11579f363..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/HostGroup.pm +++ /dev/null @@ -1,136 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centreon::HostGroup; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centreon"} = shift; - $self->{'etlProperties'} = undef; - if (@_) { - $self->{"centstorage"} = shift; - } - bless $self, $class; - return $self; -} - -#Set the etl properties as a variable of the class -sub setEtlProperties{ - my $self = shift; - $self->{'etlProperties'} = shift; -} - -# returns in a table all host/service of a group of host -sub getHostgroupServices { - my $self = shift; - my $db = $self->{"centreon"}; - my $etlProperties = $self->{'etlProperties'}; - my $hgId = 0; - if (@_) { - $hgId = shift; - } - my %result = (); - my $query = "SELECT h.`host_id`, h.`host_name`, s.`service_id`, s.`service_description`"; - $query .= " FROM `hostgroup` hg, `host_service_relation` hsr, `service` s, `hostgroup_relation` hgr, `host` h"; - $query .= " WHERE hg.`hg_id` = ".$hgId; - $query .= " AND hg.`hg_id` = hsr.`hostgroup_hg_id`"; - $query .= " AND hsr.`service_service_id` = s.`service_id`"; - $query .= " AND s.`service_activate` = '1'"; - $query .= " AND s.`service_register` = '1'"; - $query .= " AND hg.hg_id = hgr.`hostgroup_hg_id`"; - $query .= " AND hgr.`host_host_id` = h.`host_id`"; - $query .= " AND h.`host_activate` = '1'"; - $query .= " AND h.`host_register` = '1'"; - if(!defined($etlProperties->{'dimension.all.hostgroups'}) && $etlProperties->{'dimension.hostgroups'} ne ''){ - $query .= " AND hg.`hg_id` IN (".$etlProperties->{'dimension.hostgroups'}.")"; - } - my $sth = $db->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - $result{$row->{"host_id"}.";".$row->{"service_id"}} = 1; - } - $sth->finish(); - return (\%result); -} - - -# returns in a table all host/service of a group of host -sub getHostgroupHostServices { - my $self = shift; - my $db = $self->{"centreon"}; - my %etlProperties = $self->{'etlProperties'}; - - my $hgId = 0; - if (@_) { - $hgId = shift; - } - my %result = (); - my $query = "SELECT h.`host_id`, s.`service_id`"; - $query .= " FROM `host` h, `hostgroup` hg, `hostgroup_relation` hgr, `host_service_relation` hsr, `service` s"; - $query .= " WHERE hg.`hg_id` = ".$hgId; - $query .= " AND hgr.`hostgroup_hg_id` = hg.`hg_id`"; - $query .= " AND hgr.`host_host_id` = h.`host_id`"; - $query .= " AND h.`host_activate` = '1'"; - $query .= " AND h.`host_register` = '1'"; - $query .= " AND h.`host_id` = hsr.`host_host_id`"; - $query .= " AND hsr.`service_service_id` = s.`service_id`"; - $query .= " AND s.`service_activate` = '1'"; - $query .= " AND s.`service_register` = '1'"; - if(!defined($etlProperties{'etl.dimension.all.hostgroups'}) && $etlProperties{'etl.dimension.hostgroups'} ne ''){ - $query .= " AND hg.`hg_id` IN (".$etlProperties{'etl.dimension.hostgroups'}.")"; - } - my $sth = $db->query({ query => $query }); - while (my $row = $sth->fetchrow_hashref()) { - $result{$row->{"host_id"}.";".$row->{"service_id"}} = 1; - } - %result = (%result, $self->getHostgroupServices($hgId)); - return (\%result); -} - -sub getAllEntries { - my $self = shift; - my $db = $self->{"centreon"}; - my $etlProperties = $self->{'etlProperties'}; - - my $query = "SELECT `hg_id`, `hg_name`"; - $query .= " FROM `hostgroup`"; - if(!defined($etlProperties->{'dimension.all.hostgroups'}) && $etlProperties->{'dimension.hostgroups'} ne ''){ - $query .= " WHERE `hg_id` IN (".$etlProperties->{'dimension.hostgroups'}.")"; - } - my $sth = $db->query({ query => $query }); - my @entries = (); - while (my $row = $sth->fetchrow_hashref()) { - push @entries, $row->{"hg_id"}.";".$row->{"hg_name"}; - } - $sth->finish(); - return (\@entries); -} - - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Service.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Service.pm deleted file mode 100644 index fc2f313814..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Service.pm +++ /dev/null @@ -1,213 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centreon::Service; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centreon"} = shift; - $self->{'etlProperties'} = undef; - - if (@_) { - $self->{"centstorage"} = shift; - } - bless $self, $class; - return $self; -} - -sub setEtlProperties{ - my $self = shift; - $self->{'etlProperties'} = shift; -} - -# returns two references to two hash tables => services indexed by id and services indexed by name -sub getServicesWithHostAndCategory { - my $self = shift; - my $centreon = $self->{"centreon"}; - my $serviceId = ""; - my $hosts = shift; - if (@_) { - $serviceId = shift; - } - my $templateCategories = $self->getServicesTemplatesCategories; - - my (@results); - # getting services linked to hosts - my $query = "SELECT service_description, service_id, host_id, service_template_model_stm_id as tpl". - " FROM host, service, host_service_relation". - " WHERE host_id = host_host_id and service_service_id = service_id". - " AND service_register = '1'". - " AND host_activate = '1'". - " AND service_activate = '1'"; - - my $sth = $centreon->query({ query => $query }); - while(my $row = $sth->fetchrow_hashref()) { - # getting all host entries - my $serviceHostTable = $hosts->{$row->{"host_id"}}; - # getting all Categories entries - my @categoriesTable = (); - # getting categories directly linked to service - my $categories = $self->getServiceCategories($row->{"service_id"}); - while(my ($sc_id, $sc_name) = each(%$categories)) { - push @categoriesTable, $sc_id.";".$sc_name; - } - # getting categories linked to template - if (defined($row->{"tpl"}) && defined($templateCategories->{$row->{"tpl"}})) { - my $tplCategories = $templateCategories->{$row->{"tpl"}}; - while(my ($sc_id, $sc_name) = each(%$tplCategories)) { - if(!defined($categories->{$sc_id})) { - push @categoriesTable, $sc_id.";".$sc_name; - } - } - } - if (!scalar(@categoriesTable)) { - #ToDo push @categoriesTable, "0;NULL"; - } - if (defined($serviceHostTable)) { - foreach(@$serviceHostTable) { - my $hostInfos = $_; - foreach(@categoriesTable) { - push @results, $row->{"service_id"}.";".$row->{"service_description"}.";".$_.";".$hostInfos; - } - } - } - } - #getting services linked to hostgroup - $query = "SELECT DISTINCT service_description, service_id, host_id, service_template_model_stm_id as tpl". - " FROM host, service, host_service_relation hr, hostgroup_relation hgr". - " WHERE hr.hostgroup_hg_id is not null". - " AND hr.service_service_id = service_id". - " AND hr.hostgroup_hg_id = hgr.hostgroup_hg_id". - " AND hgr.host_host_id = host_id". - " AND service_register = '1'". - " AND host_activate = '1'". - " AND service_activate = '1'"; - - $sth = $centreon->query({ query => $query }); - while(my $row = $sth->fetchrow_hashref()) { - # getting all host entries - my $serviceHostTable = $hosts->{$row->{"host_id"}}; - # getting all Categories entries - my @categoriesTable = (); - # getting categories directly linked to service - my $categories = $self->getServiceCategories($row->{"service_id"}); - while(my ($sc_id, $sc_name) = each(%$categories)) { - push @categoriesTable, $sc_id.";".$sc_name; - } - # getting categories linked to template - if (defined($row->{"tpl"}) && defined($templateCategories->{$row->{"tpl"}})) { - my $tplCategories = $templateCategories->{$row->{"tpl"}}; - while(my ($sc_id, $sc_name) = each(%$tplCategories)) { - if(!defined($categories->{$sc_id})) { - push @categoriesTable, $sc_id.";".$sc_name; - } - } - } - if (!scalar(@categoriesTable)) { - push @categoriesTable, "0;NULL"; - } - if (defined($serviceHostTable)) { - foreach(@$serviceHostTable) { - my $hostInfos = $_; - foreach(@categoriesTable) { - push @results, $row->{"service_id"}.";".$row->{"service_description"}.";".$_.";".$hostInfos; - } - } - } - } - $sth->finish(); - return (\@results); -} - -sub getServicesTemplatesCategories { - my $self = shift; - my $db = $self->{"centreon"}; - my %results = (); - - my $query = "SELECT service_id, service_description, service_template_model_stm_id FROM service WHERE service_register = '0'"; - my $sth = $db->query({ query => $query }); - while(my $row = $sth->fetchrow_hashref()) { - my $currentTemplate = $row->{"service_id"}; - my $categories = $self->getServiceCategories($row->{"service_id"}); - my $parentId = $row->{"service_template_model_stm_id"}; - if (defined($parentId)) { - my $hasParent = 1; - # getting all parent templates category relations - while ($hasParent) { - my $parentQuery = "SELECT service_id, service_template_model_stm_id "; - $parentQuery .= "FROM service "; - $parentQuery .= "WHERE service_register = '0' and service_id=".$parentId; - my $sthparentQuery = $db->query({ query => $parentQuery }); - if(my $parentQueryRow = $sthparentQuery->fetchrow_hashref()) { - my $newCategories = $self->getServiceCategories($parentQueryRow->{"service_id"}); - while(my ($sc_id, $sc_name) = each(%$newCategories)) { - if (!defined($categories->{$sc_id})) { - $categories->{$sc_id} = $sc_name; - } - } - if (!defined($parentQueryRow->{'service_template_model_stm_id'})) { - $hasParent = 0; - last; - } - $parentId = $parentQueryRow->{'service_template_model_stm_id'}; - $sthparentQuery->finish(); - }else { - $hasParent = 0; - } - } - } - $results{$currentTemplate} = $categories; - } - $sth->finish(); - return \%results; -} - -sub getServiceCategories { - my $self = shift; - my $db = $self->{"centreon"}; - my $id = shift; - my %results = (); - my $etlProperties = $self->{'etlProperties'}; - - my $query = "SELECT sc.sc_id, sc_name "; - $query .= " FROM service_categories sc, service_categories_relation scr"; - $query .= " WHERE service_service_id = ".$id; - $query .= " AND sc.sc_id = scr.sc_id"; - if(!defined($etlProperties->{'dimension.all.servicecategories'}) && $etlProperties->{'dimension.servicecategories'} ne ''){ - $query .= " AND sc.sc_id IN (".$etlProperties->{'dimension.servicecategories'}.")"; - } - my $sth = $db->query({ query => $query }); - while(my $row = $sth->fetchrow_hashref()) { - $results{$row->{"sc_id"}} = $row->{"sc_name"}; - } - return (\%results); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/ServiceCategory.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/ServiceCategory.pm deleted file mode 100644 index 637ec4fb08..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/ServiceCategory.pm +++ /dev/null @@ -1,96 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centreon::ServiceCategory; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centreon"} = shift; - $self->{'etlProperties'} = undef; - if (@_) { - $self->{"centstorage"} = shift; - } - bless $self, $class; - return $self; -} - -#Set the etl properties as a variable of the class -sub setEtlProperties{ - my $self = shift; - $self->{'etlProperties'} = shift; -} - -# returns two references to two hash tables => services indexed by id and services indexed by name -sub getCategory { - my $self = shift; - my $db = $self->{"centreon"}; - my $etlProperties = $self->{'etlProperties'}; - my $scName = ""; - if (@_) { - $scName = shift; - } - - my $result = ""; - # getting services linked to hosts - my $query = "SELECT sc_id from service_categories WHERE sc_name='".$scName."'"; - if(!defined($etlProperties->{'dimension.all.servicecategories'}) && $etlProperties->{'dimension.servicecategories'} ne ''){ - $query .= " WHERE `sc_id` IN (".$etlProperties->{'dimension.servicecategories'}.")"; - } - my $sth = $db->query({ query => $query }); - if(my $row = $sth->fetchrow_hashref()) { - $result = $row->{"sc_id"}; - }else { - ($self->{"logger"})->writeLog("error", "Cannot find service category '" . $scName . "' in database"); - } - $sth->finish(); - - return ($result); -} - -sub getAllEntries { - my $self = shift; - my $db = $self->{"centreon"}; - my $etlProperties = $self->{'etlProperties'}; - - my $query = "SELECT `sc_id`, `sc_name`"; - $query .= " FROM `service_categories`"; - if(!defined($etlProperties->{'dimension.all.servicecategories'}) && $etlProperties->{'dimension.servicecategories'} ne ''){ - $query .= " WHERE `sc_id` IN (".$etlProperties->{'dimension.servicecategories'}.")"; - } - my $sth = $db->query({ query => $query }); - my @entries = (); - while (my $row = $sth->fetchrow_hashref()) { - push @entries, $row->{"sc_id"}.";".$row->{"sc_name"}; - } - $sth->finish(); - return (\@entries); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Timeperiod.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Timeperiod.pm deleted file mode 100644 index 2dab052666..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centreon/Timeperiod.pm +++ /dev/null @@ -1,247 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; -use Time::Local; -use gorgone::modules::centreon::mbi::libs::Utils; - -package gorgone::modules::centreon::mbi::libs::centreon::Timeperiod; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centreon"} = shift; - if (@_) { - $self->{"centstorage"} = shift; - } - bless $self, $class; - return $self; -} - -sub getTimeRangesForDay { - my $self = shift; - my $db = $self->{"centreon"}; - my ($weekDay, $name, $unixtime) = @_; - my @results = (); - - my @weekDays = ("sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"); - my $query = "SELECT tp_" . $weekDay; - $query .= " FROM timeperiod"; - $query .= " WHERE tp_name = '" . $name . "'"; - my $sth = $db->query({ query => $query }); - if (my $row = $sth->fetchrow_hashref()) { - if (defined($row->{'tp_'.$weekDay})) { - my @ranges = split(",", $row->{'tp_' . $weekDay}); - foreach (@ranges) { - my ($start, $end) = split("-", $_); - my ($start_hour, $start_min) = split(':', $start); - my ($end_hour, $end_min) = split(':', $end); - my @range = ($unixtime+ $start_hour * 60 * 60 + $start_min * 60, $unixtime + $end_hour * 60 * 60 + $end_min * 60); - $results[scalar(@results)] = \@range; - } - } - } - - return (\@results); -} - -sub getTimeRangesForDayByDateTime { - my $self = shift; - my $db = $self->{"centreon"}; - my ($name, $dateTime, $weekDay) = @_; - my @results = (); - - my $query = "SELECT tp_".$weekDay; - $query .= " FROM timeperiod"; - $query .= " WHERE tp_name='".$name."'"; - my $sth = $db->query({ query => $query }); - if(my $row = $sth->fetchrow_hashref()) { - if (defined($row->{'tp_'.$weekDay})) { - my @ranges = split(",", $row->{'tp_'.$weekDay}); - foreach(@ranges) { - my ($start, $end) = split("-", $_); - my $range_end = "'".$dateTime." ".$end.":00'"; - if ($end eq '24:00') { - $range_end = "DATE_ADD('".$dateTime."', INTERVAL 1 DAY)"; - } - my @range = ("'".$dateTime." ".$start.":00'", $range_end); - $results[scalar(@results)] = \@range; - } - } - } - $sth->finish(); - - return (\@results); -} - -sub getRangeTable { - my ($self, $rangeStr) = @_; - if (!defined($rangeStr)) { - $rangeStr = ""; - } - my @ranges = split(",", $rangeStr); - - my @results = (); - foreach(@ranges) { - my ($start, $end) = split("-", $_); - my ($start_hour, $start_min) = split(":", $start); - my ($end_hour, $end_min) = split(":", $end); - push @results, [$start_hour * 60 * 60 + $start_min * 60, $end_hour * 60 * 60 + $end_min * 60]; - } - return [@results]; -} - -sub getAllRangesForTpId { - my ($self, $timeperiod_id) = @_; - my $db = $self->{"centreon"}; - my $logger = $self->{"logger"}; - my $query = "SELECT tp_monday, tp_tuesday, tp_wednesday, tp_thursday, tp_friday, tp_saturday, tp_sunday"; - $query .= " FROM timeperiod"; - $query .= " WHERE tp_id='".$timeperiod_id."'"; - my $sth = $db->query({ query => $query }); - - my @results = (); - if(my $row = $sth->fetchrow_hashref()) { - $results[0] = $self->getRangeTable($row->{'tp_sunday'}); - $results[1] = $self->getRangeTable($row->{'tp_monday'}); - $results[2] = $self->getRangeTable($row->{'tp_tuesday'}); - $results[3] = $self->getRangeTable($row->{'tp_wednesday'}); - $results[4] = $self->getRangeTable($row->{'tp_thursday'}); - $results[5] = $self->getRangeTable($row->{'tp_friday'}); - $results[6] = $self->getRangeTable($row->{'tp_saturday'}); - }else { - $logger->writeLog("ERROR", "Cannot find time period with id '".$timeperiod_id."' in Centreon Database"); - } - return [@results]; -} - -sub getTimeRangesForPeriod { - my $self = shift; - my ($timeperiodId, $start, $end) = @_; - my @results = (); - my @weekDays = ("sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"); - my $days = gorgone::modules::centreon::mbi::libs::Utils->getRebuildPeriods($start, $end); - my $weekRanges = $self->getAllRangesForTpId($timeperiodId); - foreach (@$days) { - my $dayStart = $_->{'start'}; - my $dayRanges = $weekRanges->[(localtime($dayStart))[6]]; - foreach(@$dayRanges) { - push @results, [$dayStart+$_->[0], $dayStart+$_->[1]]; - } - } - return [@results]; -} - -sub getTimeRangesForPeriodAndTpList { - my $self = shift; - my ($timeperiodList, $start, $end) = @_; - - my %rangesByTP = (); - while (my ($key, $value) = each %$timeperiodList) { - $rangesByTP{$key} = $self->getTimeRangesForPeriod($key, $start, $end); - } - return \%rangesByTP; -} - -sub getId { - my $self = shift; - my $db = $self->{"centreon"}; - my $name = shift; - - my $query = "SELECT tp_id"; - $query .= " FROM timeperiod"; - $query .= " WHERE tp_name = '".$name."'"; - my $sth = $db->query({ query => $query }); - my $result = -1; - if(my $row = $sth->fetchrow_hashref()) { - $result = $row->{'tp_id'}; - } - return $result; -} - -sub getPeriodsLike { - my $self = shift; - my $db = $self->{"centreon"}; - my $name = shift; - - my $query = "SELECT tp_id, tp_name"; - $query .= " FROM timeperiod"; - $query .= " WHERE tp_name like '".$name."%'"; - my $sth = $db->query({ query => $query }); - my %result = (); - while (my $row = $sth->fetchrow_hashref()) { - $result{$row->{'tp_id'}} = $row->{'tp_name'}; - } - return \%result; -} - -sub getPeriods { - my $self = shift; - my $db = $self->{"centreon"}; - my $logger = $self->{'logger'}; - my $ids = shift; - - my $idStr = ""; - - foreach my $key (keys %$ids) { - if ($idStr eq "") { - $idStr .= $key; - }else { - $idStr .= ",".$key; - } - } - if ($idStr eq "") { - $logger->writeLog("ERROR", "Select a timeperiod in the ETL configuration menu"); - } - my $query = "SELECT tp_id, tp_name"; - $query .= " FROM timeperiod"; - $query .= " WHERE tp_id IN (".$idStr.")"; - my $sth = $db->query({ query => $query }); - my %result = (); - while (my $row = $sth->fetchrow_hashref()) { - $result{$row->{'tp_id'}} = $row->{'tp_name'}; - } - return \%result; -} - -sub getCentilePeriods { - my $self = shift; - my $db = $self->{"centreon"}; - my $logger = $self->{'logger'}; - - my $query = "SELECT tp_id, tp_name"; - $query .= " FROM timeperiod"; - $query .= " WHERE tp_id IN (select timeperiod_id from mod_bi_options_centiles)"; - my $sth = $db->query({ query => $query }); - my %result = (); - while (my $row = $sth->fetchrow_hashref()) { - $result{$row->{'tp_id'}} = $row->{'tp_name'}; - } - return \%result; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/HostStateEvents.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/HostStateEvents.pm deleted file mode 100644 index 55adc8324b..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/HostStateEvents.pm +++ /dev/null @@ -1,183 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centstorage::HostStateEvents; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - $self->{"biHostStateEventsObj"} = shift; - $self->{"timePeriodObj"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - $self->{"name"} = "hoststateevents"; - $self->{"timeColumn"} = "end_time"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} -sub agreggateEventsByTimePeriod { - my ($self, $timeperiodList, $start, $end, $liveServiceByTpId, $mode) = @_; - my $logger = $self->{"logger"}; - my $nbEvents; - my $db = $self->{"centstorage"}; - - my $rangesByTP = ($self->{"timePeriodObj"})->getTimeRangesForPeriodAndTpList($timeperiodList, $start, $end); - my $query = " SELECT e.host_id, start_time, end_time, ack_time, state, last_update"; - $query .= " FROM `hoststateevents` e"; - $query .= " RIGHT JOIN (select host_id from mod_bi_tmp_today_hosts group by host_id) t2"; - $query .= " ON e.host_id = t2.host_id"; - $query .= " WHERE start_time < ".$end.""; - $query .= " AND end_time > ".$start.""; - $query .= " AND in_downtime = 0 "; - $query .= " ORDER BY start_time "; - - - my $hostEventObjects = $self->{"biHostStateEventsObj"}; - my $sth = $db->query({ query => $query }); - $hostEventObjects->createTempBIEventsTable(); - $hostEventObjects->prepareTempQuery(); - - while (my $row = $sth->fetchrow_hashref()) { - if (!defined($row->{'end_time'})) { - $row->{'end_time'} = $end; - } - while (my ($timeperiodID, $timeRanges) = each %$rangesByTP) { - my @tab = (); - $tab[0] = $row->{'host_id'}; - $tab[1] = $liveServiceByTpId->{$timeperiodID}; - $tab[2] = $row->{'state'}; - if ($mode eq "daily") { - $timeRanges = ($self->{"timePeriodObj"})->getTimeRangesForPeriod($timeperiodID, $row->{'start_time'}, $row->{'end_time'}); - } - ($tab[3], $tab[4]) = $self->processIncidentForTp($timeRanges,$row->{'start_time'}, $row->{'end_time'}); - $tab[5] = $row->{'end_time'}; - $tab[6] = defined($row->{ack_time}) ? $row->{ack_time} : 0; - $tab[7] = $row->{'last_update'}; - if (defined($tab[3]) && $tab[3] != -1) { - $hostEventObjects->bindParam(\@tab); - } - - } - } - ($db->getInstance)->commit; -} - -sub processIncidentForTp { - my ($self, $timeRanges, $start, $end) = @_; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my $rangeSize = scalar(@$timeRanges); - my $duration = 0; - my $slaDuration = 0; - my $range = 0; - my $i = 0; - my $processed = 0; - my $slaStart = $start; - my $slaStartModified = 0; - - foreach(@$timeRanges) { - my $currentStart = $start; - my $currentEnd = $end; - - $range = $_; - my ($rangeStart, $rangeEnd) = ($range->[0], $range->[1]); - - if ($currentStart < $rangeEnd && $currentEnd > $rangeStart) { - $processed = 1; - if ($currentStart > $rangeStart) { - $slaStartModified = 1; - } elsif ($currentStart < $rangeStart) { - $currentStart = $rangeStart; - if (!$slaStartModified) { - $slaStart = $currentStart; - $slaStartModified = 1; - } - } - if ($currentEnd > $rangeEnd) { - $currentEnd = $rangeEnd; - } - $slaDuration += $currentEnd - $currentStart; - } - } - if (!$processed) { - return (-1, -1, -1); - } - - return ($slaStart, $slaDuration); -} - - -sub dailyPurge { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($end) = @_; - - $logger->writeLog("DEBUG", "[PURGE] [hoststateevents] purging data older than ".$end); - my $query = "DELETE FROM `hoststateevents` where end_time < UNIX_TIMESTAMP('".$end."')"; - $db->query({ query => $query }); -} - -sub getNbEvents{ - my $self = shift; - my $db = $self->{"centstorage"}; - my ($start, $end) = @_; - my $logger = $self->{"logger"}; - my $nbEvents = 0; - - my $query = "SELECT count(*) as nbEvents"; - $query .= " FROM `hoststateevents` e"; - $query .= " RIGHT JOIN (select host_id from mod_bi_tmp_today_hosts group by host_id) t2"; - $query .= " ON e.host_id = t2.host_id"; - $query .= " WHERE start_time < ".$end.""; - $query .= " AND end_time > ".$start.""; - $query .= " AND in_downtime = 0 "; - - my $sth = $db->query({ query => $query }); - - while (my $row = $sth->fetchrow_hashref()) { - $nbEvents = $row->{'nbEvents'}; - } - return $nbEvents; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/Metrics.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/Metrics.pm deleted file mode 100644 index 93f6b2df73..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/Metrics.pm +++ /dev/null @@ -1,230 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centstorage::Metrics; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{logger} = shift; - $self->{centstorage} = shift; - - $self->{metrics} = (); - $self->{name} = 'data_bin'; - $self->{timeColumn} = 'ctime'; - $self->{name_minmaxavg_tmp} = 'mod_bi_tmp_minmaxavgvalue'; - $self->{name_firstlast_tmp} = 'mod_bi_tmp_firstlastvalues'; - $self->{name_minmaxctime_tmp} = 'mod_bi_tmp_minmaxctime'; - if (@_) { - $self->{name_minmaxavg_tmp} .= $_[0]; - $self->{name_firstlast_tmp} .= $_[0]; - $self->{name_minmaxctime_tmp} .= $_[0]; - } - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub createTempTableMetricMinMaxAvgValues { - my ($self, $useMemory, $granularity) = @_; - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE IF EXISTS `" . $self->{name_minmaxavg_tmp} . "`" }); - my $createTable = " CREATE TABLE `" . $self->{name_minmaxavg_tmp} . "` ("; - $createTable .= " id_metric INT NULL,"; - $createTable .= " avg_value FLOAT NULL,"; - $createTable .= " min_value FLOAT NULL,"; - $createTable .= " max_value FLOAT NULL"; - if ($granularity eq "hour") { - $createTable .= ", valueTime DATETIME NULL"; - } - if (defined($useMemory) && $useMemory eq "true") { - $createTable .= ") ENGINE=MEMORY CHARSET=utf8 COLLATE=utf8_general_ci;"; - }else { - $createTable .= ") ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $createTable }); -} - -sub getMetricValueByHour { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my ($start, $end, $useMemory) = @_; - my $dateFormat = "%Y-%c-%e %k:00:00"; - - # Getting min, max, average - $self->createTempTableMetricMinMaxAvgValues($useMemory, "hour"); - my $query = "INSERT INTO `" . $self->{name_minmaxavg_tmp} . "` SELECT id_metric, avg(value) as avg_value, min(value) as min_value, max(value) as max_value, "; - $query .= " date_format(FROM_UNIXTIME(ctime), '".$dateFormat."') as valueTime "; - $query .= "FROM data_bin "; - $query .= "WHERE "; - $query .= "ctime >=UNIX_TIMESTAMP('".$start."') AND ctime < UNIX_TIMESTAMP('".$end."') "; - $query .= "GROUP BY id_metric, date_format(FROM_UNIXTIME(ctime), '".$dateFormat."')"; - - $db->query({ query => $query }); - $self->addIndexTempTableMetricMinMaxAvgValues("hour"); -} - -sub getMetricsValueByDay { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my ($period, $useMemory) = @_; - my $dateFormat = "%Y-%c-%e"; - - # Getting min, max, average - $self->createTempTableMetricMinMaxAvgValues($useMemory, "day"); - my $query = "INSERT INTO `" . $self->{name_minmaxavg_tmp} . "` SELECT id_metric, avg(value) as avg_value, min(value) as min_value, max(value) as max_value "; - #$query .= " date_format(FROM_UNIXTIME(ctime), '".$dateFormat."') as valueTime "; - $query .= "FROM data_bin "; - $query .= "WHERE "; - my @tabPeriod = @$period; - my ($start_date, $end_date); - my $tabSize = scalar(@tabPeriod); - for (my $count = 0; $count < $tabSize; $count++) { - my $range = $tabPeriod[$count]; - if ($count == 0) { - $start_date = $range->[0]; - } - if ($count == $tabSize - 1) { - $end_date = $range->[1]; - } - $query .= "(ctime >= UNIX_TIMESTAMP(".($range->[0]). ") AND ctime < UNIX_TIMESTAMP(".($range->[1]) .")) OR "; - } - - $query =~ s/OR $//; - $query .= "GROUP BY id_metric"; - - $db->query({ query => $query }); - $self->addIndexTempTableMetricMinMaxAvgValues("day"); - $self->getFirstAndLastValues($start_date, $end_date, $useMemory); -} - -sub createTempTableMetricDayFirstLastValues { - my ($self, $useMemory) = @_; - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE IF EXISTS `" . $self->{name_firstlast_tmp} . "`" }); - my $createTable = " CREATE TABLE `" . $self->{name_firstlast_tmp} . "` ("; - $createTable .= " `first_value` FLOAT NULL,"; - $createTable .= " `last_value` FLOAT NULL,"; - $createTable .= " id_metric INT NULL"; - if (defined($useMemory) && $useMemory eq "true") { - $createTable .= ") ENGINE=MEMORY CHARSET=utf8 COLLATE=utf8_general_ci;"; - } else { - $createTable .= ") ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $createTable }); -} - -sub addIndexTempTableMetricDayFirstLastValues { - my $self = shift; - my $db = $self->{"centstorage"}; - $db->query({ query => "ALTER TABLE " . $self->{name_firstlast_tmp} . " ADD INDEX (`id_metric`)" }); -} - -sub addIndexTempTableMetricMinMaxAvgValues { - my $self = shift; - my $granularity = shift; - my $db = $self->{"centstorage"}; - my $index = "id_metric"; - if ($granularity eq "hour") { - $index .= ", valueTime"; - } - my $query = "ALTER TABLE " . $self->{name_minmaxavg_tmp} . " ADD INDEX (" . $index . ")"; - $db->query({ query => $query }); -} - -sub createTempTableCtimeMinMaxValues { - my ($self, $useMemory) = @_; - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE IF EXISTS `" . $self->{name_minmaxctime_tmp} . "`" }); - my $createTable = " CREATE TABLE `" . $self->{name_minmaxctime_tmp} . "` ("; - $createTable .= " min_val INT NULL,"; - $createTable .= " max_val INT NULL,"; - $createTable .= " id_metric INT NULL"; - if (defined($useMemory) && $useMemory eq "true") { - $createTable .= ") ENGINE=MEMORY CHARSET=utf8 COLLATE=utf8_general_ci;"; - } else { - $createTable .= ") ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci;"; - } - $db->query({ query => $createTable }); -} - -sub dropTempTableCtimeMinMaxValues { - my $self = shift; - my $db = $self->{"centstorage"}; - $db->query({ query => "DROP TABLE `" . $self->{name_minmaxctime_tmp} . "`" }); -} - -sub getFirstAndLastValues { - my $self = shift; - my $db = $self->{"centstorage"}; - - my ($start_date, $end_date, $useMemory) = @_; - - $self->createTempTableCtimeMinMaxValues($useMemory); - my $query = "INSERT INTO `" . $self->{name_minmaxctime_tmp} . "` SELECT min(ctime) as min_val, max(ctime) as max_val, id_metric "; - $query .= " FROM `data_bin`"; - $query .= " WHERE ctime >= UNIX_TIMESTAMP(" . $start_date . ") AND ctime < UNIX_TIMESTAMP(" . $end_date . ")"; - $query .= " GROUP BY id_metric"; - $db->query({ query => $query }); - - $self->createTempTableMetricDayFirstLastValues($useMemory); - $query = "INSERT INTO " . $self->{name_firstlast_tmp} . " SELECT d.value as `first_value`, d2.value as `last_value`, d.id_metric"; - $query .= " FROM data_bin as d, data_bin as d2, " . $self->{name_minmaxctime_tmp} . " as db"; - $query .= " WHERE db.id_metric=d.id_metric AND db.min_val=d.ctime"; - $query .= " AND db.id_metric=d2.id_metric AND db.max_val=d2.ctime"; - $query .= " GROUP BY db.id_metric"; - my $sth = $db->query({ query => $query }); - $self->addIndexTempTableMetricDayFirstLastValues(); - $self->dropTempTableCtimeMinMaxValues(); -} - -sub dailyPurge { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($end) = @_; - - my $query = "DELETE FROM `data_bin` where ctime < UNIX_TIMESTAMP('" . $end . "')"; - $logger->writeLog("DEBUG", "[PURGE] [data_bin] purging data older than " . $end); - $db->query({ query => $query }); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/ServiceStateEvents.pm b/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/ServiceStateEvents.pm deleted file mode 100644 index b70130d1d1..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/mbi/libs/centstorage/ServiceStateEvents.pm +++ /dev/null @@ -1,179 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -package gorgone::modules::centreon::mbi::libs::centstorage::ServiceStateEvents; - -# Constructor -# parameters: -# $logger: instance of class CentreonLogger -# $centreon: Instance of centreonDB class for connection to Centreon database -# $centstorage: (optionnal) Instance of centreonDB class for connection to Centstorage database -sub new { - my $class = shift; - my $self = {}; - $self->{"logger"} = shift; - $self->{"centstorage"} = shift; - $self->{"biServiceStateEventsObj"} = shift; - $self->{"timePeriodObj"} = shift; - if (@_) { - $self->{"centreon"} = shift; - } - - $self->{"name"} = "servicestateevents"; - $self->{"timeColumn"} = "end_time"; - bless $self, $class; - return $self; -} - -sub getName() { - my $self = shift; - return $self->{'name'}; -} - -sub getTimeColumn() { - my $self = shift; - return $self->{'timeColumn'}; -} - -sub agreggateEventsByTimePeriod { - my ($self, $timeperiodList, $start, $end, $liveServiceByTpId, $mode) = @_; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my $rangesByTP = ($self->{"timePeriodObj"})->getTimeRangesForPeriodAndTpList($timeperiodList, $start, $end); - my $query = "SELECT e.host_id,e.service_id, start_time, end_time, ack_time, state, last_update"; - $query .= " FROM `servicestateevents` e"; - $query .= " RIGHT JOIN (select host_id,service_id from mod_bi_tmp_today_services group by host_id,service_id) t2"; - $query .= " ON e.host_id = t2.host_id AND e.service_id = t2.service_id"; - $query .= " WHERE start_time < ".$end.""; - $query .= " AND end_time > ".$start.""; - $query .= " AND in_downtime = 0 "; - $query .= " ORDER BY start_time "; - - my $serviceEventObjects = $self->{"biServiceStateEventsObj"}; - my $sth = $db->query({ query => $query }); - $serviceEventObjects->createTempBIEventsTable(); - $serviceEventObjects->prepareTempQuery(); - - while (my $row = $sth->fetchrow_hashref()) { - if (!defined($row->{'end_time'})) { - $row->{'end_time'} = $end; - } - while (my ($timeperiodID, $timeRanges) = each %$rangesByTP) { - my @tab = (); - $tab[0] = $row->{'host_id'}; - $tab[1] = $row->{'service_id'}; - $tab[2] = $liveServiceByTpId->{$timeperiodID}; - $tab[3] = $row->{'state'}; - if ($mode eq 'daily') { - $timeRanges = ($self->{"timePeriodObj"})->getTimeRangesForPeriod($timeperiodID, $row->{'start_time'}, $row->{'end_time'}); - } - ($tab[4], $tab[5]) = $self->processIncidentForTp($timeRanges,$row->{'start_time'}, $row->{'end_time'}); - $tab[6] = $row->{'end_time'}; - $tab[7] = defined($row->{ack_time}) ? $row->{ack_time} : 0; - $tab[8] = $row->{last_update}; - if (defined($tab[4]) && $tab[4] != -1) { - $serviceEventObjects->bindParam(\@tab); - } - } - } - ($db->getInstance)->commit; -} - -sub processIncidentForTp { - my ($self, $timeRanges, $start, $end) = @_; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - - my $rangeSize = scalar(@$timeRanges); - my $duration = 0; - my $slaDuration = 0; - my $range = 0; - my $i = 0; - my $processed = 0; - my $slaStart = $start; - my $slaStartModified = 0; - - foreach(@$timeRanges) { - my $currentStart = $start; - my $currentEnd = $end; - $range = $_; - my ($rangeStart, $rangeEnd) = ($range->[0], $range->[1]); - if ($currentStart < $rangeEnd && $currentEnd > $rangeStart) { - $processed = 1; - if ($currentStart > $rangeStart) { - $slaStartModified = 1; - } elsif ($currentStart < $rangeStart) { - $currentStart = $rangeStart; - if (!$slaStartModified) { - $slaStart = $currentStart; - $slaStartModified = 1; - } - } - if ($currentEnd > $rangeEnd) { - $currentEnd = $rangeEnd; - } - $slaDuration += $currentEnd - $currentStart; - } - } - if (!$processed) { - return (-1, -1, -1); - } - return ($slaStart, $slaDuration); -} - -sub dailyPurge { - my $self = shift; - my $db = $self->{"centstorage"}; - my $logger = $self->{"logger"}; - my ($end) = @_; - - $logger->writeLog("DEBUG", "[PURGE] [servicestateevents] purging data older than ".$end); - my $query = "DELETE FROM `servicestateevents` where end_time < UNIX_TIMESTAMP('".$end."')"; - $db->query({ query => $query }); -} - -sub getNbEvents { - my $self = shift; - my $db = $self->{"centstorage"}; - my ($start, $end) = @_; - my $nbEvents = 0; - my $logger = $self->{"logger"}; - - my $query = "SELECT count(*) as nbEvents"; - $query .= " FROM `servicestateevents` e"; - $query .= " RIGHT JOIN (select host_id,service_id from mod_bi_tmp_today_services group by host_id,service_id) t2"; - $query .= " ON e.host_id = t2.host_id AND e.service_id = t2.service_id"; - $query .= " WHERE start_time < ".$end.""; - $query .= " AND end_time > ".$start.""; - $query .= " AND in_downtime = 0 "; - - my $sth = $db->query({ query => $query }); - - while (my $row = $sth->fetchrow_hashref()) { - $nbEvents = $row->{'nbEvents'}; - } - return $nbEvents; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/nodes/class.pm b/centreon-gorgone/gorgone/modules/centreon/nodes/class.pm deleted file mode 100644 index d9deecb5ff..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/nodes/class.pm +++ /dev/null @@ -1,256 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::nodes::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::sqlquery; -use gorgone::class::http::http; -use MIME::Base64; -use JSON::XS; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{register_nodes} = {}; - - $connector->{default_resync_time} = (defined($options{config}->{resync_time}) && $options{config}->{resync_time} =~ /(\d+)/) ? $1 : 600; - $connector->{resync_time} = $connector->{default_resync_time}; - $connector->{last_resync_time} = -1; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[nodes] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub check_debug { - my ($self, %options) = @_; - - my $request = "SELECT `value` FROM options WHERE `key` = 'debug_gorgone'"; - my ($status, $datas) = $self->{class_object}->custom_execute(request => $request, mode => 2); - if ($status == -1) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot find debug configuration' }); - $self->{logger}->writeLogError('[nodes] -class- cannot find debug configuration'); - return 1; - } - - my $map_values = { 0 => 'default', 1 => 'debug' }; - my $debug_gorgone = 0; - $debug_gorgone = $datas->[0]->[0] if (defined($datas->[0]->[0])); - if (!defined($self->{debug_gorgone}) || $self->{debug_gorgone} != $debug_gorgone) { - $self->send_internal_action({ action => 'BCASTLOGGER', data => { content => { severity => $map_values->{$debug_gorgone} } } }); - } - - $self->{debug_gorgone} = $debug_gorgone; - return 0; -} - -sub action_centreonnodessync { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action nodesresync proceed' }); - - # If we have a SQL issue: resync = 10 sec - if ($self->check_debug()) { - $self->{resync_time} = 10; - return 1; - } - - my $request = 'SELECT remote_server_id, poller_server_id FROM rs_poller_relation'; - my ($status, $datas) = $self->{class_object}->custom_execute(request => $request, mode => 2); - if ($status == -1) { - $self->{resync_time} = 10; - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot find nodes remote configuration' }); - $self->{logger}->writeLogError('[nodes] Cannot find nodes remote configuration'); - return 1; - } - - # we set a pathscore of 100 because it's "slave" - my $register_subnodes = {}; - foreach (@$datas) { - $register_subnodes->{$_->[0]} = [] if (!defined($register_subnodes->{$_->[0]})); - unshift @{$register_subnodes->{$_->[0]}}, { id => $_->[1], pathscore => 100 }; - } - - $request = " - SELECT id, name, localhost, ns_ip_address, gorgone_port, remote_id, remote_server_use_as_proxy, gorgone_communication_type - FROM nagios_server - WHERE ns_activate = '1' - "; - ($status, $datas) = $self->{class_object}->custom_execute(request => $request, mode => 2); - if ($status == -1) { - $self->{resync_time} = 10; - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot find nodes configuration' }); - $self->{logger}->writeLogError('[nodes] Cannot find nodes configuration'); - return 1; - } - - my $core_id; - my $register_temp = {}; - my $register_nodes = []; - foreach (@$datas) { - if ($_->[2] == 1) { - $core_id = $_->[0]; - next; - } - - # remote_server_use_as_proxy = 1 means: pass through the remote. otherwise directly. - if (defined($_->[5]) && $_->[5] =~ /\d+/ && $_->[6] == 1) { - $register_subnodes->{$_->[5]} = [] if (!defined($register_subnodes->{$_->[5]})); - unshift @{$register_subnodes->{$_->[5]}}, { id => $_->[0], pathscore => 1 }; - next; - } - $self->{register_nodes}->{$_->[0]} = 1; - $register_temp->{$_->[0]} = 1; - if ($_->[7] == 2) { - push @$register_nodes, { - id => $_->[0], - type => 'push_ssh', - address => $_->[3], - ssh_port => $_->[4], - ssh_username => $self->{config}->{ssh_username} - }; - } else { - push @$register_nodes, { - id => $_->[0], - type => 'push_zmq', - address => $_->[3], - port => $_->[4] - }; - } - } - - my $unregister_nodes = []; - foreach (keys %{$self->{register_nodes}}) { - if (!defined($register_temp->{$_})) { - push @$unregister_nodes, { id => $_ }; - delete $self->{register_nodes}->{$_}; - } - } - - # We add subnodes - foreach (@$register_nodes) { - if (defined($register_subnodes->{ $_->{id} })) { - $_->{nodes} = $register_subnodes->{ $_->{id} }; - } - } - - $self->send_internal_action({ action => 'SETCOREID', data => { id => $core_id } }) if (defined($core_id)); - $self->send_internal_action({ action => 'REGISTERNODES', data => { nodes => $register_nodes } }); - $self->send_internal_action({ action => 'UNREGISTERNODES', data => { nodes => $unregister_nodes } }); - - $self->{logger}->writeLogDebug("[nodes] Finish resync"); - $self->send_log(code => GORGONE_ACTION_FINISH_OK, token => $options{token}, data => { message => 'action nodesresync finished' }); - - $self->{resync_time} = $self->{default_resync_time}; - return 0; -} - -sub periodic_exec { - my ($self, %options) = @_; - - if ($self->{stop} == 1) { - $self->{logger}->writeLogInfo("[nodes] -class- $$ has quit"); - exit(0); - } - - if (time() - $self->{resync_time} > $self->{last_resync_time}) { - $self->{last_resync_time} = time(); - $self->action_centreonnodessync(); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{db_centreon} = gorgone::class::db->new( - dsn => $self->{config_db_centreon}->{dsn}, - user => $self->{config_db_centreon}->{username}, - password => $self->{config_db_centreon}->{password}, - force => 0, - logger => $self->{logger} - ); - $self->{class_object} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centreon}); - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-nodes', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'CENTREONNODESREADY', - data => {} - }); - - $self->periodic_exec(); - - my $watcher_timer = $self->{loop}->timer(5, 5, sub { $self->periodic_exec() } ); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/nodes/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/nodes/hooks.pm deleted file mode 100644 index f7806358d3..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/nodes/hooks.pm +++ /dev/null @@ -1,158 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::nodes::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::centreon::nodes::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'nodes'; -use constant EVENTS => [ - { event => 'CENTREONNODESSYNC', uri => '/sync', method => 'POST' }, - { event => 'CENTREONNODESREADY' } -]; - -my $config_core; -my $config; -my ($config_db_centreon); -my $nodes = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centreon = $options{config_db_centreon}; - $config->{resync_time} = defined($config->{resync_time}) && $config->{resync_time} =~ /(\d+)/ ? $1 : 600; - $config->{ssh_username} = defined($config->{ssh_username}) ? $config->{ssh_username} : 'centreon'; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'CENTREONNODESREADY') { - $nodes->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$nodes->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgonenodes: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-nodes', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($nodes->{running}) && $nodes->{running} == 1) { - $options{logger}->writeLogDebug("[nodes] Send TERM signal $nodes->{pid}"); - CORE::kill('TERM', $nodes->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($nodes->{running} == 1) { - $options{logger}->writeLogDebug("[nodes] Send KILL signal for pool"); - CORE::kill('KILL', $nodes->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($nodes->{pid}) || $nodes->{pid} != $pid); - - $nodes = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($nodes->{running}) && $nodes->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[nodes] Create module 'nodes' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-nodes'; - my $module = gorgone::modules::centreon::nodes::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - config_db_centreon => $config_db_centreon, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[nodes] PID $child_pid (gorgone-nodes)"); - $nodes = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/statistics/class.pm b/centreon-gorgone/gorgone/modules/centreon/statistics/class.pm deleted file mode 100644 index 517c7c6fab..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/statistics/class.pm +++ /dev/null @@ -1,645 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::statistics::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::sqlquery; -use File::Path qw(make_path); -use JSON::XS; -use Time::HiRes; -use RRDs; -use EV; - -my $result; -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{log_pace} = 3; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogInfo("[statistics] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub get_pollers_config { - my ($self, %options) = @_; - - my ($status, $data) = $self->{class_object_centreon}->custom_execute( - request => "SELECT id, nagiostats_bin, cfg_dir, cfg_file FROM nagios_server, cfg_nagios WHERE ns_activate = '1' AND cfg_nagios.nagios_server_id = nagios_server.id", - mode => 1, - keys => 'id' - ); - if ($status == -1) { - $self->{logger}->writeLogError('[engine] Cannot get Pollers configuration'); - return -1; - } - - return $data; -} - -sub get_broker_stats_collection_flag { - my ($self, %options) = @_; - - my ($status, $data) = $self->{class_object_centreon}->custom_execute( - request => "SELECT `value` FROM options WHERE `key` = 'enable_broker_stats'", - mode => 2 - ); - if ($status == -1 || !defined($data->[0][0])) { - $self->{logger}->writeLogError('[statistics] Cannot get Broker statistics collection flag'); - return -1; - } - - return $data->[0]->[0]; -} - -sub action_brokerstats { - my ($self, %options) = @_; - - $options{token} = 'broker_stats' if (!defined($options{token})); - - $self->{logger}->writeLogDebug("[statistics] No Broker statistics collection configured"); - - $self->send_log( - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - instant => 1, - data => { - message => 'action brokerstats starting' - } - ); - - if ($self->get_broker_stats_collection_flag() < 1) { - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - instant => 1, - data => { - message => 'no collection configured' - } - ); - - return 0; - } - - my $request = "SELECT id, cache_directory, config_name FROM cfg_centreonbroker " . - "JOIN nagios_server " . - "WHERE ns_activate = '1' AND stats_activate = '1' AND ns_nagios_server = id"; - - if (defined($options{data}->{variables}[0]) && $options{data}->{variables}[0] =~ /\d+/) { - $request .= " AND id = '" . $options{data}->{variables}[0] . "'"; - } - - if (!defined($options{data}->{content}->{collect_localhost}) || - $options{data}->{content}->{collect_localhost} eq 'false') { - $request .= " AND localhost = '0'"; - } - - my ($status, $data) = $self->{class_object_centreon}->custom_execute(request => $request, mode => 2); - if ($status == -1) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - instant => 1, - data => { - message => 'cannot find configuration' - } - ); - $self->{logger}->writeLogError("[statistics] Cannot find configuration"); - return 1; - } - - foreach (@{$data}) { - my $target = $_->[0]; - my $statistics_file = $_->[1] . "/" . $_->[2] . "-stats.json"; - $self->{logger}->writeLogInfo( - "[statistics] Collecting Broker statistics file '" . $statistics_file . "' from target '" . $target . "'" - ); - - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonestatistics', - event => 'STATISTICSLISTENER', - target => $target, - token => $options{token} . '-' . $target, - timeout => defined($options{data}->{content}->{timeout}) && $options{data}->{content}->{timeout} =~ /(\d+)/ ? - $1 + $self->{log_pace} + 5: undef, - log_pace => $self->{log_pace} - } - ] - }); - - $self->send_internal_action({ - target => $target, - action => 'COMMAND', - token => $options{token} . '-' . $target, - data => { - instant => 1, - content => [ - { - command => 'cat ' . $statistics_file, - timeout => $options{data}->{content}->{timeout}, - metadata => { - poller_id => $target, - config_name => $_->[2], - source => 'brokerstats' - } - } - ] - } - }); - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - instant => 1, - data => { - message => 'action brokerstats finished' - } - ); - - return 0; -} - -sub action_enginestats { - my ($self, %options) = @_; - - $options{token} = 'engine_stats' if (!defined($options{token})); - - $self->send_log( - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - instant => 1, - data => { - message => 'action enginestats starting' - } - ); - - my $pollers = $self->get_pollers_config(); - - foreach (keys %$pollers) { - my $target = $_; - my $enginestats_file = $pollers->{$_}->{nagiostats_bin}; - my $config_file = $pollers->{$_}->{cfg_dir} . '/' . $pollers->{$_}->{cfg_file}; - $self->{logger}->writeLogInfo( - "[statistics] Collecting Engine statistics from target '" . $target . "'" - ); - - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonestatistics', - event => 'STATISTICSLISTENER', - target => $target, - token => $options{token} . '-' . $target, - timeout => defined($options{data}->{content}->{timeout}) && $options{data}->{content}->{timeout} =~ /(\d+)/ ? - $1 + $self->{log_pace} + 5: undef, - log_pace => $self->{log_pace} - } - ] - }); - - $self->send_internal_action({ - target => $target, - action => 'COMMAND', - token => $options{token} . '-' . $target, - data => { - instant => 1, - content => [ - { - command => $enginestats_file . ' -c ' . $config_file, - timeout => $options{data}->{content}->{timeout}, - metadata => { - poller_id => $target, - source => 'enginestats' - } - } - ] - } - }); - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - instant => 1, - data => { - message => 'action enginestats finished' - } - ); - - return 0; -} - -sub action_statisticslistener { - my ($self, %options) = @_; - - return 0 if (!defined($options{token})); - return 0 if ($options{data}->{code} != GORGONE_MODULE_ACTION_COMMAND_RESULT); - - if ($options{data}->{data}->{metadata}->{source} eq "brokerstats") { - $self->write_broker_stats(data => $options{data}->{data}); - } elsif ($options{data}->{data}->{metadata}->{source} eq "enginestats") { - $self->write_engine_stats(data => $options{data}->{data}); - } -} - -sub write_broker_stats { - my ($self, %options) = @_; - - return if (!defined($options{data}->{result}->{exit_code}) || $options{data}->{result}->{exit_code} != 0 || - !defined($options{data}->{metadata}->{poller_id}) || !defined($options{data}->{metadata}->{config_name})); - - my $broker_cache_dir = $self->{config}->{broker_cache_dir} . '/' . $options{data}->{metadata}->{poller_id}; - - if (! -d $broker_cache_dir ) { - if (make_path($broker_cache_dir) == 0) { - $self->{logger}->writeLogError("[statistics] Cannot create directory '" . $broker_cache_dir . "': $!"); - return 1; - } - } - - my $dest_file = $broker_cache_dir . '/' . $options{data}->{metadata}->{config_name} . '.json'; - $self->{logger}->writeLogDebug("[statistics] Writing file '" . $dest_file . "'"); - open(FH, '>', $dest_file); - print FH $options{data}->{result}->{stdout}; - close(FH); - - return 0 -} - -sub write_engine_stats { - my ($self, %options) = @_; - - return if (!defined($options{data}->{result}->{exit_code}) || $options{data}->{result}->{exit_code} != 0 || - !defined($options{data}->{metadata}->{poller_id})); - - my $engine_stats_dir = $self->{config}->{engine_stats_dir} . '/perfmon-' . $options{data}->{metadata}->{poller_id}; - - if (! -d $engine_stats_dir ) { - if (make_path($engine_stats_dir) == 0) { - $self->{logger}->writeLogError("[statistics] Cannot create directory '" . $engine_stats_dir . "': $!"); - return 1; - } - } - - foreach (split(/\n/, $options{data}->{result}->{stdout})) { - if ($_ =~ /Used\/High\/Total Command Buffers:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)/) { - my $dest_file = $engine_stats_dir . '/nagios_cmd_buffer.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "In_Use", "Max_Used", "Total_Available" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "In_Use", "Max_Used", "Total_Available" ], - values => [ $1, $2 , $3 ] - ); - } elsif ($_ =~ /Active Service Latency:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)\ sec/) { - my $status = $self->{class_object_centstorage}->custom_execute( - request => "DELETE FROM `nagios_stats` WHERE instance_id = '" . $options{data}->{metadata}->{poller_id} . "'" - ); - if ($status == -1) { - $self->{logger}->writeLogError("[statistics] Failed to delete statistics in 'nagios_stats table'"); - } else { - my $status = $self->{class_object_centstorage}->custom_execute( - request => "INSERT INTO `nagios_stats` (instance_id, stat_label, stat_key, stat_value) VALUES " . - "('$options{data}->{metadata}->{poller_id}', 'Service Check Latency', 'Min', '$1'), " . - "('$options{data}->{metadata}->{poller_id}', 'Service Check Latency', 'Max', '$2'), " . - "('$options{data}->{metadata}->{poller_id}', 'Service Check Latency', 'Average', '$3')" - ); - if ($status == -1) { - $self->{logger}->writeLogError("[statistics] Failed to add statistics in 'nagios_stats table'"); - } - } - - my $dest_file = $engine_stats_dir . '/nagios_active_service_latency.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "Min", "Max", "Average" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "Min", "Max", "Average" ], - values => [ $1, $2 , $3 ] - ); - } elsif ($_ =~ /Active Service Execution Time:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)\ sec/) { - my $dest_file = $engine_stats_dir . '/nagios_active_service_execution.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "Min", "Max", "Average" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "Min", "Max", "Average" ], - values => [ $1, $2 , $3 ] - ); - } elsif ($_ =~ /Active Services Last 1\/5\/15\/60 min:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)/) { - my $dest_file = $engine_stats_dir . '/nagios_active_service_last.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "Last_Min", "Last_5_Min", "Last_15_Min", "Last_Hour" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "Last_Min", "Last_5_Min", "Last_15_Min", "Last_Hour" ], - values => [ $1, $2 , $3, $4 ] - ); - } elsif ($_ =~ /Services Ok\/Warn\/Unk\/Crit:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)/) { - my $dest_file = $engine_stats_dir . '/nagios_services_states.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "Ok", "Warn", "Unk", "Crit" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "Ok", "Warn", "Unk", "Crit" ], - values => [ $1, $2 , $3, $4 ] - ); - } elsif ($_ =~ /Active Host Latency:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)\ sec/) { - my $dest_file = $engine_stats_dir . '/nagios_active_host_latency.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "Min", "Max", "Average" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "Min", "Max", "Average" ], - values => [ $1, $2 , $3 ] - ); - } elsif ($_ =~ /Active Host Execution Time:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)\ sec/) { - my $dest_file = $engine_stats_dir . '/nagios_active_host_execution.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "Min", "Max", "Average" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "Min", "Max", "Average" ], - values => [ $1, $2 , $3 ] - ); - } elsif ($_ =~ /Active Hosts Last 1\/5\/15\/60 min:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)/) { - my $dest_file = $engine_stats_dir . '/nagios_active_host_last.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "Last_Min", "Last_5_Min", "Last_15_Min", "Last_Hour" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "Last_Min", "Last_5_Min", "Last_15_Min", "Last_Hour" ], - values => [ $1, $2 , $3, $4 ] - ); - } elsif ($_ =~ /Hosts Up\/Down\/Unreach:\s*([0-9\.]*)\ \/\ ([0-9\.]*)\ \/\ ([0-9\.]*)/) { - my $dest_file = $engine_stats_dir . '/nagios_hosts_states.rrd'; - $self->{logger}->writeLogDebug("[statistics] Writing in file '" . $dest_file . "'"); - if (!-e $dest_file) { - next if ($self->rrd_create( - file => $dest_file, - heartbeat => $self->{config}->{heartbeat}, - interval => $self->{config}->{interval}, - number => $self->{config}->{number}, - ds => [ "Up", "Down", "Unreach" ] - )); - } - $self->rrd_update( - file => $dest_file, - ds => [ "Up", "Down", "Unreach" ], - values => [ $1, $2 , $3 ] - ); - } - } -} - -sub rrd_create { - my ($self, %options) = @_; - - my @ds; - foreach my $ds (@{$options{ds}}) { - push @ds, "DS:" . $ds . ":GAUGE:" . $options{interval} . ":0:U"; - } - - RRDs::create( - $options{file}, - "-s" . $options{interval}, - @ds, - "RRA:AVERAGE:0.5:1:" . $options{number}, - "RRA:AVERAGE:0.5:12:" . $options{number} - ); - if (RRDs::error()) { - my $error = RRDs::error(); - $self->{logger}->writeLogError("[statistics] Error creating RRD file '" . $options{file} . "': " . $error); - return 1 - } - - foreach my $ds (@{$options{ds}}) { - RRDs::tune($options{file}, "-h", $ds . ":" . $options{heartbeat}); - if (RRDs::error()) { - my $error = RRDs::error(); - $self->{logger}->writeLogError("[statistics] Error tuning RRD file '" . $options{file} . "': " . $error); - return 1 - } - } - - return 0; -} - -sub rrd_update { - my ($self, %options) = @_; - - my $append = ''; - my $ds; - foreach (@{$options{ds}}) { - $ds .= $append . $_; - $append = ':'; - } - my $values; - foreach (@{$options{values}}) { - $values .= $append . $_; - } - RRDs::update( - $options{file}, - "--template", - $ds, - "N" . $values - ); - if (RRDs::error()) { - my $error = RRDs::error(); - $self->{logger}->writeLogError("[statistics] Error updating RRD file '" . $options{file} . "': " . $error); - return 1 - } - - return 0; -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[statistics] $$ has quit"); - exit(0); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-statistics', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'STATISTICSREADY', - data => {} - }); - - $self->{db_centreon} = gorgone::class::db->new( - dsn => $self->{config_db_centreon}->{dsn}, - user => $self->{config_db_centreon}->{username}, - password => $self->{config_db_centreon}->{password}, - force => 2, - logger => $self->{logger} - ); - $self->{class_object_centreon} = gorgone::class::sqlquery->new( - logger => $self->{logger}, - db_centreon => $self->{db_centreon} - ); - - $self->{db_centstorage} = gorgone::class::db->new( - dsn => $self->{config_db_centstorage}->{dsn}, - user => $self->{config_db_centstorage}->{username}, - password => $self->{config_db_centstorage}->{password}, - force => 2, - logger => $self->{logger} - ); - $self->{class_object_centstorage} = gorgone::class::sqlquery->new( - logger => $self->{logger}, - db_centreon => $self->{db_centstorage} - ); - - if (defined($self->{config}->{cron})) { - $self->send_internal_action({ - action => 'ADDCRON', - data => { - content => $self->{config}->{cron} - } - }); - } - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/centreon/statistics/hooks.pm b/centreon-gorgone/gorgone/modules/centreon/statistics/hooks.pm deleted file mode 100644 index 8d13dd0837..0000000000 --- a/centreon-gorgone/gorgone/modules/centreon/statistics/hooks.pm +++ /dev/null @@ -1,172 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::centreon::statistics::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::standard::constants qw(:all); -use gorgone::modules::centreon::statistics::class; - -use constant NAMESPACE => 'centreon'; -use constant NAME => 'statistics'; -use constant EVENTS => [ - { event => 'STATISTICSREADY' }, - { event => 'STATISTICSLISTENER' }, - { event => 'BROKERSTATS', uri => '/broker', method => 'GET' }, - { event => 'ENGINESTATS', uri => '/engine', method => 'GET' } -]; - -my $config_core; -my $config; -my $config_db_centreon; -my $config_db_centstorage; -my $statistics = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centreon = $options{config_db_centreon}; - $config_db_centstorage = $options{config_db_centstorage}; - $config->{broker_cache_dir} = defined($config->{broker_cache_dir}) ? - $config->{broker_cache_dir} : '/var/cache/centreon/broker-stats/'; - $config->{engine_stats_dir} = defined($config->{config}->{engine_stats_dir}) ? - $config->{config}->{engine_stats_dir} : "/var/lib/centreon/nagios-perf/"; - - $config->{interval} = defined($config->{interval}) ? $config->{interval} : 300; - $config->{length} = defined($config->{length}) ? $config->{length} : 365; - $config->{number} = $config->{length} * 24 * 60 * 60 / $config->{interval}; - $config->{heartbeat_factor} = defined($config->{heartbeat_factor}) ? $config->{heartbeat_factor} : 10; - $config->{heartbeat} = $config->{interval} * $config->{heartbeat_factor}; - - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'STATISTICSREADY') { - $statistics->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$statistics->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { msg => 'gorgonestatistics: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-statistics', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($statistics->{running}) && $statistics->{running} == 1) { - $options{logger}->writeLogDebug("[statistics] Send TERM signal $statistics->{pid}"); - CORE::kill('TERM', $statistics->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($statistics->{running} == 1) { - $options{logger}->writeLogDebug("[statistics] Send KILL signal for pool"); - CORE::kill('KILL', $statistics->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($statistics->{pid}) || $statistics->{pid} != $pid); - - $statistics = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($statistics->{running}) && $statistics->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[statistics] Create module 'statistics' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-statistics'; - my $module = gorgone::modules::centreon::statistics::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - config_db_centreon => $config_db_centreon, - config_db_centstorage => $config_db_centstorage, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[statistics] PID $child_pid (gorgone-statistics)"); - $statistics = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/action/class.pm b/centreon-gorgone/gorgone/modules/core/action/class.pm deleted file mode 100644 index aa2a0a84ae..0000000000 --- a/centreon-gorgone/gorgone/modules/core/action/class.pm +++ /dev/null @@ -1,896 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::action::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use JSON::XS; -use File::Basename; -use File::Copy; -use File::Path qw(make_path); -use POSIX ":sys_wait_h"; -use MIME::Base64; -use Digest::MD5::File qw(file_md5_hex); -use Archive::Tar; -use Fcntl; -use Try::Tiny; -use EV; - -$Archive::Tar::SAME_PERMISSIONS = 1; -$Archive::Tar::WARN = 0; -$Digest::MD5::File::NOFATALS = 1; -my %handlers = (TERM => {}, HUP => {}, CHLD => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{process_copy_files_error} = {}; - - $connector->{command_timeout} = defined($connector->{config}->{command_timeout}) ? - $connector->{config}->{command_timeout} : 30; - $connector->{whitelist_cmds} = defined($connector->{config}->{whitelist_cmds}) && $connector->{config}->{whitelist_cmds} =~ /true|1/i ? - 1 : 0; - $connector->{allowed_cmds} = []; - $connector->{allowed_cmds} = $connector->{config}->{allowed_cmds} - if (defined($connector->{config}->{allowed_cmds}) && ref($connector->{config}->{allowed_cmds}) eq 'ARRAY'); - - if (defined($connector->{config}->{tar_insecure_extra_mode}) && $connector->{config}->{tar_insecure_extra_mode} =~ /^(?:1|true)$/) { - $Archive::Tar::INSECURE_EXTRACT_MODE = 1; - } - - $connector->{paranoid_plugins} = defined($connector->{config}->{paranoid_plugins}) && $connector->{config}->{paranoid_plugins} =~ /true|1/i ? - 1 : 0; - - $connector->{return_childs} = {}; - $connector->{engine_childs} = {}; - $connector->{max_concurrent_engine} = defined($connector->{config}->{max_concurrent_engine}) ? - $connector->{config}->{max_concurrent_engine} : 3; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; - $SIG{CHLD} = \&class_handle_CHLD; - $handlers{CHLD}->{$self} = sub { $self->handle_CHLD() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogInfo("[action] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub handle_CHLD { - my $self = shift; - my $child_pid; - - while (($child_pid = waitpid(-1, &WNOHANG)) > 0) { - $self->{logger}->writeLogDebug("[action] Received SIGCLD signal (pid: $child_pid)"); - $self->{return_child}->{$child_pid} = 1; - } - - $SIG{CHLD} = \&class_handle_CHLD; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub class_handle_CHLD { - foreach (keys %{$handlers{CHLD}}) { - &{$handlers{CHLD}->{$_}}(); - } -} - -sub check_childs { - my ($self, %options) = @_; - - foreach (keys %{$self->{return_child}}) { - delete $self->{engine_childs}->{$_} if (defined($self->{engine_childs}->{$_})); - } - - $self->{return_child} = {}; -} - -sub get_package_manager { - my ($self, %options) = @_; - - my $os = 'unknown'; - my ($rv, $message, $content) = gorgone::standard::misc::slurp(file => '/etc/os-release'); - if ($rv && $content =~ /^ID="(.*?)"/mi) { - $os = $1; - } else { - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => 'lsb_release -a', - timeout => 5, - wait_exit => 1, - redirect_stderr => 1, - logger => $options{logger} - ); - if ($error == 0 && $stdout =~ /^Description:\s+(.*)$/mi) { - $os = $1; - } - } - - $self->{package_manager} = 'unknown'; - if ($os =~ /Debian|Ubuntu/i) { - $self->{package_manager} = 'deb'; - } elsif ($os =~ /CentOS|Redhat|rhel|almalinux|rocky/i) { - $self->{package_manager} = 'rpm'; - } elsif ($os eq 'ol' || $os =~ /Oracle Linux/i) { - $self->{package_manager} = 'rpm'; - } -} - -sub check_plugins_rpm { - my ($self, %options) = @_; - - #rpm -q centreon-plugin-Network-Microsens-G6-Snmp test centreon-plugin-Network-Generic-Bluecoat-Snmp - #centreon-plugin-Network-Microsens-G6-Snmp-20211228-150846.el7.centos.noarch - #package test is not installed - #centreon-plugin-Network-Generic-Bluecoat-Snmp-20211102-130335.el7.centos.noarch - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => 'rpm', - arguments => ['-q', keys %{$options{plugins}}], - timeout => 60, - wait_exit => 1, - redirect_stderr => 1, - logger => $self->{logger} - ); - if ($error != 0) { - return (-1, 'check rpm plugins command issue: ' . $stdout); - } - - my $installed = []; - foreach my $package_name (keys %{$options{plugins}}) { - if ($stdout =~ /^$package_name-(\d+)-/m) { - my $current_version = $1; - if ($current_version < $options{plugins}->{$package_name}) { - push @$installed, $package_name . '-' . $options{plugins}->{$package_name}; - } - } else { - push @$installed, $package_name . '-' . $options{plugins}->{$package_name}; - } - } - - if (scalar(@$installed) > 0) { - return (1, 'install', $installed); - } - - $self->{logger}->writeLogInfo("[action] validate plugins - nothing to install"); - return 0; -} - -sub check_plugins_deb { - my ($self, %options) = @_; - - #dpkg -l centreon-plugin-* - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => 'dpkg', - arguments => ['-l', 'centreon-plugin-*'], - timeout => 60, - wait_exit => 1, - redirect_stderr => 1, - logger => $self->{logger} - ); - - my $installed = []; - foreach my $package_name (keys %{$options{plugins}}) { - if ($stdout =~ /\s+$package_name\s+(\d+)-/m) { - my $current_version = $1; - if ($current_version < $options{plugins}->{$package_name}) { - push @$installed, $package_name . '=' . $options{plugins}->{$package_name}; - } - } else { - push @$installed, $package_name . '=' . $options{plugins}->{$package_name}; - } - } - - if (scalar(@$installed) > 0) { - return (1, 'install', $installed); - } - - $self->{logger}->writeLogInfo("[action] validate plugins - nothing to install"); - return 0; -} - -sub install_plugins { - my ($self, %options) = @_; - - $self->{logger}->writeLogInfo("[action] validate plugins - install " . join(' ', @{$options{installed}})); - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => 'sudo', - arguments => ['/usr/local/bin/gorgone_install_plugins.pl', '--type=' . $options{type}, @{$options{installed}}], - timeout => 300, - wait_exit => 1, - redirect_stderr => 1, - logger => $self->{logger} - ); - $self->{logger}->writeLogDebug("[action] install plugins. Command output: [\"$stdout\"]"); - if ($error != 0) { - return (-1, 'install plugins command issue: ' . $stdout); - } - - return 0; -} - -sub validate_plugins_rpm { - my ($self, %options) = @_; - - my ($rv, $message, $installed) = $self->check_plugins_rpm(%options); - return (1, $message) if ($rv == -1); - return 0 if ($rv == 0); - - if ($rv == 1) { - ($rv, $message) = $self->install_plugins(type => 'rpm', installed => $installed); - return (1, $message) if ($rv == -1); - } - - ($rv, $message, $installed) = $self->check_plugins_rpm(%options); - return (1, $message) if ($rv == -1); - if ($rv == 1) { - $message = 'validate plugins - still some to install: ' . join(' ', @$installed); - $self->{logger}->writeLogError("[action] $message"); - return (1, $message); - } - - return 0; -} - -sub validate_plugins_deb { - my ($self, %options) = @_; - - my $plugins = {}; - foreach (keys %{$options{plugins}}) { - $plugins->{ lc($_) } = $options{plugins}->{$_}; - } - - my ($rv, $message, $installed) = $self->check_plugins_deb(plugins => $plugins); - return (1, $message) if ($rv == -1); - return 0 if ($rv == 0); - - if ($rv == 1) { - ($rv, $message) = $self->install_plugins(type => 'deb', installed => $installed); - return (1, $message) if ($rv == -1); - } - - ($rv, $message, $installed) = $self->check_plugins_deb(plugins => $plugins); - return (1, $message) if ($rv == -1); - if ($rv == 1) { - $message = 'validate plugins - still some to install: ' . join(' ', @$installed); - $self->{logger}->writeLogError("[action] $message"); - return (1, $message); - } - - return 0; -} - -sub validate_plugins { - my ($self, %options) = @_; - - my ($rv, $message, $content); - my $plugins = $options{plugins}; - if (!defined($plugins)) { - ($rv, $message, $content) = gorgone::standard::misc::slurp(file => $options{file}); - return (1, $message) if (!$rv); - - try { - $plugins = JSON::XS->new->decode($content); - } catch { - return (1, 'cannot decode json'); - }; - } - - # nothing to validate. so it's ok, show must go on!! :) - if (ref($plugins) ne 'HASH' || scalar(keys %$plugins) <= 0) { - return 0; - } - - if ($self->{package_manager} eq 'rpm') { - ($rv, $message) = $self->validate_plugins_rpm(plugins => $plugins); - } elsif ($self->{package_manager} eq 'deb') { - ($rv, $message) = $self->validate_plugins_deb(plugins => $plugins); - } else { - ($rv, $message) = (1, 'validate plugins - unsupported operating system'); - } - - return ($rv, $message); -} - -sub is_command_authorized { - my ($self, %options) = @_; - - return 0 if ($self->{whitelist_cmds} == 0); - - foreach my $regexp (@{$self->{allowed_cmds}}) { - return 0 if ($options{command} =~ /$regexp/); - } - - return 1; -} - -sub action_command { - my ($self, %options) = @_; - - if (!defined($options{data}->{content}) || ref($options{data}->{content}) ne 'ARRAY') { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "expected array, found '" . ref($options{data}->{content}) . "'" - } - ); - return -1; - } - - my $index = 0; - foreach my $command (@{$options{data}->{content}}) { - if (!defined($command->{command}) || $command->{command} eq '') { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "need command argument at array index '" . $index . "'" - } - ); - return -1; - } - - if ($self->is_command_authorized(command => $command->{command})) { - $self->{logger}->writeLogError("[action] command not allowed (whitelist): " . $command->{command}); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command not allowed (whitelist) at array index '$index' : $command->{command}" - } - ); - return -1; - } - - $index++; - } - - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "commands processing has started", - request_content => $options{data}->{content} - } - ); - - my $errors = 0; - foreach my $command (@{$options{data}->{content}}) { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command has started", - command => $command->{command}, - metadata => $command->{metadata} - } - ); - - # check install pkg - if (defined($command->{metadata}) && defined($command->{metadata}->{pkg_install})) { - my ($rv, $message) = $self->validate_plugins(plugins => $command->{metadata}->{pkg_install}); - if ($rv && $self->{paranoid_plugins} == 1) { - $self->{logger}->writeLogError("[action] $message"); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command execution issue", - command => $command->{command}, - metadata => $command->{metadata}, - result => { - exit_code => $rv, - stdout => $message - } - } - ); - next; - } - } - - my $start = time(); - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => $command->{command}, - timeout => (defined($command->{timeout})) ? $command->{timeout} : $self->{command_timeout}, - wait_exit => 1, - redirect_stderr => 1, - logger => $self->{logger} - ); - my $end = time(); - if ($error <= -1000) { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command execution issue", - command => $command->{command}, - metadata => $command->{metadata}, - result => { - exit_code => $return_code, - stdout => $stdout - }, - metrics => { - start => $start, - end => $end, - duration => $end - $start - } - } - ); - - if (defined($command->{continue_on_error}) && $command->{continue_on_error} == 0) { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "commands processing has been interrupted because of error" - } - ); - return -1; - } - - $errors = 1; - } else { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_MODULE_ACTION_COMMAND_RESULT, - token => $options{token}, - logging => $options{data}->{logging}, - instant => $options{data}->{instant}, - data => { - message => "command has finished successfully", - command => $command->{command}, - metadata => $command->{metadata}, - result => { - exit_code => $return_code, - stdout => $stdout - }, - metrics => { - start => $start, - end => $end, - duration => $end - $start - } - } - ); - } - } - - if ($errors) { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "commands processing has finished with errors" - } - ); - return -1; - } - - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "commands processing has finished successfully" - } - ); - - return 0; -} - -sub action_processcopy { - my ($self, %options) = @_; - - if (!defined($options{data}->{content}) || $options{data}->{content} eq '') { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { message => 'no content' } - ); - return -1; - } - - my $cache_file = $options{data}->{content}->{cache_dir} . '/copy_' . $options{token}; - if ($options{data}->{content}->{status} eq 'inprogress' && defined($options{data}->{content}->{chunk}->{data})) { - my $fh; - if (!sysopen($fh, $cache_file, O_RDWR|O_APPEND|O_CREAT, 0660)) { - # no need to insert too many logs - return -1 if (defined($self->{process_copy_files_error}->{$cache_file})); - $self->{process_copy_files_error}->{$cache_file} = 1; - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { message => "file '$cache_file' open failed: $!" } - ); - - $self->{logger}->writeLogError("[action] file '$cache_file' open failed: $!"); - return -1; - } - delete $self->{process_copy_files_error}->{$cache_file} if (defined($self->{process_copy_files_error}->{$cache_file})); - binmode($fh); - syswrite( - $fh, - MIME::Base64::decode_base64($options{data}->{content}->{chunk}->{data}), - $options{data}->{content}->{chunk}->{size} - ); - close $fh; - - $self->send_log( - code => GORGONE_MODULE_ACTION_PROCESSCOPY_INPROGRESS, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => 'process copy inprogress', - } - ); - $self->{logger}->writeLogInfo("[action] Copy processing - Received chunk for '" . $options{data}->{content}->{destination} . "'"); - return 0; - } elsif ($options{data}->{content}->{status} eq 'end' && defined($options{data}->{content}->{md5})) { - delete $self->{process_copy_files_error}->{$cache_file} if (defined($self->{process_copy_files_error}->{$cache_file})); - my $local_md5_hex = file_md5_hex($cache_file); - if (defined($local_md5_hex) && $options{data}->{content}->{md5} eq $local_md5_hex) { - if ($options{data}->{content}->{type} eq "archive") { - if (! -d $options{data}->{content}->{destination}) { - make_path($options{data}->{content}->{destination}); - } - - my $tar = Archive::Tar->new(); - $tar->setcwd($options{data}->{content}->{destination}); - unless ($tar->read($cache_file, undef, { extract => 1 })) { - my $tar_error = $tar->error(); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { message => "untar failed: $tar_error" } - ); - $self->{logger}->writeLogError("[action] Copy processing - Untar failed: $tar_error"); - return -1; - } - } elsif ($options{data}->{content}->{type} eq 'regular') { - copy($cache_file, $options{data}->{content}->{destination}); - my $uid = getpwnam($options{data}->{content}->{owner}); - my $gid = getgrnam($options{data}->{content}->{group}); - chown($uid, $gid, $options{data}->{content}->{destination}); - } - } else { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { message => 'md5 does not match' } - ); - $self->{logger}->writeLogError('[action] Copy processing - MD5 does not match'); - return -1; - } - } - - unlink($cache_file); - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "process copy finished successfully", - } - ); - $self->{logger}->writeLogInfo("[action] Copy processing - Copy to '" . $options{data}->{content}->{destination} . "' finished successfully"); - return 0; -} - -sub action_actionengine { - my ($self, %options) = @_; - - if (!defined($options{data}->{content}) || $options{data}->{content} eq '') { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { message => 'no content' } - ); - return -1; - } - - if (!defined($options{data}->{content}->{command})) { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "need valid command argument" - } - ); - return -1; - } - - if ($self->is_command_authorized(command => $options{data}->{content}->{command})) { - $self->{logger}->writeLogError("[action] command not allowed (whitelist): " . $options{data}->{content}->{command}); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => 'command not allowed (whitelist)' . $options{data}->{content}->{command} - } - ); - return -1; - } - - if (defined($options{data}->{content}->{plugins}) && $options{data}->{content}->{plugins} ne '') { - my ($rv, $message) = $self->validate_plugins(file => $options{data}->{content}->{plugins}); - if ($rv && $self->{paranoid_plugins} == 1) { - $self->{logger}->writeLogError("[action] $message"); - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => $message - } - ); - return -1; - } - } - - my $start = time(); - my ($error, $stdout, $return_code) = gorgone::standard::misc::backtick( - command => $options{data}->{content}->{command}, - timeout => $self->{command_timeout}, - wait_exit => 1, - redirect_stderr => 1, - logger => $self->{logger} - ); - my $end = time(); - if ($error != 0) { - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => "command execution issue", - command => $options{data}->{content}->{command}, - result => { - exit_code => $return_code, - stdout => $stdout - }, - metrics => { - start => $start, - end => $end, - duration => $end - $start - } - } - ); - return -1; - } - - $self->send_log( - socket => $options{socket_log}, - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - logging => $options{data}->{logging}, - data => { - message => 'actionengine has finished successfully' - } - ); - - return 0; -} - -sub action_run { - my ($self, %options) = @_; - - my $context; - { - local $SIG{__DIE__}; - $context = ZMQ::FFI->new(); - } - - my $socket_log = gorgone::standard::library::connect_com( - context => $context, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-action-'. $$, - logger => $self->{logger}, - zmq_linger => 60000, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - - if ($options{action} eq 'COMMAND') { - $self->action_command(%options, socket_log => $socket_log); - } elsif ($options{action} eq 'ACTIONENGINE') { - $self->action_actionengine(%options, socket_log => $socket_log); - } else { - $self->send_log( - socket => $socket_log, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $options{data}->{logging}, - data => { message => "action unknown" } - ); - return -1; - } -} - -sub create_child { - my ($self, %options) = @_; - - if ($options{action} =~ /^BCAST.*/) { - if ((my $method = $self->can('action_' . lc($options{action})))) { - $method->($self, token => $options{token}, data => $options{data}); - } - return undef; - } - - if ($options{action} eq 'ACTIONENGINE') { - my $num = scalar(keys %{$self->{engine_childs}}); - if ($num > $self->{max_concurrent_engine}) { - $self->{logger}->writeLogInfo("[action] max_concurrent_engine limit reached ($num/$self->{max_concurrent_engine})"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "max_concurrent_engine limit reached ($num/$self->{max_concurrent_engine})" } - ); - return undef; - } - } - - $self->{logger}->writeLogDebug("[action] Create sub-process"); - my $child_pid = fork(); - if (!defined($child_pid)) { - $self->{logger}->writeLogError("[action] Cannot fork process: $!"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "cannot fork: $!" } - ); - return undef; - } - - if ($child_pid == 0) { - $self->set_fork(); - $self->action_run(action => $options{action}, token => $options{token}, data => $options{data}); - exit(0); - } else { - if ($options{action} eq 'ACTIONENGINE') { - $self->{engine_childs}->{$child_pid} = 1; - } - } -} - -sub event { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($message) = $self->read_message(); - next if (!defined($message)); - - $self->{logger}->writeLogDebug("[action] Event: $message"); - - if ($message !~ /^\[ACK\]/) { - $message =~ /^\[(.*?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)$/m; - - my ($action, $token) = ($1, $2); - my ($rv, $data) = $self->json_decode(argument => $3, token => $token); - next if ($rv); - - if (defined($data->{parameters}->{no_fork})) { - if ((my $method = $self->can('action_' . lc($action)))) { - $method->($self, token => $token, data => $data); - } - } else { - $self->create_child(action => $action, token => $token, data => $data); - } - } - } -} - -sub periodic_exec { - $connector->check_childs(); - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[action] $$ has quit"); - exit(0); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-action', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'ACTIONREADY', - data => {} - }); - - $self->get_package_manager(); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/action/hooks.pm b/centreon-gorgone/gorgone/modules/core/action/hooks.pm deleted file mode 100644 index 4adaf195c7..0000000000 --- a/centreon-gorgone/gorgone/modules/core/action/hooks.pm +++ /dev/null @@ -1,155 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::action::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::action::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'action'; -use constant EVENTS => [ - { event => 'ACTIONREADY' }, - { event => 'PROCESSCOPY' }, - { event => 'COMMAND', uri => '/command', method => 'POST' }, - { event => 'ACTIONENGINE', uri => '/engine', method => 'POST' } -]; - -my $config_core; -my $config; -my $action = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'ACTIONREADY') { - $action->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$action->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { msg => 'gorgoneaction: still not ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-action', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($action->{running}) && $action->{running} == 1) { - $options{logger}->writeLogDebug("[action] Send TERM signal $action->{running}"); - CORE::kill('TERM', $action->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($action->{running} == 1) { - $options{logger}->writeLogDebug("[action] Send KILL signal for pool"); - CORE::kill('KILL', $action->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($action->{pid}) || $action->{pid} != $pid); - - $action = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($action->{running}) && $action->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[action] Create module 'action' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-action'; - my $module = gorgone::modules::core::action::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[action] PID $child_pid (gorgone-action)"); - $action = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/cron/class.pm b/centreon-gorgone/gorgone/modules/core/cron/class.pm deleted file mode 100644 index 275760b88f..0000000000 --- a/centreon-gorgone/gorgone/modules/core/cron/class.pm +++ /dev/null @@ -1,500 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::cron::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use Schedule::Cron; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[cron] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub action_getcron { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - my $data; - my $id = $options{data}->{variables}[0]; - my $parameter = $options{data}->{variables}[1]; - if (defined($id) && $id ne '') { - if (defined($parameter) && $parameter =~ /^status$/) { - $self->{logger}->writeLogInfo("[cron] Get logs results for definition '" . $id . "'"); - $self->send_internal_action({ - action => 'GETLOG', - token => $options{token}, - data => { - token => $id, - ctime => $options{data}->{parameters}->{ctime}, - etime => $options{data}->{parameters}->{etime}, - limit => $options{data}->{parameters}->{limit}, - code => $options{data}->{parameters}->{code} - } - }); - - my $timeout = 5; - my $ctime = time(); - while (1) { - my $watcher_timer = $self->{loop}->timer(1, 0, \&stop_ev); - $self->{loop}->run(); - last if (time() > ($ctime + $timeout)); - } - - $data = $connector->{ack}->{data}->{data}->{result}; - } else { - my $idx; - eval { - $idx = $self->{cron}->check_entry($id); - }; - if ($@) { - $self->{logger}->writeLogError("[cron] Cron get failed to retrieve entry index"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'failed to retrieve entry index' } - ); - return 1; - } - if (!defined($idx)) { - $self->{logger}->writeLogError("[cron] Cron get failed no entry found for id"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'no entry found for id' } - ); - return 1; - } - - eval { - my $result = $self->{cron}->get_entry($idx); - push @{$data}, { %{$result->{args}[1]->{definition}} } if (defined($result->{args}[1]->{definition})); - }; - if ($@) { - $self->{logger}->writeLogError("[cron] Cron get failed"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'get failed:' . $@ } - ); - return 1; - } - } - } else { - eval { - my @results = $self->{cron}->list_entries(); - foreach my $cron (@results) { - push @{$data}, { %{$cron->{args}[1]->{definition}} }; - } - }; - if ($@) { - $self->{logger}->writeLogError("[cron] Cron get failed"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'get failed:' . $@ } - ); - return 1; - } - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => $data - ); - return 0; -} - -sub action_addcron { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{logger}->writeLogDebug("[cron] Cron add start"); - - foreach my $definition (@{$options{data}->{content}}) { - if (!defined($definition->{timespec}) || $definition->{timespec} eq '' || - !defined($definition->{action}) || $definition->{action} eq '' || - !defined($definition->{id}) || $definition->{id} eq '') { - $self->{logger}->writeLogError("[cron] Cron add missing arguments"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'missing arguments' } - ); - return 1; - } - } - - eval { - foreach my $definition (@{$options{data}->{content}}) { - my $idx = $self->{cron}->check_entry($definition->{id}); - if (defined($idx)) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "id '" . $definition->{id} . "' already exists" } - ); - next; - } - $self->{logger}->writeLogInfo("[cron] Adding cron definition '" . $definition->{id} . "'"); - $self->{cron}->add_entry( - $definition->{timespec}, - $definition->{id}, - { - connector => $connector, - socket => $connector->{internal_socket}, - logger => $self->{logger}, - definition => $definition - } - ); - } - }; - if ($@) { - $self->{logger}->writeLogError("[cron] Cron add failed"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'add failed:' . $@ } - ); - return 1; - } - - $self->{logger}->writeLogDebug("[cron] Cron add finish"); - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { message => 'add succeed' } - ); - return 0; -} - -sub action_updatecron { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{logger}->writeLogDebug("[cron] Cron update start"); - - my $id = $options{data}->{variables}[0]; - if (!defined($id)) { - $self->{logger}->writeLogError("[cron] Cron update missing id"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'missing id' } - ); - return 1; - } - - my $idx; - eval { - $idx = $self->{cron}->check_entry($id); - }; - if ($@) { - $self->{logger}->writeLogError("[cron] Cron update failed to retrieve entry index"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'failed to retrieve entry index' } - ); - return 1; - } - if (!defined($idx)) { - $self->{logger}->writeLogError("[cron] Cron update failed no entry found for id"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'no entry found for id' } - ); - return 1; - } - - my $definition = $options{data}->{content}; - if ((!defined($definition->{timespec}) || $definition->{timespec} eq '') && - (!defined($definition->{command_line}) || $definition->{command_line} eq '')) { - $self->{logger}->writeLogError("[cron] Cron update missing arguments"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'missing arguments' } - ); - return 1; - } - - eval { - my $entry = $self->{cron}->get_entry($idx); - $entry->{time} = $definition->{timespec}; - $entry->{args}[1]->{definition}->{timespec} = $definition->{timespec} - if (defined($definition->{timespec})); - $entry->{args}[1]->{definition}->{command_line} = $definition->{command_line} - if (defined($definition->{command_line})); - $self->{cron}->update_entry($idx, $entry); - }; - if ($@) { - $self->{logger}->writeLogError("[cron] Cron update failed"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'update failed:' . $@ } - ); - return 1; - } - - $self->{logger}->writeLogDebug("[cron] Cron update succeed"); - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { message => 'update succeed' } - ); - return 0; -} - -sub action_deletecron { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{logger}->writeLogDebug("[cron] Cron delete start"); - - my $id = $options{data}->{variables}->[0]; - if (!defined($id) || $id eq '') { - $self->{logger}->writeLogError("[cron] Cron delete missing id"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'missing id' } - ); - return 1; - } - - my $idx; - eval { - $idx = $self->{cron}->check_entry($id); - }; - if ($@) { - $self->{logger}->writeLogError("[cron] Cron delete failed to retrieve entry index"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'failed to retrieve entry index' } - ); - return 1; - } - if (!defined($idx)) { - $self->{logger}->writeLogError("[cron] Cron delete failed no entry found for id"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'no entry found for id' } - ); - return 1; - } - - eval { - $self->{cron}->delete_entry($idx); - }; - if ($@) { - $self->{logger}->writeLogError("[cron] Cron delete failed"); - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'delete failed:' . $@ } - ); - return 1; - } - - $self->{logger}->writeLogDebug("[cron] Cron delete finish"); - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { message => 'delete succeed' } - ); - return 0; -} - -sub event { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($message) = $self->read_message(); - next if (!defined($message)); - - $self->{logger}->writeLogDebug("[cron] Event: $message"); - if ($message =~ /^\[ACK\]\s+\[(.*?)\]\s+(.*)$/m) { - my $token = $1; - my ($rv, $data) = $self->json_decode(argument => $2, token => $token); - next if ($rv); - - $self->{ack} = { - token => $token, - data => $data - }; - } else { - $message =~ /^\[(.*?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)$/m; - if ((my $method = $self->can('action_' . lc($1)))) { - $message =~ /^\[(.*?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)$/m; - my ($action, $token) = ($1, $2); - my ($rv, $data) = $self->json_decode(argument => $3, token => $token); - next if ($rv); - - $method->($self, token => $token, data => $data); - } - } - } -} - -sub stop_ev { - $connector->{loop}->break(); -} - -sub cron_sleep { - my $watcher_timer = $connector->{loop}->timer(1, 0, \&stop_ev); - $connector->{loop}->run(); - - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[cron] $$ has quit"); - exit(0); - } -} - -sub dispatcher { - my ($id, $options) = @_; - - $options->{logger}->writeLogInfo("[cron] Launching job '" . $id . "'"); - - my $token = (defined($options->{definition}->{keep_token})) && $options->{definition}->{keep_token} =~ /true|1/i - ? $options->{definition}->{id} : undef; - - $options->{connector}->send_internal_action({ - socket => $options->{socket}, - token => $token, - action => $options->{definition}->{action}, - target => $options->{definition}->{target}, - data => { - content => $options->{definition}->{parameters} - }, - json_encode => 1 - }); - - my $timeout = 5; - my $ctime = time(); - while (1) { - my $watcher_timer = $options->{connector}->{loop}->timer(1, 0, \&stop_ev); - $options->{connector}->{loop}->run(); - last if (time() > ($ctime + $timeout)); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-cron', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'CRONREADY', - data => {} - }); - - # need at least one cron to get sleep working - push @{$self->{config}->{cron}}, { - id => "default", - timespec => "0 0 * * *", - action => "INFORMATION", - parameters => {} - }; - - $self->{cron} = new Schedule::Cron(\&dispatcher, nostatus => 1, nofork => 1, catch => 1); - - foreach my $definition (@{$self->{config}->{cron}}) { - $self->{cron}->add_entry( - $definition->{timespec}, - $definition->{id}, - { - connector => $connector, - socket => $connector->{internal_socket}, - logger => $self->{logger}, - definition => $definition - } - ); - } - - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - - $self->{cron}->run(sleep => \&cron_sleep); - - exit(0); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/cron/hooks.pm b/centreon-gorgone/gorgone/modules/core/cron/hooks.pm deleted file mode 100644 index f2aaa00711..0000000000 --- a/centreon-gorgone/gorgone/modules/core/cron/hooks.pm +++ /dev/null @@ -1,156 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::cron::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::cron::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'cron'; -use constant EVENTS => [ - { event => 'CRONREADY' }, - { event => 'GETCRON', uri => '/definitions', method => 'GET' }, - { event => 'ADDCRON', uri => '/definitions', method => 'POST' }, - { event => 'DELETECRON', uri => '/definitions', method => 'DELETE' }, - { event => 'UPDATECRON', uri => '/definitions', method => 'PATCH' }, -]; - -my $config_core; -my $config; -my $cron = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'CRONREADY') { - $cron->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$cron->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgonecron: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-cron', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($cron->{running}) && $cron->{running} == 1) { - $options{logger}->writeLogDebug("[cron] Send TERM signal $cron->{pid}"); - CORE::kill('TERM', $cron->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($cron->{running} == 1) { - $options{logger}->writeLogDebug("[cron] Send KILL signal for pool"); - CORE::kill('KILL', $cron->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($cron->{pid}) || $cron->{pid} != $pid); - - $cron = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($cron->{running}) && $cron->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[cron] Create module 'cron' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-cron'; - my $module = gorgone::modules::core::cron::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[cron] PID $child_pid (gorgone-cron)"); - $cron = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/dbcleaner/class.pm b/centreon-gorgone/gorgone/modules/core/dbcleaner/class.pm deleted file mode 100644 index 8e4c8350ae..0000000000 --- a/centreon-gorgone/gorgone/modules/core/dbcleaner/class.pm +++ /dev/null @@ -1,195 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::dbcleaner::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::class::db; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use JSON::XS; -use EV; - -my %handlers = (TERM => {}, HUP => {}, DIE => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{purge_timer} = time(); - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; - $SIG{__DIE__} = \&class_handle_DIE; - $handlers{DIE}->{$self} = sub { $self->handle_DIE($_[0]) }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[dbcleaner] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub handle_DIE { - my $self = shift; - my $msg = shift; - - $self->{logger}->writeLogError("[dbcleaner] Receiving DIE: $msg"); - $self->exit_process(); -} - -sub class_handle_DIE { - my ($msg) = @_; - - foreach (keys %{$handlers{DIE}}) { - &{$handlers{DIE}->{$_}}($msg); - } -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub exit_process { - my ($self, %options) = @_; - - $self->{logger}->writeLogInfo("[dbcleaner] $$ has quit"); - exit(0); -} - -sub action_dbclean { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - if (defined($options{cycle})) { - return 0 if ((time() - $self->{purge_timer}) < 3600); - } - - $self->send_log( - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - data => { - message => 'action dbclean proceed' - } - ) if (!defined($options{cycle})); - - $self->{logger}->writeLogDebug("[dbcleaner] Purge database in progress..."); - my ($status) = $self->{db_gorgone}->query({ - query => 'DELETE FROM gorgone_identity WHERE `mtime` < ?', - bind_values => [time() - $self->{config}->{purge_sessions_time}] - }); - my ($status2) = $self->{db_gorgone}->query({ - query => "DELETE FROM gorgone_history WHERE (instant = 1 AND `ctime` < " . (time() - 86400) . ") OR `ctime` < ?", - bind_values => [time() - $self->{config}->{purge_history_time}] - }); - $self->{purge_timer} = time(); - - $self->{logger}->writeLogDebug("[dbcleaner] Purge finished"); - - if ($status == -1 || $status2 == -1) { - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { - message => 'action dbclean finished' - } - ) if (!defined($options{cycle})); - return 0; - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { - message => 'action dbclean finished' - } - ) if (!defined($options{cycle})); - return 0; -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->exit_process(); - } - - $connector->action_dbclean(cycle => 1); -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-dbcleaner', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'DBCLEANERREADY', - data => {} - }); - - $self->{db_gorgone} = gorgone::class::db->new( - type => $self->get_core_config(name => 'gorgone_db_type'), - db => $self->get_core_config(name => 'gorgone_db_name'), - host => $self->get_core_config(name => 'gorgone_db_host'), - port => $self->get_core_config(name => 'gorgone_db_port'), - user => $self->get_core_config(name => 'gorgone_db_user'), - password => $self->get_core_config(name => 'gorgone_db_password'), - force => 2, - logger => $self->{logger} - ); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/dbcleaner/hooks.pm b/centreon-gorgone/gorgone/modules/core/dbcleaner/hooks.pm deleted file mode 100644 index dba893cb3a..0000000000 --- a/centreon-gorgone/gorgone/modules/core/dbcleaner/hooks.pm +++ /dev/null @@ -1,163 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::dbcleaner::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::dbcleaner::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'dbcleaner'; -use constant EVENTS => [ - { event => 'DBCLEANERREADY' } -]; - -my $config_core; -my $config; -my ($config_db_centreon); -my $dbcleaner = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config->{purge_sessions_time} = - defined($config->{purge_sessions_time}) && $config->{purge_sessions_time} =~ /(\d+)/ ? - $1 : - 3600 - ; - $config->{purge_history_time} = - defined($config->{purge_history_time}) && $config->{purge_history_time} =~ /(\d+)/ ? - $1 : - 604800 - ; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'DBCLEANERREADY') { - $dbcleaner->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$dbcleaner->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgonedbcleaner: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-dbcleaner', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($dbcleaner->{running}) && $dbcleaner->{running} == 1) { - $options{logger}->writeLogDebug("[dbcleaner] Send TERM signal $dbcleaner->{pid}"); - CORE::kill('TERM', $dbcleaner->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($dbcleaner->{running} == 1) { - $options{logger}->writeLogDebug("[dbcleaner] Send KILL signal for pool"); - CORE::kill('KILL', $dbcleaner->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($dbcleaner->{pid}) || $dbcleaner->{pid} != $pid); - - $dbcleaner = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($dbcleaner->{running}) && $dbcleaner->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[dbcleaner] Create module 'dbcleaner' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-dbcleaner'; - my $module = gorgone::modules::core::dbcleaner::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[dbcleaner] PID $child_pid (gorgone-dbcleaner)"); - $dbcleaner = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/httpserver/class.pm b/centreon-gorgone/gorgone/modules/core/httpserver/class.pm deleted file mode 100644 index 10b41e56d2..0000000000 --- a/centreon-gorgone/gorgone/modules/core/httpserver/class.pm +++ /dev/null @@ -1,407 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::httpserver::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::misc; -use gorgone::standard::api; -use HTTP::Daemon; -use HTTP::Status; -use MIME::Base64; -use JSON::XS; -use Socket; -use EV; - -my $time = time(); - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -my %dispatch; - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{api_endpoints} = $options{api_endpoints}; - - if ($connector->{config}->{ssl} eq 'true') { - exit(1) if (gorgone::standard::misc::mymodule_load( - logger => $connector->{logger}, - module => 'HTTP::Daemon::SSL', - error_msg => "[httpserver] -class- cannot load module 'HTTP::Daemon::SSL'") - ); - } - - $connector->{auth_enabled} = (defined($connector->{config}->{auth}->{enabled}) && $connector->{config}->{auth}->{enabled} eq 'true') ? 1 : 0; - - $connector->{allowed_hosts_enabled} = (defined($connector->{config}->{allowed_hosts}->{enabled}) && $connector->{config}->{allowed_hosts}->{enabled} eq 'true') ? 1 : 0; - if (gorgone::standard::misc::mymodule_load( - logger => $connector->{logger}, - module => 'NetAddr::IP', - error_msg => "[httpserver] -class- cannot load module 'NetAddr::IP'. Cannot use allowed_hosts configuration.") - ) { - $connector->{allowed_hosts_enabled} = 0; - } - - $connector->{tokens} = {}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[httpserver] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub init_dispatch { - my ($self, $config_dispatch) = @_; - - $self->{dispatch} = { %{$self->{config}->{dispatch}} } - if (defined($self->{config}->{dispatch}) && $self->{config}->{dispatch} ne ''); -} - -sub check_allowed_host { - my ($self, %options) = @_; - - my $subnet = NetAddr::IP->new($options{peer_addr} . '/32'); - foreach (@{$self->{peer_subnets}}) { - return 1 if ($_->contains($subnet)); - } - - return 0; -} - -sub load_peer_subnets { - my ($self, %options) = @_; - - return if ($self->{allowed_hosts_enabled} == 0); - - $self->{peer_subnets} = []; - return if (!defined($connector->{config}->{allowed_hosts}->{subnets})); - - foreach (@{$self->{config}->{allowed_hosts}->{subnets}}) { - my $subnet = NetAddr::IP->new($_); - if (!defined($subnet)) { - $self->{logger}->writeLogError("[httpserver] Cannot load subnet: $_"); - next; - } - - push @{$self->{peer_subnets}}, $subnet; - } -} - -sub stop_ev { - $connector->{loop}->break(); -} - -sub event { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($message) = $self->read_message(); - next if (!defined($message)); - - if ($message =~ /^\[(.*?)\]\s+\[([a-zA-Z0-9:\-_]*?)\]\s+\[.*?\]\s+(.*)$/m || - $message =~ /^\[(.*?)\]\s+\[([a-zA-Z0-9:\-_]*?)\]\s+(.*)$/m) { - my ($action, $token, $data) = ($1, $2, $3); - $self->{tokens}->{$token} = { - action => $action, - token => $token, - data => $data - }; - if ((my $method = $self->can('action_' . lc($action)))) { - my ($rv, $decoded) = $self->json_decode(argument => $data, token => $token); - next if ($rv); - $method->($self, token => $token, data => $decoded); - } - } - } - - if (defined($self->{break_token}) && defined($self->{tokens}->{ $self->{break_token} })) { - $self->{loop}->break(); - } -} - -sub run { - my ($self, %options) = @_; - - $self->load_peer_subnets(); - - # Connect internal - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $connector->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-httpserver', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'HTTPSERVERREADY', - data => {} - }); - - gorgone::standard::api::set_module($self); - - my $watcher_timer = $self->{loop}->timer(4, 0, \&stop_ev); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() }); - $self->{loop}->run(); - - $self->init_dispatch(); - - # HTTP daemon - my ($daemon, $message_error); - if ($self->{config}->{ssl} eq 'false') { - $message_error = '$@'; - $daemon = HTTP::Daemon->new( - LocalAddr => $self->{config}->{address} . ':' . $self->{config}->{port}, - ReusePort => 1, - Timeout => 5 - ); - } elsif ($self->{config}->{ssl} eq 'true') { - $message_error = '$!, ssl_error=$IO::Socket::SSL::SSL_ERROR'; - $daemon = HTTP::Daemon::SSL->new( - LocalAddr => $self->{config}->{address} . ':' . $self->{config}->{port}, - SSL_cert_file => $self->{config}->{ssl_cert_file}, - SSL_key_file => $self->{config}->{ssl_key_file}, - SSL_error_trap => \&ssl_error, - ReusePort => 1, - Timeout => 5 - ); - } - - if (!defined($daemon)) { - eval "\$message_error = \"$message_error\""; - $connector->{logger}->writeLogError("[httpserver] can't construct socket: $message_error"); - exit(1); - } - - while (1) { - my ($connection) = $daemon->accept(); - - if ($self->{stop} == 1) { - $self->{logger}->writeLogInfo("[httpserver] $$ has quit"); - $connection->close() if (defined($connection)); - exit(0); - } - - if (!defined($connection)) { - $self->event(); - next; - } - - while (my $request = $connection->get_request) { - if ($connection->antique_client eq '1') { - $connection->force_last_request; - next; - } - - my $msg = "[httpserver] " . $connection->peerhost() . " " . $request->method . " '" . $request->uri->path . "'"; - $msg .= " '" . $request->header("User-Agent") . "'" if (defined($request->header("User-Agent")) && $request->header("User-Agent") ne ''); - $connector->{logger}->writeLogInfo($msg); - - if ($connector->{allowed_hosts_enabled} == 1) { - if ($connector->check_allowed_host(peer_addr => inet_ntoa($connection->peeraddr())) == 0) { - $connector->{logger}->writeLogError("[httpserver] " . $connection->peerhost() . " Unauthorized"); - $self->send_error( - connection => $connection, - code => "401", - response => '{"error":"http_error_401","message":"unauthorized"}' - ); - next; - } - } - - if ($self->authentication($request->header('Authorization'))) { # Check Basic authentication - my ($root) = ($request->uri->path =~ /^(\/\w+)/); - - if ($root eq "/api") { # API - $self->send_response(connection => $connection, response => $self->api_call($request)); - } elsif (defined($self->{dispatch}->{$root})) { # Other dispatch definition - $self->send_response(connection => $connection, response => $self->dispatch_call(root => $root, request => $request)); - } else { # Forbidden - $connector->{logger}->writeLogError("[httpserver] " . $connection->peerhost() . " '" . $request->uri->path . "' Forbidden"); - $self->send_error( - connection => $connection, - code => "403", - response => '{"error":"http_error_403","message":"forbidden"}' - ); - } - } else { # Authen error - $connector->{logger}->writeLogError("[httpserver] " . $connection->peerhost() . " Unauthorized"); - $self->send_error( - connection => $connection, - code => "401", - response => '{"error":"http_error_401","message":"unauthorized"}' - ); - } - $connection->force_last_request; - } - $connection->close; - undef($connection); - } -} - -sub ssl_error { - my ($self, $error) = @_; - - chomp $error; - $connector->{logger}->writeLogError("[httpserver] ssl error: $error"); - ${*$self}{httpd_client_proto} = 1000; - ${*$self}{httpd_daemon} = HTTP::Daemon::SSL::DummyDaemon->new(); - $self->send_error(RC_BAD_REQUEST); - $self->close(); -} - -sub authentication { - my ($self, $header) = @_; - - return 1 if ($self->{auth_enabled} == 0); - - return 0 if (!defined($header) || $header eq ''); - - ($header =~ /Basic\s(.*)$/); - my ($user, $password) = split(/:/, MIME::Base64::decode($1), 2); - return 1 if (defined($self->{config}->{auth}->{user}) && $user eq $self->{config}->{auth}->{user} && - defined($self->{config}->{auth}->{password}) && $password eq $self->{config}->{auth}->{password}); - - return 0; -} - -sub send_response { - my ($self, %options) = @_; - - if (defined($options{response}) && $options{response} ne '') { - my $http_code = 200; - eval { - # we don't want to raise an error if we can't find an http code or if we don't send back - # something else than a json, so we don't check $@ variable - my $content = JSON::XS->new->decode($options{response}); - if ($content->{http_response_code}){ - $http_code = $content->{http_response_code}; - delete($content->{http_response_code}); - $options{response} = JSON::XS->new->encode($content); - } - elsif ($content->{error}){ - $http_code = 400; - } - }; - - - my $response = HTTP::Response->new($http_code); - $response->header('Content-Type' => 'application/json'); - $response->content($options{response} . "\n"); - $options{connection}->send_response($response); - } else { - my $response = HTTP::Response->new(204); - $options{connection}->send_response($response); - } -} - -sub send_error { - my ($self, %options) = @_; - - my $response = HTTP::Response->new($options{code}); - $response->header('Content-Type' => 'application/json'); - $response->content($options{response} . "\n"); - $options{connection}->send_response($response); -} - -sub api_call { - my ($self, $request) = @_; - - my $content; - eval { - $content = JSON::XS->new->decode($request->content) - if ($request->method =~ /POST|PATCH/ && defined($request->content)); - }; - if ($@) { - return '{"error":"decode_error","message":"POST content must be JSON-formated","http_response_code":"400"}'; - } - - my %parameters = $request->uri->query_form; - my $response = gorgone::standard::api::root( - method => $request->method, - uri => $request->uri->path, - parameters => \%parameters, - content => $content, - socket => $connector->{internal_socket}, - logger => $self->{logger}, - api_endpoints => $self->{api_endpoints}, - module => $self - ); - - return $response; -} - -sub dispatch_call { - my ($self, %options) = @_; - - my $class = $self->{dispatch}->{$options{root}}->{class}; - my $method = $self->{dispatch}->{$options{root}}->{method}; - my $response; - eval { - (my $file = "$class.pm") =~ s|::|/|g; - require $file; - $response = $class->$method(request => $options{request}); - }; - if ($@) { - $response = $@; - }; - - return $response; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/httpserver/hooks.pm b/centreon-gorgone/gorgone/modules/core/httpserver/hooks.pm deleted file mode 100644 index 9f751180f6..0000000000 --- a/centreon-gorgone/gorgone/modules/core/httpserver/hooks.pm +++ /dev/null @@ -1,169 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::httpserver::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::httpserver::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'httpserver'; -use constant EVENTS => [ - { event => 'HTTPSERVERREADY' }, -]; - -my $config_core; -my $config; -my $httpserver = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - my $loaded = 1; - $config = $options{config}; - $config_core = $options{config_core}; - $config->{address} = defined($config->{address}) && $config->{address} ne '' ? $config->{address} : '0.0.0.0'; - $config->{port} = defined($config->{port}) && $config->{port} =~ /(\d+)/ ? $1 : 8080; - if (defined($config->{auth}->{enabled}) && $config->{auth}->{enabled} eq 'true') { - if (!defined($config->{auth}->{user}) || $config->{auth}->{user} =~ /^\s*$/) { - $options{logger}->writeLogError('[httpserver] User option mandatory if authentication is enabled'); - $loaded = 0; - } - if (!defined($config->{auth}->{password}) || $config->{auth}->{password} =~ /^\s*$/) { - $options{logger}->writeLogError('[httpserver] Password option mandatory if authentication is enabled'); - $loaded = 0; - } - } - - return ($loaded, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}, api_endpoints => $options{api_endpoints}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'HTTPSERVERREADY') { - $httpserver->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$httpserver->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgonehttpserver: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-httpserver', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($httpserver->{running}) && $httpserver->{running} == 1) { - $options{logger}->writeLogDebug("[httpserver] Send TERM signal $httpserver->{pid}"); - CORE::kill('TERM', $httpserver->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($httpserver->{running} == 1) { - $options{logger}->writeLogDebug("[httpserver] Send KILL signal for pool"); - CORE::kill('KILL', $httpserver->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($httpserver->{pid}) || $httpserver->{pid} != $pid); - - $httpserver = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}, api_endpoints => $options{api_endpoints}); - } - - last; - } - - $count++ if (defined($httpserver->{running}) && $httpserver->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[httpserver] Create module 'httpserver' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-httpserver'; - my $module = gorgone::modules::core::httpserver::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - api_endpoints => $options{api_endpoints} - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[httpserver] PID $child_pid (gorgone-httpserver)"); - $httpserver = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/httpserverng/class.pm b/centreon-gorgone/gorgone/modules/core/httpserverng/class.pm deleted file mode 100644 index 57ef32290a..0000000000 --- a/centreon-gorgone/gorgone/modules/core/httpserverng/class.pm +++ /dev/null @@ -1,726 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::httpserverng::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use Mojolicious::Lite; -use Mojo::Server::Daemon; -use Authen::Simple::Password; -use IO::Socket::SSL; -use IO::Handle; -use JSON::XS; -use IO::Poll qw(POLLIN POLLPRI); -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -websocket '/' => sub { - my $mojo = shift; - - $connector->{logger}->writeLogDebug('[httpserverng] websocket client connected: ' . $mojo->tx->connection); - - if ($connector->{allowed_hosts_enabled} == 1) { - if ($connector->check_allowed_host(peer_addr => $mojo->tx->remote_address) == 0) { - $connector->{logger}->writeLogError("[httpserverng] " . $mojo->tx->remote_address . " Unauthorized"); - $mojo->tx->send({json => { - code => 401, - message => 'unauthorized', - }}); - return ; - } - } - - $connector->{ws_clients}->{ $mojo->tx->connection } = { - tx => $mojo->tx, - logged => 0, - last_update => time(), - tokens => {} - }; - - $mojo->on(message => sub { - my ($mojo, $msg) = @_; - - $connector->{ws_clients}->{ $mojo->tx->connection }->{last_update} = time(); - - my $content; - eval { - $content = JSON::XS->new->decode($msg); - }; - if ($@) { - $connector->close_websocket( - code => 500, - message => 'decode error: unsupported format', - ws_id => $mojo->tx->connection - ); - return ; - } - - my $rv = $connector->is_logged_websocket(ws_id => $mojo->tx->connection, content => $content); - return if ($rv != 1); - - $connector->api_root_ws(ws_id => $mojo->tx->connection, content => $content); - }); - - $mojo->on(finish => sub { - my ($mojo, $code, $reason) = @_; - - $connector->{logger}->writeLogDebug('[httpserverng] websocket client disconnected: ' . $mojo->tx->connection); - $connector->clean_websocket(ws_id => $mojo->tx->connection, finish => 1); - }); -}; - -patch '/*' => sub { - my $mojo = shift; - - $connector->api_call( - mojo => $mojo, - method => 'PATCH' - ); -}; - -post '/*' => sub { - my $mojo = shift; - - $connector->api_call( - mojo => $mojo, - method => 'POST' - ); -}; - -get '/*' => sub { - my $mojo = shift; - - $connector->api_call( - mojo => $mojo, - method => 'GET' - ); -}; - -sub construct { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{api_endpoints} = $options{api_endpoints}; - $connector->{auth_enabled} = (defined($connector->{config}->{auth}->{enabled}) && $connector->{config}->{auth}->{enabled} eq 'true') ? 1 : 0; - $connector->{allowed_hosts_enabled} = (defined($connector->{config}->{allowed_hosts}->{enabled}) && $connector->{config}->{allowed_hosts}->{enabled} eq 'true') ? 1 : 0; - $connector->{clients} = {}; - $connector->{token_watch} = {}; - $connector->{ws_clients} = {}; - - if (gorgone::standard::misc::mymodule_load( - logger => $connector->{logger}, - module => 'NetAddr::IP', - error_msg => "[httpserverng] -class- cannot load module 'NetAddr::IP'. Cannot use allowed_hosts configuration.") - ) { - $connector->{allowed_hosts_enabled} = 0; - } - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[httpserverng] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub check_allowed_host { - my ($self, %options) = @_; - - my $subnet = NetAddr::IP->new($options{peer_addr} . '/32'); - foreach (@{$self->{peer_subnets}}) { - return 1 if ($_->contains($subnet)); - } - - return 0; -} - -sub load_peer_subnets { - my ($self, %options) = @_; - - return if ($self->{allowed_hosts_enabled} == 0); - - $self->{peer_subnets} = []; - return if (!defined($connector->{config}->{allowed_hosts}->{subnets})); - - foreach (@{$self->{config}->{allowed_hosts}->{subnets}}) { - my $subnet = NetAddr::IP->new($_); - if (!defined($subnet)) { - $self->{logger}->writeLogError("[httpserverng] Cannot load subnet: $_"); - next; - } - - push @{$self->{peer_subnets}}, $subnet; - } -} - -sub run { - my ($self, %options) = @_; - - $self->load_peer_subnets(); - - my $listen = 'reuse=1'; - if ($self->{config}->{ssl} eq 'true') { - if (!defined($self->{config}->{ssl_cert_file}) || $self->{config}->{ssl_cert_file} eq '' || - ! -r "$self->{config}->{ssl_cert_file}") { - $connector->{logger}->writeLogError("[httpserverng] cannot read/find ssl-cert-file"); - exit(1); - } - if (!defined($self->{config}->{ssl_key_file}) || $self->{config}->{ssl_key_file} eq '' || - ! -r "$self->{config}->{ssl_key_file}") { - $connector->{logger}->writeLogError("[httpserverng] cannot read/find ssl-key-file"); - exit(1); - } - $listen .= '&cert=' . $self->{config}->{ssl_cert_file} . '&key=' . $self->{config}->{ssl_key_file}; - } - my $proto = 'http'; - if ($self->{config}->{ssl} eq 'true') { - $proto = 'https'; - if (defined($self->{config}->{passphrase}) && $self->{config}->{passphrase} ne '') { - IO::Socket::SSL::set_defaults(SSL_passwd_cb => sub { return $connector->{config}->{passphrase} } ); - } - } - - # Connect internal - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $connector->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-httpserverng', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'HTTPSERVERNGREADY', - data => {} - }); - $self->read_zmq_events(); - - my $type = ref(Mojo::IOLoop->singleton->reactor); - my $watcher_io; - if ($type eq 'Mojo::Reactor::Poll') { - Mojo::IOLoop->singleton->reactor->{io}{ $self->{internal_socket}->get_fd()} = { - cb => sub { $connector->read_zmq_events(); }, - mode => POLLIN | POLLPRI - }; - } else { - # need EV version 4.32 - $watcher_io = EV::io( - $self->{internal_socket}->get_fd(), - EV::READ, - sub { - $connector->read_zmq_events(); - } - ); - } - - #my $socket_fd = gorgone::standard::library::zmq_getfd(socket => $self->{internal_socket}); - #my $socket = IO::Handle->new_from_fd($socket_fd, 'r'); - #Mojo::IOLoop->singleton->reactor->io($socket => sub { - # $connector->read_zmq_events(); - #}); - #Mojo::IOLoop->singleton->reactor->watch($socket, 1, 0); - - Mojo::IOLoop->singleton->recurring(60 => sub { - $connector->{logger}->writeLogDebug('[httpserverng] recurring timeout loop'); - my $ctime = time(); - foreach my $ws_id (keys %{$connector->{ws_clients}}) { - if (scalar(keys %{$connector->{ws_clients}->{$ws_id}->{tokens}}) <= 0 && ($ctime - $connector->{ws_clients}->{$ws_id}->{last_update}) > 300) { - $connector->{logger}->writeLogDebug('[httpserverng] websocket client timeout reached: ' . $ws_id); - $connector->close_websocket( - code => 500, - message => 'timeout reached', - ws_id => $ws_id - ); - } - } - }); - - $self->{basic_auth_plus} = 1; - eval { - local $SIG{__DIE__} = 'IGNORE'; - - app->plugin('basic_auth_plus'); - }; - if ($@) { - $self->{basic_auth_plus} = 0; - } - if ($self->{auth_enabled} == 1 && $self->{basic_auth_plus} == 0 && $self->{allowed_hosts_enabled} == 0) { - $connector->{logger}->writeLogError("[httpserverng] need to install the module basic_auth_plus"); - exit(1); - } - - app->mode('production'); - my $daemon = Mojo::Server::Daemon->new( - app => app, - listen => [$proto . '://' . $self->{config}->{address} . ':' . $self->{config}->{port} . '?' . $listen] - ); - # more than 2 minutes, need to use async system - $daemon->inactivity_timeout(120); - - #my $loop = Mojo::IOLoop->new(); - #my $reactor = Mojo::Reactor::EV->new(); - #$reactor->io($socket => sub { - # my $message = gorgone::standard::library::zmq_dealer_read_message(socket => $connector->{internal_socket}); - #}); - #$reactor->watch($socket, 1, 0); - #$loop->reactor($reactor); - #$daemon->ioloop($loop); - - $daemon->run(); - - exit(0); -} - -sub read_log_event { - my ($self, %options) = @_; - - my $token = $options{token}; - $token =~ s/-log$//; - my $response = { error => 'no_log', message => 'No log found for token', data => [], token => $token }; - if (defined($options{data})) { - my $content; - eval { - $content = JSON::XS->new->decode($options{data}); - }; - if ($@) { - $response = { error => 'decode_error', message => 'Cannot decode response' }; - } elsif (defined($content->{data}->{result}) && scalar(@{$content->{data}->{result}}) > 0) { - $response = { - message => 'Logs found', - token => $token, - data => $content->{data}->{result} - }; - } - } - - if (defined($self->{token_watch}->{ $options{token} }->{ws_id})) { - $response->{userdata} = $self->{token_watch}->{ $options{token} }->{userdata}; - $self->{ws_clients}->{ $self->{token_watch}->{ $options{token} }->{ws_id} }->{last_update} = time(); - $self->{ws_clients}->{ $self->{token_watch}->{ $options{token} }->{ws_id} }->{tx}->send({json => $response }); - delete $self->{ws_clients}->{ $self->{token_watch}->{ $options{token} }->{ws_id} }->{tokens}->{ $options{token} }; - } else { - $self->{token_watch}->{ $options{token} }->{mojo}->render(json => $response); - } - delete $self->{token_watch}->{ $options{token} }; -} - -sub read_listener { - my ($self, %options) = @_; - - my $content; - eval { - $content = JSON::XS->new->decode($options{data}); - }; - if ($@) { - $self->{token_watch}->{ $options{token} }->{mojo}->render(json => { error => 'decode_error', message => 'Cannot decode response' }); - delete $self->{token_watch}->{ $options{token} }; - return ; - } - - push @{$self->{token_watch}->{ $options{token} }->{results}}, $content; - if (defined($self->{token_watch}->{ $options{token} }->{ws_id})) { - $self->{ws_clients}->{ $self->{token_watch}->{ $options{token} }->{ws_id} }->{last_update} = time(); - } - - if ($content->{code} == GORGONE_ACTION_FINISH_KO || $content->{code} == GORGONE_ACTION_FINISH_OK) { - my $json = { data => $self->{token_watch}->{ $options{token} }->{results} }; - if (defined($self->{token_watch}->{ $options{token} }->{internal}) && $content->{code} == GORGONE_ACTION_FINISH_OK) { - $json = $content->{data}; - } - - if (defined($self->{token_watch}->{ $options{token} }->{ws_id})) { - $json->{userdata} = $self->{token_watch}->{ $options{token} }->{userdata}; - $self->{ws_clients}->{ $self->{token_watch}->{ $options{token} }->{ws_id} }->{tx}->send({json => $json }); - delete $self->{ws_clients}->{ $self->{token_watch}->{ $options{token} }->{ws_id} }->{tokens}->{ $options{token} }; - } else { - $self->{token_watch}->{ $options{token} }->{mojo}->render(json => $json); - } - delete $self->{token_watch}->{ $options{token} }; - } -} - -sub read_zmq_events { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($message) = $connector->read_message(); - $connector->{logger}->writeLogDebug('[httpserverng] zmq message received: ' . $message); - if ($message =~ /^\[(.*?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)$/m || - $message =~ /^\[(.*?)\]\s+\[(.*?)\]\s+(.*)$/m) { - my ($action, $token, $data) = ($1, $2, $3); - if (defined($connector->{token_watch}->{$token})) { - if ($action eq 'HTTPSERVERNGLISTENER') { - $connector->read_listener(token => $token, data => $data); - } elsif ($token =~ /-log$/) { - $connector->read_log_event(token => $token, data => $data); - } - } - if ((my $method = $connector->can('action_' . lc($action)))) { - my ($rv, $decoded) = $connector->json_decode(argument => $data, token => $token); - if (!$rv) { - $method->($connector, token => $token, data => $decoded); - } - } - } - } -} - -sub api_call { - my ($self, %options) = @_; - - if ($self->{allowed_hosts_enabled} == 1) { - if ($self->check_allowed_host(peer_addr => $options{mojo}->tx->remote_address) == 0) { - $connector->{logger}->writeLogError("[httpserverng] " . $options{mojo}->tx->remote_address . " Unauthorized"); - return $options{mojo}->render(json => { message => 'unauthorized' }, status => 401); - } - } - - if ($self->{auth_enabled} == 1 && $self->{basic_auth_plus} == 1) { - my ($hash_ref, $auth_ok) = $options{mojo}->basic_auth( - 'Realm Name' => { - username => $self->{config}->{auth}->{user}, - password => $self->{config}->{auth}->{password} - } - ); - if (!$auth_ok) { - return $options{mojo}->render(json => { message => 'unauthorized' }, status => 401); - } - } - - my $path = $options{mojo}->tx->req->url->path; - my $names = $options{mojo}->req->params->names(); - my $params = {}; - foreach (@$names) { - $params->{$_} = $options{mojo}->param($_); - } - - my $content = $options{mojo}->req->json(); - - $self->api_root( - mojo => $options{mojo}, - method => $options{method}, - uri => $path, - parameters => $params, - content => $content - ); -} - -sub get_log { - my ($self, %options) = @_; - - if (defined($options{target}) && $options{target} ne '') { - $self->send_internal_action({ - target => $options{target}, - action => 'GETLOG', - data => {} - }); - $self->read_zmq_events(); - } - - my $token_log = $options{token} . '-log'; - - if (defined($options{ws_id})) { - $self->{ws_clients}->{ $options{ws_id} }->{tokens}->{$token_log} = 1; - } - $self->{token_watch}->{$token_log} = { - ws_id => $options{ws_id}, - userdata => $options{userdata}, - mojo => $options{mojo} - }; - - $self->send_internal_action({ - action => 'GETLOG', - token => $token_log, - data => { - token => $options{token}, - %{$options{parameters}} - } - }); - - $self->read_zmq_events(); - - # keep reference tx to avoid "Transaction already destroyed" - $self->{token_watch}->{$token_log}->{tx} = $options{mojo}->render_later()->tx if (!defined($options{ws_id})); -} - -sub call_action { - my ($self, %options) = @_; - - my $action_token = gorgone::standard::library::generate_token(); - - if ($options{async} == 0) { - if (defined($options{ws_id})) { - $self->{ws_clients}->{ $options{ws_id} }->{tokens}->{$action_token} = 1; - } - $self->{token_watch}->{$action_token} = { - ws_id => $options{ws_id}, - userdata => $options{userdata}, - mojo => $options{mojo}, - internal => $options{internal}, - results => [] - }; - - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgone-httpserverng', - event => 'HTTPSERVERNGLISTENER', - token => $action_token, - target => $options{target}, - log_pace => 5, - timeout => 110 - } - ] - }); - $self->read_zmq_events(); - } - - $self->send_internal_action({ - action => $options{action}, - target => $options{target}, - token => $action_token, - data => $options{data} - }); - $self->read_zmq_events(); - - if ($options{async} == 1) { - $options{mojo}->render(json => { token => $action_token }, status => 200); - } else { - # keep reference tx to avoid "Transaction already destroyed" - $self->{token_watch}->{$action_token}->{tx} = $options{mojo}->render_later()->tx if (!defined($options{ws_id})); - } -} - -sub is_logged_websocket { - my ($self, %options) = @_; - - return 1 if ($self->{ws_clients}->{ $options{ws_id} }->{logged} == 1); - - if ($self->{auth_enabled} == 1) { - if (!defined($options{content}->{username}) || $options{content}->{username} eq '' || - !defined($options{content}->{password}) || $options{content}->{password} eq '') { - $self->close_websocket( - code => 500, - message => 'please set username/password', - ws_id => $options{ws_id} - ); - return 0; - } - - unless ($options{content}->{username} eq $self->{config}->{auth}->{user} && - Authen::Simple::Password->check($options{content}->{password}, $self->{config}->{auth}->{password})) { - $self->close_websocket( - code => 401, - message => 'unauthorized user', - ws_id => $options{ws_id} - ); - return 0; - } - } - - $self->{ws_clients}->{ $options{ws_id} }->{logged} = 1; - return 2; -} - -sub clean_websocket { - my ($self, %options) = @_; - - return if (!defined($self->{ws_clients}->{ $options{ws_id} })); - - $self->{ws_clients}->{ $options{ws_id} }->{tx}->finish() if (!defined($options{finish})); - foreach (keys %{$self->{ws_clients}->{ $options{ws_id} }->{tokens}}) { - delete $self->{token_watch}->{$_}; - } - delete $self->{ws_clients}->{ $options{ws_id} }; -} - -sub close_websocket { - my ($self, %options) = @_; - - $self->{ws_clients}->{ $options{ws_id} }->{tx}->send({json => { - code => $options{code}, - message => $options{message} - }}); - $self->clean_websocket(ws_id => $options{ws_id}); -} - -sub api_root_ws { - my ($self, %options) = @_; - - if (!defined($options{content}->{method})) { - $self->{ws_clients}->{ $options{ws_id} }->{tx}->send({json => { - code => 500, - message => 'unknown method', - userdata => $options{content}->{userdata} - }}); - return ; - } - if (!defined($options{content}->{uri})) { - $self->{ws_clients}->{ $options{ws_id} }->{tx}->send({json => { - code => 500, - message => 'unknown uri', - userdata => $options{content}->{userdata} - }}); - return ; - } - - $self->{logger}->writeLogInfo("[api] Requesting '" . $options{content}->{uri} . "' [" . $options{content}->{method} . "]"); - - if ($options{content}->{method} eq 'GET' && $options{content}->{uri} =~ /^\/api\/log\/?$/) { - $self->get_log( - ws_id => $options{ws_id}, - userdata => $options{content}->{userdata}, - target => $options{target}, - token => $options{content}->{token}, - parameters => $options{content}->{parameters} - ); - } elsif ($options{content}->{uri} =~ /^\/internal\/(\w+)\/?$/ - && defined($self->{api_endpoints}->{ $options{content}->{method} . '_/internal/' . $1 })) { - $self->call_action( - ws_id => $options{ws_id}, - userdata => $options{content}->{userdata}, - async => 0, - action => $self->{api_endpoints}->{ $options{content}->{method} . '_/internal/' . $1 }, - internal => $1, - target => $options{target}, - data => { - content => $options{content}->{data}, - parameters => $options{content}->{parameters}, - variables => $options{content}->{variable} - } - ); - } elsif ($options{content}->{uri} =~ /^\/(\w+)\/(\w+)\/(\w+)\/?$/ - && defined($self->{api_endpoints}->{ $options{content}->{method} . '_/' . $1 . '/' . $2 . '/' . $3 })) { - $self->call_action( - ws_id => $options{ws_id}, - userdata => $options{content}->{userdata}, - async => 0, - action => $self->{api_endpoints}->{ $options{content}->{method} . '_/' . $1 . '/' . $2 . '/' . $3 }, - target => $options{target}, - data => { - content => $options{content}->{data}, - parameters => $options{content}->{parameters}, - variables => $options{content}->{variable} - } - ); - } else { - $self->{ws_clients}->{ $options{ws_id} }->{tx}->send({json => { - code => 500, - message => 'method not implemented', - userdata => $options{userdata} - }}); - } -} - -sub api_root { - my ($self, %options) = @_; - - $self->{logger}->writeLogInfo("[api] Requesting '" . $options{uri} . "' [" . $options{method} . "]"); - - my $async = 0; - $async = 1 if (defined($options{parameters}->{async}) && $options{parameters}->{async} == 1); - - # async mode: - # provide the token directly and close the connection. need to call GETLOG on the token - # not working with GETLOG - - # listener is used for other case. - - if ($options{method} eq 'GET' && $options{uri} =~ /^\/api\/(nodes\/(\w*)\/)?log\/(.*)$/) { - $self->get_log( - mojo => $options{mojo}, - target => $2, - token => $3, - parameters => $options{parameters} - ); - } elsif ($options{uri} =~ /^\/api\/(nodes\/(\w*)\/)?internal\/(\w+)\/?([\w\/]*?)$/ - && defined($self->{api_endpoints}->{ $options{method} . '_/internal/' . $3 })) { - my @variables = split(/\//, $4); - $self->call_action( - mojo => $options{mojo}, - async => $async, - action => $self->{api_endpoints}->{ $options{method} . '_/internal/' . $3 }, - internal => $3, - target => $2, - data => { - content => $options{content}, - parameters => $options{parameters}, - variables => \@variables - } - ); - } elsif ($options{uri} =~ /^\/api\/(nodes\/(\w*)\/)?(\w+)\/(\w+)\/(\w+)\/?([\w\/]*?)$/ - && defined($self->{api_endpoints}->{ $options{method} . '_/' . $3 . '/' . $4 . '/' . $5 })) { - my @variables = split(/\//, $6); - $self->call_action( - mojo => $options{mojo}, - async => $async, - action => $self->{api_endpoints}->{ $options{method} . '_/' . $3 . '/' . $4 . '/' . $5 }, - target => $2, - data => { - content => $options{content}, - parameters => $options{parameters}, - variables => \@variables - } - ); - } else { - $options{mojo}->render(json => { error => 'method_unknown', message => 'Method not implemented' }, status => 200); - return ; - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/httpserverng/hooks.pm b/centreon-gorgone/gorgone/modules/core/httpserverng/hooks.pm deleted file mode 100644 index 14525e1c74..0000000000 --- a/centreon-gorgone/gorgone/modules/core/httpserverng/hooks.pm +++ /dev/null @@ -1,170 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::httpserverng::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::httpserverng::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'httpserverng'; -use constant EVENTS => [ - { event => 'HTTPSERVERNGLISTENER' }, - { event => 'HTTPSERVERNGREADY' } -]; - -my $config_core; -my $config; -my $httpserverng = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - my $loaded = 1; - $config = $options{config}; - $config_core = $options{config_core}; - $config->{address} = defined($config->{address}) && $config->{address} ne '' ? $config->{address} : '0.0.0.0'; - $config->{port} = defined($config->{port}) && $config->{port} =~ /(\d+)/ ? $1 : 8080; - if (defined($config->{auth}->{enabled}) && $config->{auth}->{enabled} eq 'true') { - if (!defined($config->{auth}->{user}) || $config->{auth}->{user} =~ /^\s*$/) { - $options{logger}->writeLogError('[httpserverng] User option mandatory if authentication is enabled'); - $loaded = 0; - } - if (!defined($config->{auth}->{password}) || $config->{auth}->{password} =~ /^\s*$/) { - $options{logger}->writeLogError('[httpserverng] Password option mandatory if authentication is enabled'); - $loaded = 0; - } - } - - return ($loaded, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}, api_endpoints => $options{api_endpoints}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'HTTPSERVERNGREADY') { - $httpserverng->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$httpserverng->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-httpserverng: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-httpserverng', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($httpserverng->{running}) && $httpserverng->{running} == 1) { - $options{logger}->writeLogDebug("[httpserverng] Send TERM signal $httpserverng->{pid}"); - CORE::kill('TERM', $httpserverng->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($httpserverng->{running} == 1) { - $options{logger}->writeLogDebug("[httpserverng] Send KILL signal for pool"); - CORE::kill('KILL', $httpserverng->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($httpserverng->{pid}) || $httpserverng->{pid} != $pid); - - $httpserverng = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}, api_endpoints => $options{api_endpoints}); - } - - last; - } - - $count++ if (defined($httpserverng->{running}) && $httpserverng->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[httpserverng] Create module 'httpserverng' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-httpserverng'; - my $module = gorgone::modules::core::httpserverng::class->construct( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - api_endpoints => $options{api_endpoints} - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[httpserverng] PID $child_pid (gorgone-httpserverng)"); - $httpserverng = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/pipeline/class.pm b/centreon-gorgone/gorgone/modules/core/pipeline/class.pm deleted file mode 100644 index bb80a24b0c..0000000000 --- a/centreon-gorgone/gorgone/modules/core/pipeline/class.pm +++ /dev/null @@ -1,244 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::pipeline::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::class::db; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use JSON::XS; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{timeout} = 600; - $connector->{pipelines} = {}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[pipeline] -class- $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub send_listener { - my ($self, %options) = @_; - - my $current = $self->{pipelines}->{ $options{token} }->{current}; - - $self->{pipelines}->{ $options{token} }->{pipe}->[$current]->{created} = time(); - $self->send_internal_action({ - action => 'ADDLISTENER', - data => [ - { - identity => 'gorgonepipeline', - event => 'PIPELINELISTENER', - target => $self->{pipelines}->{ $options{token} }->{pipe}->[$current]->{target}, - token => $options{token} . '-' . $current, - timeout => $self->{pipelines}->{ $options{token} }->{pipe}->[$current]->{timeout}, - log_pace => $self->{pipelines}->{ $options{token} }->{pipe}->[$current]->{log_pace} - } - ] - }); - - $self->send_internal_action({ - action => $self->{pipelines}->{ $options{token} }->{pipe}->[$current]->{action}, - target => $self->{pipelines}->{ $options{token} }->{pipe}->[$current]->{target}, - token => $options{token} . '-' . $current, - data => $self->{pipelines}->{ $options{token} }->{pipe}->[$current]->{data} - }); - - $self->{logger}->writeLogDebug("[pipeline] -class- pipeline '$options{token}' run $current"); - $self->send_log( - code => GORGONE_MODULE_PIPELINE_RUN_ACTION, - token => $options{token}, - data => { message => 'proceed action ' . ($current + 1), token => $options{token} . '-' . $current } - ); -} - -sub action_addpipeline { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - #[ - # { "action": "COMMAND", "data": { "content": [ { "command": "ls" } ] }, "continue": "ok", "continue_custom": "%{last_exit_code} == 1" }, // By default for COMMAND: "continue": "%{last_exit_code} == 0" - # { "action:" "COMMAND", "target": 10, "timeout": 60, "log_pace": 10, "data": { [ "content": { "command": "ls /tmp" } ] } } - #] - - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action addpipeline proceed' }); - - $self->{pipelines}->{$options{token}} = { current => 0, pipe => $options{data} }; - $self->send_listener(token => $options{token}); - - return 0; -} - -sub action_pipelinelistener { - my ($self, %options) = @_; - - return 0 if (!defined($options{token}) || $options{token} !~ /^(.*)-(\d+)$/); - my ($token, $current_event) = ($1, $2); - - return 0 if (!defined($self->{pipelines}->{ $token })); - my $current = $self->{pipelines}->{$token}->{current}; - return 0 if ($current != $current_event); - - if ($self->{pipelines}->{$token}->{pipe}->[$current]->{action} eq 'COMMAND') { - # we want to catch exit_code for command results - if ($options{data}->{code} == GORGONE_MODULE_ACTION_COMMAND_RESULT) { - $self->{pipelines}->{$token}->{pipe}->[$current]->{last_exit_code} = $options{data}->{data}->{result}->{exit_code}; - $self->{pipelines}->{$token}->{pipe}->[$current]->{total_exit_code} += $options{data}->{data}->{result}->{exit_code} - if (!defined($self->{pipelines}->{$token}->{pipe}->[$current]->{total_exit_code})); - return 0; - } - } - - return 0 if ($options{data}->{code} != GORGONE_ACTION_FINISH_OK && $options{data}->{code} != GORGONE_ACTION_FINISH_KO); - - my $continue = GORGONE_ACTION_FINISH_OK; - if (defined($self->{pipelines}->{$token}->{pipe}->[$current]->{continue}) && - $self->{pipelines}->{$token}->{pipe}->[$current]->{continue} eq 'ko') { - $continue = GORGONE_ACTION_FINISH_KO; - } - - my $success = 1; - if ($options{data}->{code} != $continue) { - $success = 0; - } - if ($self->{pipelines}->{$token}->{pipe}->[$current]->{action} eq 'COMMAND') { - my $eval = '%{last_exit_code} == 0'; - $eval = $self->{pipelines}->{$token}->{pipe}->[$current]->{continue_continue_custom} - if (defined($self->{pipelines}->{$token}->{pipe}->[$current]->{continue_continue_custom})); - $eval = $self->change_macros( - template => $eval, - macros => { - total_exit_code => '$self->{pipelines}->{$token}->{pipe}->[$current]->{total_exit_code}', - last_exit_code => '$self->{pipelines}->{$token}->{pipe}->[$current]->{last_exit_code}' - } - ); - if (! eval "$eval") { - $success = 0; - } - } - - if ($success == 0) { - $self->{logger}->writeLogDebug("[pipeline] -class- pipeline '$token' failed at $current"); - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $token, data => { message => 'action pipeline failed' }); - delete $self->{pipelines}->{$token}; - } else { - if (defined($self->{pipelines}->{$token}->{pipe}->[$current + 1])) { - $self->{pipelines}->{$token}->{current}++; - $self->send_listener(token => $token); - } else { - $self->{logger}->writeLogDebug("[pipeline] -class- pipeline '$token' finished successfully"); - $self->send_log(code => GORGONE_ACTION_FINISH_OK, token => $token, data => { message => 'action pipeline finished successfully' }); - delete $self->{pipelines}->{$token}; - } - } - - return 0; -} - -sub check_timeout { - my ($self, %options) = @_; - - foreach (keys %{$self->{pipelines}}) { - my $current = $self->{pipelines}->{$_}->{current}; - my $timeout = defined($self->{pipelines}->{$_}->{pipe}->[$current]->{timeout}) && $self->{pipelines}->{$_}->{pipe}->[$current]->{timeout} =~ /(\d+)/ ? - $1 : $self->{timeout}; - - if ((time() - $self->{pipelines}->{$_}->{pipe}->[$current]->{created}) > $timeout) { - $self->{logger}->writeLogDebug("[pipeline] -class- delete pipeline '$_' timeout"); - delete $self->{pipelines}->{$_}; - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $_, data => { message => 'pipeline timeout reached' }); - } - } -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[pipeline] -class- $$ has quit"); - exit(0); - } - - $connector->check_timeout(); -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-pipeline', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'PIPELINEREADY', - data => {} - }); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/pipeline/hooks.pm b/centreon-gorgone/gorgone/modules/core/pipeline/hooks.pm deleted file mode 100644 index 83aed872a2..0000000000 --- a/centreon-gorgone/gorgone/modules/core/pipeline/hooks.pm +++ /dev/null @@ -1,164 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::pipeline::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::pipeline::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'pipeline'; -use constant EVENTS => [ - { event => 'PIPELINEREADY' }, - { event => 'PIPELINELISTENER' }, - { event => 'ADDPIPELINE', uri => '/definitions', method => 'POST' }, -]; - -my $config_core; -my $config; -my $pipeline = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config->{purge_sessions_time} = - defined($config->{purge_sessions_time}) && $config->{purge_sessions_time} =~ /(\d+)/ ? - $1 : - 3600 - ; - $config->{purge_history_time} = - defined($config->{purge_history_time}) && $config->{purge_history_time} =~ /(\d+)/ ? - $1 : - 604800 - ; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'PIPELINEREADY') { - $pipeline->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$pipeline->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-pipeline: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-pipeline', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($pipeline->{running}) && $pipeline->{running} == 1) { - $options{logger}->writeLogDebug("[pipeline] Send TERM signal $pipeline->{pid}"); - CORE::kill('TERM', $pipeline->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($pipeline->{running} == 1) { - $options{logger}->writeLogDebug('[pipeline] Send KILL signal for subprocess'); - CORE::kill('KILL', $pipeline->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($pipeline->{pid}) || $pipeline->{pid} != $pid); - - $pipeline = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($pipeline->{running}) && $pipeline->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[pipeline] Create module 'pipeline' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-pipeline'; - my $module = gorgone::modules::core::pipeline::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[pipeline] PID $child_pid (gorgone-pipeline)"); - $pipeline = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/proxy/class.pm b/centreon-gorgone/gorgone/modules/core/proxy/class.pm deleted file mode 100644 index de525cd98e..0000000000 --- a/centreon-gorgone/gorgone/modules/core/proxy/class.pm +++ /dev/null @@ -1,548 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::proxy::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::clientzmq; -use gorgone::modules::core::proxy::sshclient; -use JSON::XS; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{pool_id} = $options{pool_id}; - $connector->{clients} = {}; - $connector->{internal_channels} = {}; - $connector->{watchers} = {}; - - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogInfo("[proxy] $$ Receiving order to stop..."); - $self->{stop} = 1; - $self->{stop_time} = time(); -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub exit_process { - my ($self, %options) = @_; - - $self->{logger}->writeLogInfo("[proxy] $$ has quit"); - $self->close_connections(); - foreach (keys %{$self->{internal_channels}}) { - $self->{logger}->writeLogInfo("[proxy] Close internal connection for $_"); - $self->{internal_channels}->{$_}->close(); - } - $self->{logger}->writeLogInfo("[proxy] Close control connection"); - $self->{internal_socket}->close(); - exit(0); -} - -sub read_message_client { - my (%options) = @_; - - return undef if (!defined($options{identity}) || $options{identity} !~ /^gorgone-proxy-(.*?)-(.*?)$/); - - my ($client_identity) = ($2); - if ($options{data} =~ /^\[PONG\]/) { - if ($options{data} !~ /^\[(.+?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)/m) { - return undef; - } - my ($action, $token) = ($1, $2); - my ($code, $data) = $connector->json_decode(argument => $3); - return undef if ($code == 1); - - $data->{data}->{id} = $client_identity; - - # if we get a pong response, we can open the internal com read - $connector->{clients}->{ $client_identity }->{com_read_internal} = 1; - $connector->send_internal_action({ - action => 'PONG', - data => $data, - token => $token, - target => '' - }); - } elsif ($options{data} =~ /^\[(?:REGISTERNODES|UNREGISTERNODES|SYNCLOGS)\]/) { - if ($options{data} !~ /^\[(.+?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)/ms) { - return undef; - } - my ($action, $token, $data) = ($1, $2, $3); - - $connector->send_internal_action({ - action => $action, - data => $data, - data_noencode => 1, - token => $token, - target => '' - }); - } elsif ($options{data} =~ /^\[ACK\]\s+\[(.*?)\]\s+(.*)/ms) { - my ($code, $data) = $connector->json_decode(argument => $2); - return undef if ($code == 1); - - # we set the id (distant node can not have id in configuration) - $data->{data}->{id} = $client_identity; - if (defined($data->{data}->{action}) && $data->{data}->{action} eq 'getlog') { - $connector->send_internal_action({ - action => 'SETLOGS', - data => $data, - token => $1, - target => '' - }); - } - } -} - -sub connect { - my ($self, %options) = @_; - - if ($self->{clients}->{$options{id}}->{type} eq 'push_zmq') { - $self->{clients}->{$options{id}}->{class} = gorgone::class::clientzmq->new( - context => $self->{zmq_context}, - core_loop => $self->{loop}, - identity => 'gorgone-proxy-' . $self->{core_id} . '-' . $options{id}, - cipher => $self->{clients}->{ $options{id} }->{cipher}, - vector => $self->{clients}->{ $options{id} }->{vector}, - client_pubkey => - defined($self->{clients}->{ $options{id} }->{client_pubkey}) && $self->{clients}->{ $options{id} }->{client_pubkey} ne '' - ? $self->{clients}->{ $options{id} }->{client_pubkey} : $self->get_core_config(name => 'pubkey'), - client_privkey => - defined($self->{clients}->{ $options{id} }->{client_privkey}) && $self->{clients}->{ $options{id} }->{client_privkey} ne '' - ? $self->{clients}->{ $options{id} }->{client_privkey} : $self->get_core_config(name => 'privkey'), - target_type => defined($self->{clients}->{ $options{id} }->{target_type}) ? - $self->{clients}->{ $options{id} }->{target_type} : - 'tcp', - target_path => defined($self->{clients}->{ $options{id} }->{target_path}) ? - $self->{clients}->{ $options{id} }->{target_path} : - $self->{clients}->{ $options{id} }->{address} . ':' . $self->{clients}->{ $options{id} }->{port}, - config_core => $self->get_core_config(), - logger => $self->{logger} - ); - $self->{clients}->{ $options{id} }->{class}->init(callback => \&read_message_client); - } elsif ($self->{clients}->{ $options{id} }->{type} eq 'push_ssh') { - $self->{clients}->{$options{id}}->{class} = gorgone::modules::core::proxy::sshclient->new(logger => $self->{logger}); - my $code = $self->{clients}->{$options{id}}->{class}->open_session( - ssh_host => $self->{clients}->{$options{id}}->{address}, - ssh_port => $self->{clients}->{$options{id}}->{ssh_port}, - ssh_username => $self->{clients}->{$options{id}}->{ssh_username}, - ssh_password => $self->{clients}->{$options{id}}->{ssh_password}, - ssh_directory => $self->{clients}->{$options{id}}->{ssh_directory}, - ssh_known_hosts => $self->{clients}->{$options{id}}->{ssh_known_hosts}, - ssh_identity => $self->{clients}->{$options{id}}->{ssh_identity}, - strict_serverkey_check => $self->{clients}->{$options{id}}->{strict_serverkey_check}, - ssh_connect_timeout => $self->{clients}->{$options{id}}->{ssh_connect_timeout} - ); - if ($code != 0) { - $self->{clients}->{ $options{id} }->{delete} = 1; - return -1; - } - } - - return 0; -} - -sub action_proxyaddnode { - my ($self, %options) = @_; - - my ($code, $data) = $self->json_decode(argument => $options{data}); - return if ($code == 1); - - if (defined($self->{clients}->{ $data->{id} }->{class})) { - # test if a connection parameter changed - my $changed = 0; - foreach (keys %$data) { - if (ref($data->{$_}) eq '' && (!defined($self->{clients}->{ $data->{id} }->{$_}) || $data->{$_} ne $self->{clients}->{ $data->{id} }->{$_})) { - $changed = 1; - last; - } - } - - if ($changed == 0) { - $self->{logger}->writeLogInfo("[proxy] Session not changed $data->{id}"); - return ; - } - - $self->{logger}->writeLogInfo("[proxy] Recreate session for $data->{id}"); - # we send a pong reset. because the ping can be lost - $self->send_internal_action({ - action => 'PONGRESET', - data => '{ "data": { "id": ' . $data->{id} . ' } }', - data_noencode => 1, - token => $self->generate_token(), - target => '' - }); - - $self->{clients}->{ $data->{id} }->{class}->close(); - } else { - $self->{internal_channels}->{ $data->{id} } = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-proxy-channel-' . $data->{id}, - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'PROXYREADY', - data => { - node_id => $data->{id} - } - }); - $self->{watchers}->{ $data->{id} } = $self->{loop}->io( - $self->{internal_channels}->{ $data->{id} }->get_fd(), - EV::READ, - sub { - $connector->event(channel => $data->{id}); - } - ); - } - - $self->{clients}->{ $data->{id} } = $data; - $self->{clients}->{ $data->{id} }->{delete} = 0; - $self->{clients}->{ $data->{id} }->{class} = undef; - $self->{clients}->{ $data->{id} }->{com_read_internal} = 1; -} - -sub action_proxydelnode { - my ($self, %options) = @_; - - my ($code, $data) = $self->json_decode(argument => $options{data}); - return if ($code == 1); - - if (defined($self->{clients}->{$data->{id}})) { - $self->{clients}->{ $data->{id} }->{delete} = 1; - } -} - -sub action_proxycloseconnection { - my ($self, %options) = @_; - - my ($code, $data) = $self->json_decode(argument => $options{data}); - return if ($code == 1); - - return if (!defined($self->{clients}->{ $data->{id} })); - - $self->{logger}->writeLogInfo("[proxy] Close connectionn for $data->{id}"); - - $self->{clients}->{ $data->{id} }->{class}->close(); - $self->{clients}->{ $data->{id} }->{delete} = 0; - $self->{clients}->{ $data->{id} }->{class} = undef; -} - -sub close_connections { - my ($self, %options) = @_; - - foreach (keys %{$self->{clients}}) { - if (defined($self->{clients}->{$_}->{class}) && $self->{clients}->{$_}->{type} eq 'push_zmq') { - $self->{logger}->writeLogInfo("[proxy] Close connection for $_"); - $self->{clients}->{$_}->{class}->close(); - } - } -} - -sub proxy_ssh { - my ($self, %options) = @_; - - my ($code, $decoded_data) = $self->json_decode(argument => $options{data}); - return if ($code == 1); - - if ($options{action} eq 'PING') { - if ($self->{clients}->{ $options{target_client} }->{class}->ping() == -1) { - $self->{clients}->{ $options{target_client} }->{delete} = 1; - } else { - $self->{clients}->{ $options{target_client} }->{com_read_internal} = 1; - $self->send_internal_action({ - action => 'PONG', - data => { data => { id => $options{target_client} } }, - token => $options{token}, - target => '' - }); - } - return ; - } - - my $retry = 1; # manage server disconnected - while ($retry >= 0) { - my ($status, $data_ret) = $self->{clients}->{ $options{target_client} }->{class}->action( - action => $options{action}, - data => $decoded_data, - target_direct => $options{target_direct}, - target => $options{target}, - token => $options{token} - ); - - if (ref($data_ret) eq 'ARRAY') { - foreach (@{$data_ret}) { - $self->send_log( - code => $_->{code}, - token => $options{token}, - logging => $decoded_data->{logging}, - instant => $decoded_data->{instant}, - data => $_->{data} - ); - } - last; - } - - $self->{logger}->writeLogDebug("[proxy] Sshclient return: [message = $data_ret->{message}]"); - if ($status == 0) { - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - logging => $decoded_data->{logging}, - data => $data_ret - ); - last; - } - - $self->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - logging => $decoded_data->{logging}, - data => $data_ret - ); - - # quit because it's not a ssh connection issue - last if ($self->{clients}->{ $options{target_client} }->{class}->is_connected() != 0); - $retry--; - } -} - -sub proxy { - my (%options) = @_; - - if ($options{message} !~ /^\[(.+?)\]\s+\[(.*?)\]\s+\[(.*?)\]\s+(.*)$/m) { - return undef; - } - my ($action, $token, $target_complete, $data) = ($1, $2, $3, $4); - $connector->{logger}->writeLogDebug( - "[proxy] Send message: [channel = $options{channel}] [action = $action] [token = $token] [target = $target_complete] [data = $data]" - ); - - if ($action eq 'PROXYADDNODE') { - $connector->action_proxyaddnode(data => $data); - return ; - } elsif ($action eq 'PROXYDELNODE') { - $connector->action_proxydelnode(data => $data); - return ; - } elsif ($action eq 'BCASTLOGGER' && $target_complete eq '') { - (undef, $data) = $connector->json_decode(argument => $data); - $connector->action_bcastlogger(data => $data); - return ; - } elsif ($action eq 'BCASTCOREKEY' && $target_complete eq '') { - (undef, $data) = $connector->json_decode(argument => $data); - $connector->action_bcastcorekey(data => $data); - return ; - } elsif ($action eq 'PROXYCLOSECONNECTION') { - $connector->action_proxycloseconnection(data => $data); - return ; - } - - if ($target_complete !~ /^(.+)~~(.+)$/) { - $connector->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { - message => "unknown target format '$target_complete'" - } - ); - return ; - } - - my ($target_client, $target, $target_direct) = ($1, $2, 1); - if ($target_client ne $target) { - $target_direct = 0; - } - if (!defined($connector->{clients}->{$target_client}->{class})) { - $connector->{logger}->writeLogInfo("[proxy] connect for $target_client"); - if ($connector->connect(id => $target_client) != 0) { - $connector->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { - message => "cannot connect on target node '$target_client'" - } - ); - return ; - } - } - - if ($connector->{clients}->{$target_client}->{type} eq 'push_zmq') { - my ($status, $msg) = $connector->{clients}->{$target_client}->{class}->send_message( - action => $action, - token => $token, - target => $target_direct == 0 ? $target : undef, - data => $data - ); - if ($status != 0) { - $connector->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { - message => "Send message problem for '$target': $msg" - } - ); - $connector->{logger}->writeLogError("[proxy] Send message problem for '$target': $msg"); - $connector->{clients}->{$target_client}->{delete} = 1; - } - } elsif ($connector->{clients}->{$target_client}->{type} eq 'push_ssh') { - $connector->proxy_ssh( - action => $action, - data => $data, - target_client => $target_client, - target => $target, - target_direct => $target_direct, - token => $token - ); - } -} - -sub event { - my ($self, %options) = @_; - - my $socket; - if (defined($options{channel})) { - #$self->{logger}->writeLogDebug("[proxy] event channel $options{channel} delete: $self->{clients}->{ $options{channel} }->{delete} com_read_internal: $self->{clients}->{ $options{channel} }->{com_read_internal}") - # if (defined($self->{clients}->{ $options{channel} })); - return if ( - defined($self->{clients}->{ $options{channel} }) && - ($self->{clients}->{ $options{channel} }->{com_read_internal} == 0 || $self->{clients}->{ $options{channel} }->{delete} == 1) - ); - - $socket = $options{channel} eq 'control' ? $self->{internal_socket} : $self->{internal_channels}->{ $options{channel} }; - } else { - $socket = $options{socket}; - $options{channel} = 'control'; - } - - while ($socket->has_pollin()) { - my ($message) = $self->read_message(socket => $socket); - next if (!defined($message)); - - proxy(message => $message, channel => $options{channel}); - if ($self->{stop} == 1 && (time() - $self->{exit_timeout}) > $self->{stop_time}) { - $self->exit_process(); - } - return if ( - defined($self->{clients}->{ $options{channel} }) && - ($self->{clients}->{ $options{channel} }->{com_read_internal} == 0 || $self->{clients}->{ $options{channel} }->{delete} == 1) - ); - } -} - -sub periodic_exec { - foreach (keys %{$connector->{clients}}) { - if (defined($connector->{clients}->{$_}->{delete}) && $connector->{clients}->{$_}->{delete} == 1) { - $connector->send_internal_action({ - action => 'PONGRESET', - data => '{ "data": { "id": ' . $_ . ' } }', - data_noencode => 1, - token => $connector->generate_token(), - target => '' - }); - $connector->{clients}->{$_}->{class}->close() if (defined($connector->{clients}->{$_}->{class})); - $connector->{clients}->{$_}->{class} = undef; - $connector->{clients}->{$_}->{delete} = 0; - $connector->{clients}->{$_}->{com_read_internal} = 0; - $connector->{logger}->writeLogInfo("[proxy] periodic close connection for $_"); - next; - } - } - - foreach (keys %{$connector->{clients}}) { - $connector->event(channel => $_); - } - - if ($connector->{stop} == 1) { - $connector->exit_process(); - } -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-proxy-' . $self->{pool_id}, - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'PROXYREADY', - data => { - pool_id => $self->{pool_id} - } - }); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io( - $self->{internal_socket}->get_fd(), - EV::READ, - sub { - $connector->event(channel => 'control'); - } - ); - - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/proxy/hooks.pm b/centreon-gorgone/gorgone/modules/core/proxy/hooks.pm deleted file mode 100644 index 1319abad40..0000000000 --- a/centreon-gorgone/gorgone/modules/core/proxy/hooks.pm +++ /dev/null @@ -1,1227 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::proxy::hooks; - -use warnings; -use strict; -use JSON::XS; -use gorgone::class::frame; -use gorgone::standard::misc; -use gorgone::class::core; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::modules::core::proxy::class; -use File::Basename; -use MIME::Base64; -use Digest::MD5::File qw(file_md5_hex); -use Fcntl; -use Time::HiRes; -use Try::Tiny; -use Archive::Tar; -use File::Find; - -$Archive::Tar::SAME_PERMISSIONS = 1; -$Archive::Tar::WARN = 0; - -=begin comment -for each proxy processus, we have: - one control channel (DEALER identity: gorgone-proxy-$poolid) - one channel by client (DEALER identity: gorgone-proxy-channel-$nodeid) -=cut - -use constant NAMESPACE => 'core'; -use constant NAME => 'proxy'; -use constant EVENTS => [ - { event => 'PROXYREADY' }, - { event => 'REMOTECOPY', uri => '/remotecopy', method => 'POST' }, - { event => 'SETLOGS' }, # internal. Shouldn't be used by third party clients - { event => 'PONG' }, # internal. Shouldn't be used by third party clients - { event => 'REGISTERNODES' }, # internal. Shouldn't be used by third party clients - { event => 'UNREGISTERNODES' }, # internal. Shouldn't be used by third party clients - { event => 'PROXYADDNODE' }, # internal. Shouldn't be used by third party clients - { event => 'PROXYDELNODE' }, # internal. Shouldn't be used by third party clients - { event => 'PROXYADDSUBNODE' }, # internal. Shouldn't be used by third party clients - { event => 'PONGRESET' }, # internal. Shouldn't be used by third party clients - { event => 'PROXYCLOSECONNECTION' }, - { event => 'PROXYSTOPREADCHANNEL' } -]; - -my $config_core; -my $config; - -my $synctime_error = 0; -my $synctime_nodes = {}; # get last time retrieved -my $synctime_lasttime; -my $synctime_option; -my $synctimeout_option; -my $ping_interval; - -my $last_pong = {}; -my $register_nodes = {}; -# With static routes we have a pathscore. Dynamic no pathscore. -# Dynamic comes from PONG result -# algo is: we use static routes first. after we use dynamic routes -# { -# subnode_id => { -# static => { -# parent_id1 => 1, -# parent_id2 => 2, -# }, -# dynamic => { -# parent_id3 => 1, -# parent_id5 => 1, -# } -# } -# } -# -my $register_subnodes = {}; -my $constatus_ping = {}; -my $parent_ping = {}; -my $pools = {}; -my $pools_pid = {}; -my $nodes_pool = {}; -my $prevails = {}; -my $prevails_subnodes = {}; -my $rr_current = 0; -my $stop = 0; - -# httpserver is only for pull wss client -my $httpserver = {}; - -my ($external_socket, $core_id); - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - - $synctime_option = defined($config->{synchistory_time}) ? $config->{synchistory_time} : 60; - $synctimeout_option = defined($config->{synchistory_timeout}) ? $config->{synchistory_timeout} : 30; - $ping_interval = defined($config->{ping}) ? $config->{ping} : 60; - $config->{pong_discard_timeout} = defined($config->{pong_discard_timeout}) ? $config->{pong_discard_timeout} : 300; - $config->{pong_max_timeout} = defined($config->{pong_max_timeout}) ? $config->{pong_max_timeout} : 3; - $config->{pool} = defined($config->{pool}) && $config->{pool} =~ /(\d+)/ ? $1 : 5; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - $synctime_lasttime = Time::HiRes::time(); - $core_id = $options{id}; - $external_socket = $options{external_socket}; - for my $pool_id (1..$config->{pool}) { - create_child(dbh => $options{dbh}, pool_id => $pool_id, logger => $options{logger}); - } - if (defined($config->{httpserver}->{enable}) && $config->{httpserver}->{enable} eq 'true') { - create_httpserver_child(dbh => $options{dbh}, logger => $options{logger}); - } -} - -sub routing { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - $options{logger}->writeLogError("[proxy] Cannot decode json data: " . $options{frame}->getLastError()); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'proxy - cannot decode json' }, - json_encode => 1 - }); - return undef; - } - - if ($options{action} eq 'PONG') { - return undef if (!defined($data->{data}->{id}) || $data->{data}->{id} eq ''); - $constatus_ping->{ $data->{data}->{id} }->{in_progress_ping} = 0; - $constatus_ping->{ $data->{data}->{id} }->{ping_timeout} = 0; - $last_pong->{ $data->{data}->{id} } = time(); - $constatus_ping->{ $data->{data}->{id} }->{last_ping_recv} = time(); - $constatus_ping->{ $data->{data}->{id} }->{nodes} = $data->{data}->{data}; - $constatus_ping->{ $data->{data}->{id} }->{ping_ok}++; - register_subnodes(%options, id => $data->{data}->{id}, subnodes => $data->{data}->{data}); - $options{logger}->writeLogInfo("[proxy] Pong received from '" . $data->{data}->{id} . "'"); - return undef; - } - - if ($options{action} eq 'PONGRESET') { - return undef if (!defined($data->{data}->{id}) || $data->{data}->{id} eq ''); - if (defined($constatus_ping->{ $data->{data}->{id} })) { - $constatus_ping->{ $data->{data}->{id} }->{in_progress_ping} = 0; - $constatus_ping->{ $data->{data}->{id} }->{ping_timeout} = 0; - $constatus_ping->{ $data->{data}->{id} }->{ping_failed}++; - } - $options{logger}->writeLogInfo("[proxy] PongReset received from '" . $data->{data}->{id} . "'"); - return undef; - } - - if ($options{action} eq 'UNREGISTERNODES') { - unregister_nodes(%options, data => $data); - return undef; - } - - if ($options{action} eq 'REGISTERNODES') { - register_nodes(%options, data => $data); - return undef; - } - - if ($options{action} eq 'PROXYREADY') { - if (defined($data->{pool_id})) { - $pools->{ $data->{pool_id} }->{ready} = 1; - # we sent proxyaddnode to sync - foreach my $node_id (keys %$nodes_pool) { - next if ($nodes_pool->{$node_id} != $data->{pool_id}); - routing( - action => 'PROXYADDNODE', - target => $node_id, - frame => gorgone::class::frame->new(data => $register_nodes->{$node_id}), - gorgone => $options{gorgone}, - dbh => $options{dbh}, - logger => $options{logger} - ); - } - } elsif (defined($data->{httpserver})) { - $httpserver->{ready} = 1; - } elsif (defined($data->{node_id}) && defined($synctime_nodes->{ $data->{node_id} })) { - $synctime_nodes->{ $data->{node_id} }->{channel_ready} = 1; - } - return undef; - } - - if ($options{action} eq 'SETLOGS') { - setlogs(dbh => $options{dbh}, data => $data, token => $options{token}, logger => $options{logger}); - return undef; - } - - my ($code, $is_ctrl_channel, $target_complete, $target_parent, $target) = pathway( - action => $options{action}, - target => $options{target}, - dbh => $options{dbh}, - token => $options{token}, - gorgone => $options{gorgone}, - logger => $options{logger} - ); - return if ($code == -1); - - # we check if we have all proxy connected - if (gorgone::class::core::waiting_ready_pool() == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'proxy - still not ready' }, - json_encode => 1 - }); - return ; - } - - if ($options{action} eq 'GETLOG') { - if (defined($register_nodes->{$target_parent}) && $register_nodes->{$target_parent}->{type} eq 'push_ssh') { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, token => $options{token}, - data => { message => "proxy - can't get log a ssh target or through a ssh node" }, - json_encode => 1 - }); - return undef; - } - - if (defined($register_nodes->{$target})) { - if ($synctime_nodes->{$target}->{synctime_error} == -1 && get_sync_time(dbh => $options{dbh}, node_id => $target) == -1) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, token => $options{token}, - data => { message => 'proxy - problem to getlog' }, - json_encode => 1 - }); - return undef; - } - - if ($synctime_nodes->{$target}->{in_progress} == 1) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, token => $options{token}, - data => { message => 'proxy - getlog already in progress' }, - json_encode => 1 - }); - return undef; - } - - # We put the good time to get - my $ctime = $synctime_nodes->{$target}->{ctime}; - $options{frame}->setData({ ctime => $ctime }); - $options{frame}->setRawData(); - $synctime_nodes->{$target}->{in_progress} = 1; - $synctime_nodes->{$target}->{in_progress_time} = time(); - } - } - - my $action = $options{action}; - my $bulk_actions; - push @{$bulk_actions}, $options{frame}->getRawData(); - - if ($options{action} eq 'REMOTECOPY' && defined($register_nodes->{$target_parent}) && - $register_nodes->{$target_parent}->{type} ne 'push_ssh') { - $action = 'PROCESSCOPY'; - ($code, $bulk_actions) = prepare_remote_copy( - dbh => $options{dbh}, - data => $data, - target => $target_parent, - token => $options{token}, - logger => $options{logger} - ); - return if ($code == -1); - } - - my $pool_id; - if (defined($nodes_pool->{$target_parent})) { - $pool_id = $nodes_pool->{$target_parent}; - } else { - $pool_id = rr_pool(); - $nodes_pool->{$target_parent} = $pool_id; - } - - my $identity = 'gorgone-proxy-' . $pool_id; - if ($is_ctrl_channel == 0 && $synctime_nodes->{$target_parent}->{channel_ready} == 1) { - $identity = 'gorgone-proxy-channel-' . $target_parent; - } - if ($register_nodes->{$target_parent}->{type} eq 'wss' || $register_nodes->{$target_parent}->{type} eq 'pullwss') { - $identity = 'gorgone-proxy-httpserver'; - } - - foreach my $raw_data_ref (@{$bulk_actions}) { - # Mode zmq pull - if ($register_nodes->{$target_parent}->{type} eq 'pull') { - pull_request( - gorgone => $options{gorgone}, - dbh => $options{dbh}, - action => $action, - raw_data_ref => $raw_data_ref, - token => $options{token}, - target_parent => $target_parent, - target => $target, - logger => $options{logger} - ); - next; - } - - $options{gorgone}->send_internal_message( - identity => $identity, - action => $action, - raw_data_ref => $raw_data_ref, - token => $options{token}, - target => $target_complete - ); - } -} - -sub gently { - my (%options) = @_; - - $stop = 1; - foreach my $pool_id (keys %$pools) { - if (defined($pools->{$pool_id}->{running}) && $pools->{$pool_id}->{running} == 1) { - $options{logger}->writeLogDebug("[proxy] Send TERM signal for pool '" . $pool_id . "'"); - CORE::kill('TERM', $pools->{$pool_id}->{pid}); - } - } - - if (defined($httpserver->{running}) && $httpserver->{running} == 1) { - $options{logger}->writeLogDebug("[action] Send TERM signal for httpserver"); - CORE::kill('TERM', $httpserver->{pid}); - } -} - -sub kill { - my (%options) = @_; - - foreach (keys %{$pools}) { - if ($pools->{$_}->{running} == 1) { - $options{logger}->writeLogDebug("[proxy] Send KILL signal for pool '" . $_ . "'"); - CORE::kill('KILL', $pools->{$_}->{pid}); - } - } - - if (defined($httpserver->{running}) && $httpserver->{running} == 1) { - $options{logger}->writeLogDebug("[action] Send KILL signal for httpserver"); - CORE::kill('KILL', $httpserver->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check_create_child { - my (%options) = @_; - - return if ($stop == 1); - - # Check if we need to create a child - for my $pool_id (1..$config->{pool}) { - if (!defined($pools->{$pool_id})) { - create_child(dbh => $options{dbh}, pool_id => $pool_id, logger => $options{logger}); - } - } -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - if (defined($httpserver->{pid}) && $httpserver->{pid} == $pid) { - $httpserver = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_httpserver_child(logger => $options{logger}); - } - next; - } - - # Not me - next if (!defined($pools_pid->{$pid})); - - # If someone dead, we recreate - my $pool_id = $pools_pid->{$pid}; - delete $pools->{$pools_pid->{$pid}}; - delete $pools_pid->{$pid}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(dbh => $options{dbh}, pool_id => $pool_id, logger => $options{logger}); - } - } - - check_create_child(dbh => $options{dbh}, logger => $options{logger}); - - $count++ if (defined($httpserver->{running}) && $httpserver->{running} == 1); - foreach (keys %$pools) { - $count++ if ($pools->{$_}->{running} == 1); - } - - # We check synclog/ping/ping request timeout - foreach (keys %$synctime_nodes) { - if ($register_nodes->{$_}->{type} =~ /^(?:pull|wss|pullwss)$/ && $constatus_ping->{$_}->{in_progress_ping} == 1) { - my $ping_timeout = defined($register_nodes->{$_}->{ping_timeout}) ? $register_nodes->{$_}->{ping_timeout} : 30; - if ((time() - $constatus_ping->{$_}->{in_progress_ping_pull}) > $ping_timeout) { - $constatus_ping->{$_}->{in_progress_ping} = 0; - $options{logger}->writeLogInfo("[proxy] Ping timeout from '" . $_ . "'"); - } - } - if ($register_nodes->{$_}->{type} !~ /^(?:pull|wss|pullwss)$/ && $constatus_ping->{$_}->{in_progress_ping} == 1) { - if (time() - $constatus_ping->{ $_ }->{last_ping_sent} > $config->{pong_discard_timeout}) { - $options{logger}->writeLogInfo("[proxy] Ping timeout from '" . $_ . "'"); - $constatus_ping->{$_}->{in_progress_ping} = 0; - $constatus_ping->{$_}->{ping_timeout}++; - $constatus_ping->{$_}->{ping_failed}++; - if (($constatus_ping->{$_}->{ping_timeout} % $config->{pong_max_timeout}) == 0) { - $options{logger}->writeLogInfo("[proxy] Ping max timeout reached from '" . $_ . "'"); - routing( - target => $_, - action => 'PROXYCLOSECONNECTION', - frame => gorgone::class::frame->new(data => { id => $_ }), - gorgone => $options{gorgone}, - dbh => $options{dbh}, - logger => $options{logger} - ); - } - } - } - - if ($synctime_nodes->{$_}->{in_progress} == 1 && - time() - $synctime_nodes->{$_}->{in_progress_time} > $synctimeout_option) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - data => { message => "proxy - getlog in timeout for '$_'" }, - json_encode => 1 - }); - $synctime_nodes->{$_}->{in_progress} = 0; - } - } - - # We check if we need synclogs - if ($stop == 0 && - time() - $synctime_lasttime > $synctime_option) { - $synctime_lasttime = time(); - full_sync_history(gorgone => $options{gorgone}, dbh => $options{dbh}, logger => $options{logger}); - } - - if ($stop == 0) { - ping_send(gorgone => $options{gorgone}, dbh => $options{dbh}, logger => $options{logger}); - } - - # We clean all parents - foreach (keys %$parent_ping) { - if (time() - $parent_ping->{$_}->{last_time} > 1800) { # 30 minutes - delete $parent_ping->{$_}; - } - } - - return ($count, 1); -} - -sub broadcast { - my (%options) = @_; - - foreach my $pool_id (keys %$pools) { - next if ($pools->{$pool_id}->{ready} != 1); - - $options{gorgone}->send_internal_message( - identity => 'gorgone-proxy-' . $pool_id, - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); - } - - if (defined($httpserver->{ready}) && $httpserver->{ready} == 1) { - $options{gorgone}->send_internal_message( - identity => 'gorgone-proxy-httpserver', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); - } -} - -# Specific functions -sub pathway { - my (%options) = @_; - - my $target = $options{target}; - if (!defined($target)) { - $options{logger}->writeLogDebug('[proxy] need a valid node id'); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, token => $options{token}, - data => { message => 'proxy - need a valid node id' }, - json_encode => 1 - }); - return -1; - } - - if (!defined($register_nodes->{$target}) && !defined($register_subnodes->{$target})) { - $options{logger}->writeLogDebug("[proxy] unknown target '$target'"); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, token => $options{token}, - data => { message => 'proxy - unknown target ' . $target }, - json_encode => 1 - }); - return -1; - } - - my @targets = (); - if (defined($register_nodes->{$target})) { - push @targets, $target; - } - if (defined($register_subnodes->{$target}->{static})) { - push @targets, sort { $register_subnodes->{$target}->{static}->{$a} <=> $register_subnodes->{$target}->{static}->{$b} } keys %{$register_subnodes->{$target}->{static}}; - } - if (defined($register_subnodes->{$target}->{dynamic})) { - push @targets, keys %{$register_subnodes->{$target}->{dynamic}}; - } - - my $first_target; - foreach (@targets) { - if ($register_nodes->{$_}->{type} =~ /^(?:pull|wss|pullwss)$/ && !defined($register_nodes->{$_}->{identity})) { - $options{logger}->writeLogDebug("[proxy] skip node " . $register_nodes->{$_}->{type} . " target '$_' for node '$target' - never connected"); - next; - } - - # we let passthrough. it's for control channel - if ($options{action} =~ /^(?:PING|PROXYADDNODE|PROXYDELNODE|PROXYADDSUBNODE|PROXYCLOSECONNECTION|PROXYSTOPREADCHANNEL)$/ && $_ eq $target) { - return (1, 1, $_ . '~~' . $target, $_, $target); - } - - if (!defined($last_pong->{$_}) || $last_pong->{$_} == 0 || (time() - $config->{pong_discard_timeout} < $last_pong->{$_})) { - $options{logger}->writeLogDebug("[proxy] choose node target '$_' for node '$target'"); - return (1, 0, $_ . '~~' . $target, $_, $target); - } - - $first_target = $_ if (!defined($first_target)); - } - - if (!defined($first_target)) { - $options{logger}->writeLogDebug("[proxy] no pathway for target '$target'"); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, token => $options{token}, - data => { message => 'proxy - no pathway for target ' . $target }, - json_encode => 1 - }); - return -1; - } - - # if there are here, we use the first pathway (because all pathways had an issue) - return (1, 0, $first_target . '~~' . $target, $first_target, $target); -} - -sub setlogs { - my (%options) = @_; - - if (!defined($options{data}->{data}->{id}) || $options{data}->{data}->{id} eq '') { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, token => $options{token}, - data => { message => 'proxy - need a id to setlogs' }, - json_encode => 1 - }); - return undef; - } - if ($synctime_nodes->{ $options{data}->{data}->{id} }->{in_progress} == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, token => $options{token}, - data => { message => 'proxy - skip setlogs response. Maybe too much time to get response. Retry' }, - json_encode => 1 - }); - return undef; - } - - $options{logger}->writeLogInfo("[proxy] Received setlogs for '$options{data}->{data}->{id}'"); - - # we have received the setlogs (it's like a pong response. not a problem if we received the pong after) - $constatus_ping->{ $options{data}->{data}->{id} }->{in_progress_ping} = 0; - $constatus_ping->{ $options{data}->{data}->{id} }->{ping_timeout} = 0; - $constatus_ping->{ $options{data}->{data}->{id} }->{last_ping_recv} = time(); - $last_pong->{ $options{data}->{data}->{id} } = time() if (defined($last_pong->{ $options{data}->{data}->{id} })); - - $synctime_nodes->{ $options{data}->{data}->{id} }->{in_progress} = 0; - - my $ctime_recent = 0; - # Transaction. We don't use last_id (problem if it's clean the sqlite table). - my $status; - $status = $options{dbh}->transaction_mode(1); - return -1 if ($status == -1); - - foreach (@{$options{data}->{data}->{result}}) { - # wrong timestamp inserted. we skip it - if ($_->{ctime} !~ /[0-9\.]/) { - $options{logger}->writeLogDebug("[proxy] wrong ctime for '$options{data}->{data}->{id}'"); - next; - } - $status = gorgone::standard::library::add_history({ - dbh => $options{dbh}, - etime => $_->{etime}, - code => $_->{code}, - token => $_->{token}, - instant => $_->{instant}, - data => $_->{data} - }); - last if ($status == -1); - $ctime_recent = $_->{ctime} if ($ctime_recent < $_->{ctime}); - } - if ($status == 0 && update_sync_time(dbh => $options{dbh}, id => $options{data}->{data}->{id}, ctime => $ctime_recent) == 0) { - $status = $options{dbh}->commit(); - return -1 if ($status == -1); - $options{dbh}->transaction_mode(0); - - $synctime_nodes->{ $options{data}->{data}->{id} }->{ctime} = $ctime_recent if ($ctime_recent != 0); - } else { - $options{dbh}->rollback(); - $options{dbh}->transaction_mode(0); - return -1; - } - - # We try to send it to parents - foreach (keys %$parent_ping) { - gorgone::class::core::send_message_parent( - router_type => $parent_ping->{$_}->{router_type}, - identity => $_, - response_type => 'SYNCLOGS', - data => { id => $core_id }, - code => GORGONE_ACTION_BEGIN, - token => undef, - ); - } - - return 0; -} - -sub ping_send { - my (%options) = @_; - - my $nodes_id = [keys %$register_nodes]; - $nodes_id = [$options{node_id}] if (defined($options{node_id})); - my $current_time = time(); - foreach my $id (@$nodes_id) { - next if ($constatus_ping->{$id}->{in_progress_ping} == 1 || $current_time < $constatus_ping->{$id}->{next_ping}); - - $constatus_ping->{$id}->{last_ping_sent} = $current_time; - $constatus_ping->{$id}->{next_ping} = $current_time + $ping_interval; - if ($register_nodes->{$id}->{type} eq 'push_zmq' || $register_nodes->{$id}->{type} eq 'push_ssh') { - $constatus_ping->{$id}->{in_progress_ping} = 1; - routing(action => 'PING', target => $id, frame => gorgone::class::frame->new(data => {}), gorgone => $options{gorgone}, dbh => $options{dbh}, logger => $options{logger}); - } elsif ($register_nodes->{$id}->{type} =~ /^(?:pull|wss|pullwss)$/) { - $constatus_ping->{$id}->{in_progress_ping} = 1; - $constatus_ping->{$id}->{in_progress_ping_pull} = time(); - routing(action => 'PING', target => $id, frame => gorgone::class::frame->new(data => {}), gorgone => $options{gorgone}, dbh => $options{dbh}, logger => $options{logger}); - } - } -} - -sub synclog { - my (%options) = @_; - - # We check if we need synclogs - if ($stop == 0) { - $synctime_lasttime = time(); - full_sync_history(gorgone => $options{gorgone}, dbh => $options{dbh}, logger => $options{logger}); - } -} - -sub full_sync_history { - my (%options) = @_; - - foreach my $id (keys %{$register_nodes}) { - if ($register_nodes->{$id}->{type} eq 'push_zmq') { - routing(action => 'GETLOG', target => $id, frame => gorgone::class::frame->new(data => {}), gorgone => $options{gorgone}, dbh => $options{dbh}, logger => $options{logger}); - } elsif ($register_nodes->{$id}->{type} =~ /^(?:pull|wss|pullwss)$/) { - routing(action => 'GETLOG', target => $id, frame => gorgone::class::frame->new(data => {}), gorgone => $options{gorgone}, dbh => $options{dbh}, logger => $options{logger}); - } - } -} - -sub update_sync_time { - my (%options) = @_; - - # Nothing to update (no insert before) - return 0 if ($options{ctime} == 0); - - my ($status) = $options{dbh}->query({ - query => "REPLACE INTO gorgone_synchistory (`id`, `ctime`) VALUES (?, ?)", - bind_values => [$options{id}, $options{ctime}] - } - ); - return $status; -} - -sub get_sync_time { - my (%options) = @_; - - my ($status, $sth) = $options{dbh}->query({ query => "SELECT * FROM gorgone_synchistory WHERE id = '" . $options{node_id} . "'" }); - if ($status == -1) { - $synctime_nodes->{$options{node_id}}->{synctime_error} = -1; - return -1; - } - - $synctime_nodes->{$options{node_id}}->{synctime_error} = 0; - if (my $row = $sth->fetchrow_hashref()) { - $synctime_nodes->{ $row->{id} }->{ctime} = $row->{ctime}; - $synctime_nodes->{ $row->{id} }->{in_progress} = 0; - $synctime_nodes->{ $row->{id} }->{in_progress_time} = -1; - } - - return 0; -} - -sub is_all_proxy_ready { - my $ready = 0; - for my $pool_id (1..$config->{pool}) { - if (defined($pools->{$pool_id}) && $pools->{$pool_id}->{ready} == 1) { - $ready++; - } - } - - return ($ready * 100 / $config->{pool}); -} - -sub rr_pool { - my (%options) = @_; - - while (1) { - $rr_current = $rr_current % $config->{pool}; - if ($pools->{$rr_current + 1}->{ready} == 1) { - $rr_current++; - return $rr_current; - } - $rr_current++; - } -} - -sub create_child { - my (%options) = @_; - - if (!defined($core_id) || $core_id =~ /^\s*$/) { - $options{logger}->writeLogError("[proxy] Cannot create child, need a core id"); - return ; - } - - $options{logger}->writeLogInfo("[proxy] Create module 'proxy' child process for pool id '" . $options{pool_id} . "'"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-proxy'; - my $module = gorgone::modules::core::proxy::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - pool_id => $options{pool_id}, - core_id => $core_id, - container_id => $options{pool_id} - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[proxy] PID $child_pid (gorgone-proxy) for pool id '" . $options{pool_id} . "'"); - $pools->{$options{pool_id}} = { pid => $child_pid, ready => 0, running => 1 }; - $pools_pid->{$child_pid} = $options{pool_id}; -} - -sub create_httpserver_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[proxy] Create module 'proxy' httpserver child process"); - - my $rv = gorgone::standard::misc::mymodule_load( - logger => $options{logger}, - module => 'gorgone::modules::core::proxy::httpserver', - error_msg => "Cannot load module 'gorgone::modules::core::proxy::httpserver'" - ); - return if ($rv != 0); - - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-proxy-httpserver'; - my $module = gorgone::modules::core::proxy::httpserver->construct( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - container_id => 'httpserver' - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[proxy] PID $child_pid (gorgone-proxy-httpserver)"); - $httpserver = { pid => $child_pid, ready => 0, running => 1 }; -} - -sub pull_request { - my (%options) = @_; - - my $message = gorgone::standard::library::build_protocol( - action => $options{action}, - raw_data_ref => $options{raw_data_ref}, - token => $options{token}, - target => $options{target} - ); - - if (!defined($register_nodes->{ $options{target_parent} }->{identity})) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "proxy - node '" . $options{target_parent} . "' had never been connected" }, - json_encode => 1 - }); - return undef; - } - - my $identity = unpack('H*', $register_nodes->{ $options{target_parent} }->{identity}); - my ($rv, $cipher_infos) = $options{gorgone}->is_handshake_done( - identity => $identity - ); - if ($rv == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "proxy - node '" . $options{target_parent} . "' had never been connected" }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->external_core_response( - cipher_infos => $cipher_infos, - identity => $identity, - message => $message - ); -} - -sub get_constatus_result { - my (%options) = @_; - - return $constatus_ping; -} - -sub unregister_nodes { - my (%options) = @_; - - return if (!defined($options{data}->{nodes})); - - foreach my $node (@{$options{data}->{nodes}}) { - if (defined($register_nodes->{ $node->{id} }) && $register_nodes->{ $node->{id} }->{type} !~ /^(?:pull|wss|pullwss)$/) { - routing( - action => 'PROXYDELNODE', - target => $node->{id}, - frame => gorgone::class::frame->new(data => $node), - gorgone => $options{gorgone}, - dbh => $options{dbh}, - logger => $options{logger} - ); - } - - my $prevail = 0; - $prevail = 1 if (defined($prevails->{ $node->{id} })); - - if (defined($register_nodes->{ $node->{id} }) && $register_nodes->{ $node->{id} }->{type} =~ /^(?:pull|wss|pullwss)$/ && $prevail == 1) { - $register_nodes->{ $node->{id} }->{identity} = undef; - } - - $options{logger}->writeLogInfo("[proxy] Node '" . $node->{id} . "' is unregistered"); - if (defined($register_nodes->{ $node->{id} }) && $register_nodes->{ $node->{id} }->{nodes}) { - foreach my $subnode (@{$register_nodes->{ $node->{id} }->{nodes}}) { - delete $register_subnodes->{ $subnode->{id} }->{static}->{ $node->{id} } - if (defined($register_subnodes->{ $subnode->{id} }->{static}->{ $node->{id} }) && $prevail == 0); - delete $register_subnodes->{ $subnode->{id} }->{dynamic}->{ $node->{id} } - if (defined($register_subnodes->{ $subnode->{id} }->{dynamic}->{ $node->{id} })); - } - } - - delete $nodes_pool->{ $node->{id} } if (defined($nodes_pool->{ $node->{id} })); - if (defined($register_nodes->{ $node->{id} })) { - delete $register_nodes->{ $node->{id} } if ($prevail == 0); - delete $synctime_nodes->{ $node->{id} }; - delete $constatus_ping->{ $node->{id} }; - delete $last_pong->{ $node->{id} }; - } - } -} - -# It comes from PONG result. -sub register_subnodes { - my (%options) = @_; - - # we remove dynamic values - foreach my $subnode_id (keys %$register_subnodes) { - delete $register_subnodes->{$subnode_id}->{dynamic}->{ $options{id} } - if (defined($register_subnodes->{$subnode_id}->{dynamic}->{ $options{id} })); - } - - # we can add in dynamic even if it's in static (not an issue) - my $subnodes = [$options{subnodes}]; - while (1) { - last if (scalar(@$subnodes) <= 0); - - my $entry = shift(@$subnodes); - foreach (keys %$entry) { - $register_subnodes->{$_}->{dynamic}->{ $options{id} } = 1; - } - push @$subnodes, $entry->{nodes} if (defined($entry->{nodes})); - } -} - -# 'pull' type: -# - it does a REGISTERNODES without subnodes (if it already exist, no new entry created, otherwise create an entry). We save the uniq identity -# - PING done by proxy and with PONG we get subnodes -sub register_nodes { - my (%options) = @_; - - return if (!defined($options{data}->{nodes})); - - foreach my $node (@{$options{data}->{nodes}}) { - my ($new_node, $prevail) = (1, 0); - - # prevail = 1 means: we cannot override the old one (if it exists) - if (defined($prevails_subnodes->{ $node->{id} })) { - $options{logger}->writeLogInfo("[proxy] cannot register node '$node->{id}': already defined as a subnode [prevails]"); - next; - } - $prevail = 1 if (defined($prevails->{ $node->{id} })); - $prevails->{ $node->{id} } = 1 if (defined($node->{prevail}) && $node->{prevail} == 1); - - if ($prevail == 1) { - $options{logger}->writeLogInfo("[proxy] cannot override node '$node->{id}' registration: prevails!!!"); - } - - if (defined($register_nodes->{ $node->{id} }) && $prevail == 0) { - # we remove subnodes before - foreach my $subnode_id (keys %$register_subnodes) { - delete $register_subnodes->{$subnode_id}->{static}->{ $node->{id} } - if (defined($register_subnodes->{$subnode_id}->{static}->{ $node->{id} })); - delete $register_subnodes->{$subnode_id}->{dynamic}->{ $node->{id} } - if (defined($register_subnodes->{$subnode_id}->{dynamic}->{ $node->{id} })); - } - } - - if (defined($register_nodes->{ $node->{id} })) { - $new_node = 0; - - if ($register_nodes->{ $node->{id} }->{type} !~ /^(?:pull|wss|pullwss)$/ && $node->{type} =~ /^(?:pull|wss|pullwss)$/) { - unregister_nodes( - data => { nodes => [ { id => $node->{id} } ] }, - gorgone => $options{gorgone}, - dbh => $options{dbh}, - logger => $options{logger} - ); - $new_node = 1; - } - } - - if ($prevail == 0) { - $register_nodes->{ $node->{id} } = $node; - if (defined($node->{nodes})) { - foreach my $subnode (@{$node->{nodes}}) { - $register_subnodes->{ $subnode->{id} } = { static => {}, dynamic => {} } if (!defined($register_subnodes->{ $subnode->{id} })); - $register_subnodes->{ $subnode->{id} }->{static}->{ $node->{id} } = defined($subnode->{pathscore}) && $subnode->{pathscore} =~ /[0-9]+/ ? $subnode->{pathscore} : 1; - - # subnodes also prevails. we try to unregister it - if (defined($node->{prevail}) && $node->{prevail} == 1) { - unregister_nodes( - data => { nodes => [ { id => $subnode->{id} } ] }, - gorgone => $options{gorgone}, - dbh => $options{dbh}, - logger => $options{logger} - ); - $prevails_subnodes->{ $subnode->{id} } = 1; - } - } - } - } - - # we update identity in all cases (already created or not) - if ($node->{type} =~ /^(?:pull|wss|pullwss)$/ && defined($node->{identity})) { - $register_nodes->{ $node->{id} }->{identity} = $node->{identity}; - $last_pong->{ $node->{id} } = time() if (defined($last_pong->{ $node->{id} })); - } - - $last_pong->{ $node->{id} } = 0 if (!defined($last_pong->{ $node->{id} })); - if (!defined($synctime_nodes->{ $node->{id} })) { - $synctime_nodes->{ $node->{id} } = { - ctime => 0, - in_progress => 0, - in_progress_time => -1, - synctime_error => 0, - channel_ready => 0 - }; - get_sync_time(node_id => $node->{id}, dbh => $options{dbh}); - } - - if ($register_nodes->{ $node->{id} }->{type} !~ /^(?:pull|wss|pullwss)$/) { - if ($prevail == 1) { - routing( - action => 'PROXYADDNODE', - target => $node->{id}, - frame => gorgone::class::frame->new(data => $register_nodes->{ $node->{id} }), - gorgone => $options{gorgone}, - dbh => $options{dbh}, - logger => $options{logger} - ); - } else { - routing( - action => 'PROXYADDNODE', - target => $node->{id}, - frame => gorgone::class::frame->new(data => $node), - gorgone => $options{gorgone}, - dbh => $options{dbh}, - logger => $options{logger} - ); - } - } - if ($new_node == 1) { - $constatus_ping->{ $node->{id} } = { - type => $node->{type}, - in_progress_ping => 0, - ping_timeout => 0, - last_ping_sent => 0, - last_ping_recv => 0, - next_ping => time() + int(rand($ping_interval)), - ping_ok => 0, - ping_failed => 0, - nodes => {} - }; - $options{logger}->writeLogInfo("[proxy] Node '" . $node->{id} . "' is registered"); - } - } -} - -sub prepare_remote_copy { - my (%options) = @_; - - my @actions = (); - - if (!defined($options{data}->{content}->{source}) || $options{data}->{content}->{source} eq '') { - $options{logger}->writeLogError('[proxy] Need source for remote copy'); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'remote copy failed' }, - json_encode => 1 - }); - return -1; - } - if (!defined($options{data}->{content}->{destination}) || $options{data}->{content}->{destination} eq '') { - $options{logger}->writeLogError('[proxy] Need destination for remote copy'); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'remote copy failed' }, - json_encode => 1 - }); - return -1; - } - - my $type; - my $filename; - my $localsrc = $options{data}->{content}->{source}; - my $src = $options{data}->{content}->{source}; - my $dst = $options{data}->{content}->{destination}; - - if (-f $options{data}->{content}->{source}) { - $type = 'regular'; - $localsrc = $src; - $filename = File::Basename::basename($src); - $dst .= $filename if ($dst =~ /\/$/); - } elsif (-d $options{data}->{content}->{source}) { - $type = 'archive'; - $filename = (defined($options{data}->{content}->{type}) ? $options{data}->{content}->{type} : 'tmp') . '-' . $options{target} . '.tar.gz'; - $localsrc = $options{data}->{content}->{cache_dir} . '/' . $filename; - - my $tar = Archive::Tar->new(); - unless (chdir($options{data}->{content}->{source})) { - $options{logger}->writeLogError("[proxy] cannot chdir: $!"); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "cannot chdir: $!" }, - json_encode => 1 - }); - return -1; - } - - my @inventory = (); - File::Find::find ({ wanted => sub { push @inventory, $_ }, no_chdir => 1 }, '.'); - my $owner; - $owner = $options{data}->{content}->{owner} if (defined($options{data}->{content}->{owner}) && $options{data}->{content}->{owner} ne ''); - my $group; - $group = $options{data}->{content}->{group} if (defined($options{data}->{content}->{group}) && $options{data}->{content}->{group} ne ''); - foreach my $file (@inventory) { - next if ($file eq '.'); - $tar->add_files($file); - if (defined($owner) || defined($group)) { - $tar->chown($file, $owner, $group); - } - } - - unless (chdir($options{data}->{content}->{cache_dir})) { - $options{logger}->writeLogError("[proxy] cannot chdir: $!"); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => "cannot chdir: $!" }, - json_encode => 1 - }); - return -1; - } - unless ($tar->write($filename, COMPRESS_GZIP)) { - $options{logger}->writeLogError("[proxy] Tar failed: " . $tar->error()); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'tar failed' }, - json_encode => 1 - }); - return -1; - } - } else { - $options{logger}->writeLogError('[proxy] Unknown source for remote copy'); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'unknown source' }, - json_encode => 1 - }); - return -1; - } - - sysopen(FH, $localsrc, O_RDONLY); - binmode(FH); - my $buffer_size = (defined($config->{buffer_size})) ? $config->{buffer_size} : 500_000; - my $buffer; - while (my $bytes = sysread(FH, $buffer, $buffer_size)) { - my $action = JSON::XS->new->encode({ - logging => $options{data}->{logging}, - content => { - status => 'inprogress', - type => $type, - chunk => { - data => MIME::Base64::encode_base64($buffer), - size => $bytes, - }, - md5 => undef, - destination => $dst, - cache_dir => $options{data}->{content}->{cache_dir} - }, - parameters => { no_fork => 1 } - }); - push @actions, \$action; - } - close FH; - - my $action = JSON::XS->new->encode({ - logging => $options{data}->{logging}, - content => { - status => 'end', - type => $type, - chunk => undef, - md5 => file_md5_hex($localsrc), - destination => $dst, - cache_dir => $options{data}->{content}->{cache_dir}, - owner => $options{data}->{content}->{owner}, - group => $options{data}->{content}->{group} - }, - parameters => { no_fork => 1 } - }); - push @actions, \$action; - - return (0, \@actions); -} - -sub setcoreid { - my (%options) = @_; - - $core_id = $options{core_id}; - check_create_child(%options); -} - -sub add_parent_ping { - my (%options) = @_; - - $options{logger}->writeLogDebug("[proxy] Parent ping '" . $options{identity} . "' is registered"); - $parent_ping->{ $options{identity} } = { last_time => time(), router_type => $options{router_type} }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/proxy/httpserver.pm b/centreon-gorgone/gorgone/modules/core/proxy/httpserver.pm deleted file mode 100644 index e2ba6525a9..0000000000 --- a/centreon-gorgone/gorgone/modules/core/proxy/httpserver.pm +++ /dev/null @@ -1,381 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::proxy::httpserver; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use Mojolicious::Lite; -use Mojo::Server::Daemon; -use IO::Socket::SSL; -use IO::Handle; -use JSON::XS; -use IO::Poll qw(POLLIN POLLPRI); -use EV; -use HTML::Entities; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -websocket '/' => sub { - my $mojo = shift; - - $connector->{logger}->writeLogDebug('[proxy] httpserver websocket client connected: ' . $mojo->tx->connection); - - $connector->{ws_clients}->{ $mojo->tx->connection } = { - tx => $mojo->tx, - logged => 0, - last_update => time(), - authorization => $mojo->tx->req->headers->header('authorization') - }; - - $mojo->on(message => sub { - my ($mojo, $msg) = @_; - - $msg = HTML::Entities::decode_entities($msg); - - $connector->{ws_clients}->{ $mojo->tx->connection }->{last_update} = time(); - - $connector->{logger}->writeLogDebug("[proxy] httpserver receiving message: " . $msg); - - my $rv = $connector->is_logged_websocket(ws_id => $mojo->tx->connection, data => $msg); - return if ($rv == 0); - - read_message_client(data => $msg); - }); - - $mojo->on(finish => sub { - my ($mojo, $code, $reason) = @_; - - $connector->{logger}->writeLogDebug('[proxy] httpserver websocket client disconnected: ' . $mojo->tx->connection); - $connector->clean_websocket(ws_id => $mojo->tx->connection, finish => 1); - }); -}; - -sub construct { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{ws_clients} = {}; - $connector->{identities} = {}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[proxy] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub run { - my ($self, %options) = @_; - - my $listen = 'reuse=1'; - if ($self->{config}->{httpserver}->{ssl} eq 'true') { - if (!defined($self->{config}->{httpserver}->{ssl_cert_file}) || $self->{config}->{httpserver}->{ssl_cert_file} eq '' || - ! -r "$self->{config}->{httpserver}->{ssl_cert_file}") { - $connector->{logger}->writeLogError("[proxy] httpserver cannot read/find ssl-cert-file"); - exit(1); - } - if (!defined($self->{config}->{httpserver}->{ssl_key_file}) || $self->{config}->{httpserver}->{ssl_key_file} eq '' || - ! -r "$self->{config}->{httpserver}->{ssl_key_file}") { - $connector->{logger}->writeLogError("[proxy] httpserver cannot read/find ssl-key-file"); - exit(1); - } - $listen .= '&cert=' . $self->{config}->{httpserver}->{ssl_cert_file} . '&key=' . $self->{config}->{httpserver}->{ssl_key_file}; - } - my $proto = 'http'; - if ($self->{config}->{httpserver}->{ssl} eq 'true') { - $proto = 'https'; - if (defined($self->{config}->{httpserver}->{passphrase}) && $self->{config}->{httpserver}->{passphrase} ne '') { - IO::Socket::SSL::set_defaults(SSL_passwd_cb => sub { return $connector->{config}->{httpserver}->{passphrase} } ); - } - } - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-proxy-httpserver', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'PROXYREADY', - data => { - httpserver => 1 - } - }); - $self->read_zmq_events(); - - my $type = ref(Mojo::IOLoop->singleton->reactor); - my $watcher_io; - if ($type eq 'Mojo::Reactor::Poll') { - Mojo::IOLoop->singleton->reactor->{io}{ $self->{internal_socket}->get_fd()} = { - cb => sub { $connector->read_zmq_events(); }, - mode => POLLIN | POLLPRI - }; - } else { - # need EV version 4.32 - $watcher_io = EV::io( - $self->{internal_socket}->get_fd(), - EV::READ, - sub { - $connector->read_zmq_events(); - } - ); - } - - #my $socket_fd = $self->{internal_socket}->get_fd(); - #my $socket = IO::Handle->new_from_fd($socket_fd, 'r'); - #Mojo::IOLoop->singleton->reactor->io($socket => sub { - # $connector->read_zmq_events(); - #}); - #Mojo::IOLoop->singleton->reactor->watch($socket, 1, 0); - - Mojo::IOLoop->singleton->recurring(60 => sub { - $connector->{logger}->writeLogDebug('[proxy] httpserver recurring timeout loop'); - my $ctime = time(); - foreach my $ws_id (keys %{$connector->{ws_clients}}) { - if (($ctime - $connector->{ws_clients}->{$ws_id}->{last_update}) > 300) { - $connector->{logger}->writeLogDebug('[proxy] httpserver websocket client timeout reached: ' . $ws_id); - $connector->close_websocket( - code => 500, - message => 'timeout reached', - ws_id => $ws_id - ); - } - } - }); - - app->mode('production'); - my $daemon = Mojo::Server::Daemon->new( - app => app, - listen => [$proto . '://' . $self->{config}->{httpserver}->{address} . ':' . $self->{config}->{httpserver}->{port} . '?' . $listen] - ); - $daemon->inactivity_timeout(180); - - $daemon->run(); - - exit(0); -} - -sub read_message_client { - my (%options) = @_; - - if ($options{data} =~ /^\[PONG\]/) { - return undef if ($options{data} !~ /^\[(.+?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)/m); - - my ($action, $token) = ($1, $2); - my ($rv, $data) = $connector->json_decode(argument => $3); - return undef if ($rv == 1); - - $connector->send_internal_action({ - action => 'PONG', - data => $data, - token => $token, - target => '' - }); - $connector->read_zmq_events(); - } elsif ($options{data} =~ /^\[(?:REGISTERNODES|UNREGISTERNODES|SYNCLOGS|SETLOGS)\]/) { - return undef if ($options{data} !~ /^\[(.+?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)/ms); - - my ($action, $token, $data) = ($1, $2, $3); - - $connector->send_internal_action({ - action => $action, - data => $data, - data_noencode => 1, - token => $token, - target => '' - }); - $connector->read_zmq_events(); - } -} - -sub proxy { - my (%options) = @_; - - return undef if ($options{message} !~ /^\[(.+?)\]\s+\[(.*?)\]\s+\[(.*?)\]\s+(.*)$/m); - - my ($action, $token, $target_complete, $data) = ($1, $2, $3, $4); - $connector->{logger}->writeLogDebug( - "[proxy] httpserver send message: [action = $action] [token = $token] [target = $target_complete] [data = $data]" - ); - - if ($action eq 'BCASTLOGGER' && $target_complete eq '') { - (undef, $data) = $connector->json_decode(argument => $data); - $connector->action_bcastlogger(data => $data); - return ; - } elsif ($action eq 'BCASTCOREKEY' && $target_complete eq '') { - (undef, $data) = $connector->json_decode(argument => $data); - $connector->action_bcastcorekey(data => $data); - return ; - } - - if ($target_complete !~ /^(.+)~~(.+)$/) { - $connector->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { - message => "unknown target format '$target_complete'" - } - ); - $connector->read_zmq_events(); - return ; - } - - my ($target_client, $target, $target_direct) = ($1, $2, 1); - if ($target_client ne $target) { - $target_direct = 0; - } - - if (!defined($connector->{identities}->{$target_client})) { - $connector->send_log( - code => GORGONE_ACTION_FINISH_KO, - token => $token, - data => { - message => "cannot get connection from target node '$target_client'" - } - ); - $connector->read_zmq_events(); - return ; - } - - my $message = gorgone::standard::library::build_protocol( - action => $action, - token => $token, - target => $target_direct == 0 ? $target : undef, - data => $data - ); - - $connector->{ws_clients}->{ $connector->{identities}->{$target_client} }->{tx}->send({text => $message}); -} - -sub read_zmq_events { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($message) = $connector->read_message(); - proxy(message => $message); - } -} - -sub is_logged_websocket { - my ($self, %options) = @_; - - return 1 if ($self->{ws_clients}->{ $options{ws_id} }->{logged} == 1); - - if (!defined($self->{ws_clients}->{ $options{ws_id} }->{authorization}) || - $self->{ws_clients}->{ $options{ws_id} }->{authorization} !~ /^\s*Bearer\s+$self->{config}->{httpserver}->{token}\s*$/) { - $self->close_websocket( - code => 500, - message => 'token authorization unallowed', - ws_id => $options{ws_id} - ); - return 0; - } - - if ($options{data} !~ /^\[REGISTERNODES\]\s+\[(?:.*?)\]\s+\[.*?\]\s+(.*)/ms) { - $self->close_websocket( - code => 500, - message => 'please registernodes', - ws_id => $options{ws_id} - ); - return 0; - } - - my $content; - eval { - $content = JSON::XS->new->decode($1); - }; - if ($@) { - $self->close_websocket( - code => 500, - message => 'decode error: unsupported format', - ws_id => $options{ws_id} - ); - return 0; - } - - $self->{logger}->writeLogDebug("[proxy] httpserver client " . $content->{nodes}->[0]->{id} . " is logged"); - - $self->{ws_clients}->{ $options{ws_id} }->{identity} = $content->{nodes}->[0]->{id}; - $self->{identities}->{ $content->{nodes}->[0]->{id} } = $options{ws_id}; - $self->{ws_clients}->{ $options{ws_id} }->{logged} = 1; - return 2; -} - -sub clean_websocket { - my ($self, %options) = @_; - - return if (!defined($self->{ws_clients}->{ $options{ws_id} })); - - $self->{ws_clients}->{ $options{ws_id} }->{tx}->finish() if (!defined($options{finish})); - delete $self->{identities}->{ $self->{ws_clients}->{ $options{ws_id} }->{identity} } - if (defined($self->{ws_clients}->{ $options{ws_id} }->{identity})); - delete $self->{ws_clients}->{ $options{ws_id} }; -} - -sub close_websocket { - my ($self, %options) = @_; - - $self->{ws_clients}->{ $options{ws_id} }->{tx}->send({json => { - code => $options{code}, - message => $options{message} - }}); - $self->clean_websocket(ws_id => $options{ws_id}); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/proxy/sshclient.pm b/centreon-gorgone/gorgone/modules/core/proxy/sshclient.pm deleted file mode 100644 index d0f40303e1..0000000000 --- a/centreon-gorgone/gorgone/modules/core/proxy/sshclient.pm +++ /dev/null @@ -1,555 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::proxy::sshclient; - -use base qw(Libssh::Session); - -use strict; -use warnings; -use Libssh::Sftp qw(:all); -use POSIX; -use gorgone::standard::misc; -use File::Basename; -use Time::HiRes; -use gorgone::standard::constants qw(:all); -use MIME::Base64; - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(%options); - bless $self, $class; - - $self->{save_options} = {}; - $self->{logger} = $options{logger}; - $self->{sftp} = undef; - return $self; -} - -sub open_session { - my ($self, %options) = @_; - - $self->{save_options} = { %options }; - my $timeout = defined($options{ssh_connect_timeout}) && $options{ssh_connect_timeout} =~ /^\d+$/ ? $options{ssh_connect_timeout} : 5; - if ($self->options( - host => $options{ssh_host}, - port => $options{ssh_port}, - user => $options{ssh_username}, - sshdir => $options{ssh_directory}, - knownhosts => $options{ssh_known_hosts}, - identity => $options{ssh_identity}, - timeout => $timeout - ) != Libssh::Session::SSH_OK) { - $self->{logger}->writeLogError('[sshclient] Options method: ' . $self->error()); - return -1; - } - - if ($self->connect(SkipKeyProblem => $options{strict_serverkey_check}) != Libssh::Session::SSH_OK) { - $self->{logger}->writeLogError('[sshclient] Connect method: ' . $self->error()); - return -1; - } - - if ($self->auth_publickey_auto() != Libssh::Session::SSH_AUTH_SUCCESS) { - $self->{logger}->writeLogInfo('[sshclient] Authentication publickey auto failure: ' . $self->error(GetErrorSession => 1)); - if (!defined($options{ssh_password}) || $options{ssh_password} eq '') { - $self->{logger}->writeLogError('[sshclient] Authentication issue: no password'); - return -1; - } - if ($self->auth_password(password => $options{ssh_password}) != Libssh::Session::SSH_AUTH_SUCCESS) { - $self->{logger}->writeLogError('[sshclient] Authentication issue: ' . $self->error(GetErrorSession => 1)); - return -1; - } - } - - $self->{logger}->writeLogInfo( - "[sshclient] Client authenticated successfully to 'ssh://" . $options{ssh_host} . ":" . $options{ssh_port} . "'" - ); - - $self->{sftp} = Libssh::Sftp->new(session => $self); - if (!defined($self->{sftp})) { - $self->{logger}->writeLogError('[sshclient] Cannot init sftp: ' . Libssh::Sftp::error()); - $self->disconnect(); - return -1; - } - - return 0; -} - -sub local_command { - my ($self, %options) = @_; - - my ($error, $stdout, $exit_code) = gorgone::standard::misc::backtick( - command => $options{command}, - timeout => (defined($options{timeout})) ? $options{timeout} : 120, - wait_exit => 1, - redirect_stderr => 1, - logger => $self->{logger} - ); - if ($error <= -1000) { - return (-1, { message => "command '$options{command}' execution issue: $stdout" }); - } - if ($exit_code != 0) { - return (-1, { message => "command '$options{command}' execution issue ($exit_code): $stdout" }); - } - return 0; -} - -sub ping { - my ($self, %options) = @_; - - my $ret = $self->execute_simple( - cmd => 'hostname', - timeout => 5, - timeout_nodata => 5 - ); - if ($ret->{exit} == Libssh::Session::SSH_OK) { - return 0; - } - - return -1; -} - -sub action_centcore { - my ($self, %options) = @_; - - if (!defined($options{data}->{content}->{command}) || $options{data}->{content}->{command} eq '') { - $self->{logger}->writeLogError('[sshclient] Action centcore - Need command'); - return (-1, { message => 'please set command' }); - } - if (!defined($options{data}->{content}->{target}) || $options{data}->{content}->{target} eq '') { - $self->{logger}->writeLogError('[sshclient] Action centcore - Need target'); - return (-1, { message => 'please set target' }); - } - - my $centcore_cmd = defined($options{data}->{content}->{centcore_cmd}) ? $options{data}->{content}->{centcore_dir} : '/var/lib/centreon/centcore/'; - my $time = Time::HiRes::time(); - $time =~ s/\.//g; - $centcore_cmd .= $time . '.cmd'; - - my $data = $options{data}->{content}->{command} . ':' . $options{data}->{content}->{target}; - $data .= ':' . $options{data}->{content}->{param} if (defined($options{data}->{content}->{param}) && $options{data}->{content}->{param} ne ''); - chomp $data; - - my $file = $self->{sftp}->open(file => $centcore_cmd, accesstype => O_WRONLY|O_CREAT|O_TRUNC, mode => 0660); - if (!defined($file)) { - return (-1, { message => "cannot open stat file '$centcore_cmd': " . $self->{sftp}->error() }); - } - if ($self->{sftp}->write(handle_file => $file, data => $data . "\n") != Libssh::Session::SSH_OK) { - return (-1, { message => "cannot write stat file '$centcore_cmd': " . $self->{sftp}->error() }); - } - - $self->{logger}->writeLogDebug("[sshclient] Action centcore - '" . $centcore_cmd . "' succeeded"); - return (0, { message => 'send action_centcore succeeded' }); -} - -sub action_actionengine { - my ($self, %options) = @_; - - # validate plugins unsupported with ssh - $self->action_command( - data => { - logging => $options{data}->{logging}, - content => [ - $options{data}->{content} - ] - }, - target_direct => $options{target_direct}, - target => $options{target}, - token => $options{token} - ); -} - -sub action_command { - my ($self, %options) = @_; - - if (!defined($options{data}->{content}) || ref($options{data}->{content}) ne 'ARRAY') { - return (-1, { message => "expected array, found '" . ref($options{data}->{content}) . "'" }); - } - - my $index = 0; - foreach my $command (@{$options{data}->{content}}) { - if (!defined($command->{command}) || $command->{command} eq '') { - return (-1, { message => "need command argument at array index '" . $index . "'" }); - } - $index++; - } - - my $errors = 0; - my $results; - - push @{$results}, { - code => GORGONE_ACTION_BEGIN, - data => { - message => "commands processing has started", - request_content => $options{data}->{content} - } - }; - - foreach my $command (@{$options{data}->{content}}) { - my ($code, $data) = (0, {}); - - push @{$results}, { - code => GORGONE_ACTION_BEGIN, - data => { - message => "command has started", - command => $command->{command}, - metadata => $command->{metadata} - } - }; - - if (defined($command->{metadata}->{centcore_proxy}) && $options{target_direct} == 0) { - ($code, $data->{data}) = $self->action_centcore( - data => { - content => { - command => $command->{metadata}->{centcore_cmd}, - target => $options{target}, - } - } - ); - $data->{code} = ($code < 0) ? GORGONE_ACTION_FINISH_KO : GORGONE_ACTION_FINISH_OK; - } else { - my $timeout = defined($command->{timeout}) && $command->{timeout} =~ /(\d+)/ ? $1 : 60; - my $timeout_nodata = defined($command->{timeout_nodata}) && $command->{timeout_nodata} =~ /(\d+)/ ? $1 : 30; - - my $start = time(); - my $ret = $self->execute_simple( - cmd => $command->{command}, - timeout => $timeout, - timeout_nodata => $timeout_nodata - ); - my $end = time(); - - $data = { - data => { - command => $command->{command}, - metadata => $command->{metadata}, - result => { - exit_code => $ret->{exit_code}, - stdout => $ret->{stdout}, - stderr => $ret->{stderr}, - }, - metrics => { - start => $start, - end => $end, - duration => $end - $start - } - } - }; - - if ($ret->{exit} == Libssh::Session::SSH_OK) { - $data->{data}->{message} = "command has finished successfully"; - $data->{code} = GORGONE_MODULE_ACTION_COMMAND_RESULT; - } elsif ($ret->{exit} == Libssh::Session::SSH_AGAIN) { # AGAIN means timeout - $code = -1; - $data->{data}->{message} = "command has timed out"; - $data->{code} = GORGONE_ACTION_FINISH_KO; - } else { - $code = -1; - $data->{data}->{message} = $self->error(GetErrorSession => 1); - $data->{code} = GORGONE_ACTION_FINISH_KO; - } - } - - push @{$results}, $data; - - if ($code < 0) { - if (defined($command->{continue_on_error}) && $command->{continue_on_error} == 0) { - push @{$results}, { - code => 1, - data => { - message => "commands processing has been interrupted because of error" - } - }; - return (-1, $results); - } - - $errors = 1; - } - } - - if ($errors) { - push @{$results}, { - code => GORGONE_ACTION_FINISH_KO, - data => { - message => "commands processing has finished with errors" - } - }; - return (-1, $results); - } - - push @{$results}, { - code => GORGONE_ACTION_FINISH_OK, - data => { - message => "commands processing has finished successfully" - } - }; - - return (0, $results); -} - -sub action_enginecommand { - my ($self, %options) = @_; - - my $results; - - if ($options{target_direct} == 0) { - foreach my $command (@{$options{data}->{content}->{commands}}) { - chomp $command; - my $msg = "[sshclient] Handling command 'EXTERNALCMD'"; - $msg .= ", Target: '" . $options{target} . "'" if (defined($options{target})); - $msg .= ", Parameters: '" . $command . "'" if (defined($command)); - $self->{logger}->writeLogInfo($msg); - my ($code, $data) = $self->action_centcore( - data => { - content => { - command => 'EXTERNALCMD', - target => $options{target}, - param => $command, - } - } - ); - } - } else { - if (!defined($options{data}->{content}->{command_file}) || $options{data}->{content}->{command_file} eq '') { - $self->{logger}->writeLogError("[sshclient] Need command_file argument"); - return (-1, { message => "need command_file argument" }); - } - - my $command_file = $options{data}->{content}->{command_file}; - - my $ret = $self->{sftp}->stat_file(file => $command_file); - if (!defined($ret)) { - $self->{logger}->writeLogError("[sshclient] Command file '$command_file' must exist"); - return (-1, { message => "command file '$command_file' must exist", error => $self->{sftp}->get_msg_error() }); - } - - if ($ret->{type} != SSH_FILEXFER_TYPE_SPECIAL) { - $self->{logger}->writeLogError("[sshclient] Command file '$command_file' must be a pipe file"); - return (-1, { message => "command file '$command_file' must be a pipe file" }); - } - - my $file = $self->{sftp}->open(file => $command_file, accesstype => O_WRONLY|O_APPEND, mode => 0660); - if (!defined($file)) { - $self->{logger}->writeLogError("[sshclient] Cannot open command file '$command_file'"); - return (-1, { message => "cannot open command file '$command_file'", error => $self->{sftp}->error() }); - } - - push @{$results}, { - code => GORGONE_ACTION_BEGIN, - data => { - message => "commands processing has started", - request_content => $options{data}->{content} - } - }; - - foreach my $command (@{$options{data}->{content}->{commands}}) { - $self->{logger}->writeLogInfo("[sshclient] Processing external command '" . $command . "'"); - if ($self->{sftp}->write(handle_file => $file, data => $command . "\n") != Libssh::Session::SSH_OK) { - $self->{logger}->writeLogError("[sshclient] Command file '$command_file' must be writeable"); - push @{$results}, { - code => GORGONE_ACTION_FINISH_KO, - data => { - message => "command file '$command_file' must be writeable", - error => $self->{sftp}->error() - } - }; - - return (-1, $results); - } - - push @{$results}, { - code => GORGONE_ACTION_FINISH_OK, - data => { - message => "command has been submitted", - command => $command - } - }; - } - } - - push @{$results}, { - code => GORGONE_ACTION_FINISH_OK, - data => { - message => "commands processing has finished" - } - }; - - return (0, $results); -} - -sub action_processcopy { - my ($self, %options) = @_; - - if (!defined($options{data}->{content}->{status}) || $options{data}->{content}->{status} !~ /^(?:inprogress|end)$/) { - $self->{logger}->writeLogError('[sshclient] Action process copy - need status'); - return (-1, { message => 'please set status' }); - } - if (!defined($options{data}->{content}->{type}) || $options{data}->{content}->{type} !~ /^(?:archive|regular)$/) { - $self->{logger}->writeLogError('[sshclient] Action process copy - need type'); - return (-1, { message => 'please set type' }); - } - if (!defined($options{data}->{content}->{cache_dir}) || $options{data}->{content}->{cache_dir} eq '') { - $self->{logger}->writeLogError('[sshclient] Action process copy - need cache_dir'); - return (-1, { message => 'please set cache_dir' }); - } - if ($options{data}->{content}->{status} eq 'end' && - (!defined($options{data}->{content}->{destination}) || $options{data}->{content}->{destination} eq '')) { - $self->{logger}->writeLogError('[sshclient] Action process copy - need destination'); - return (-1, { message => 'please set destination' }); - } - - my $copy_local_file = $options{data}->{content}->{cache_dir} . '/copy_local_' . $options{token}; - if ($options{data}->{content}->{status} eq 'inprogress') { - my $fh; - if (!sysopen($fh, $copy_local_file, O_RDWR|O_APPEND|O_CREAT, 0660)) { - return (-1, { message => "file '$copy_local_file' open failed: $!" }); - } - binmode($fh); - syswrite( - $fh, - MIME::Base64::decode_base64($options{data}->{content}->{chunk}->{data}), - $options{data}->{content}->{chunk}->{size} - ); - close $fh; - - return (0, [{ - code => GORGONE_MODULE_ACTION_PROCESSCOPY_INPROGRESS, - data => { - message => 'process copy inprogress' - } - }]); - } - if ($options{data}->{content}->{status} eq 'end') { - my $copy_file = $options{data}->{content}->{cache_dir} . '/copy_' . $options{token}; - my $code = $self->{sftp}->copy_file(src => $copy_local_file, dst => $copy_file); - unlink($copy_local_file); - if ($code == -1) { - return (-1, { message => "cannot sftp copy file : " . $self->{sftp}->error() }); - } - - if ($options{data}->{content}->{type} eq 'archive') { - return $self->action_command( - data => { - content => [ { command => "tar zxf $copy_file -C '" . $options{data}->{content}->{destination} . "' ." } ] - } - ); - } - if ($options{data}->{content}->{type} eq 'regular') { - return $self->action_command( - data => { - content => [ { command => "cp -f $copy_file '$options{data}->{content}->{destination}'" } ] - } - ); - } - } - - return (-1, { message => 'process copy unknown error' }); -} - -sub action_remotecopy { - my ($self, %options) = @_; - - if (!defined($options{data}->{content}->{source}) || $options{data}->{content}->{source} eq '') { - $self->{logger}->writeLogError('[sshclient] Action remote copy - need source'); - return (-1, { message => 'please set source' }); - } - if (!defined($options{data}->{content}->{destination}) || $options{data}->{content}->{destination} eq '') { - $self->{logger}->writeLogError('[sshclient] Action remote copy - need destination'); - return (-1, { message => 'please set destination' }); - } - - my ($code, $message, $data); - - my $srcname; - my $localsrc = $options{data}->{content}->{source}; - my $src = $options{data}->{content}->{source}; - my ($dst, $dst_sftp) = ($options{data}->{content}->{destination}, $options{data}->{content}->{destination}); - if ($options{target_direct} == 0) { - $dst = $src; - $dst_sftp = $src; - } - - if (-f $options{data}->{content}->{source}) { - $localsrc = $src; - $srcname = File::Basename::basename($src); - $dst_sftp .= $srcname if ($dst =~ /\/$/); - } elsif (-d $options{data}->{content}->{source}) { - $srcname = (defined($options{data}->{content}->{type}) ? $options{data}->{content}->{type} : 'tmp') . '-' . $options{target} . '.tar.gz'; - $localsrc = $options{data}->{content}->{cache_dir} . '/' . $srcname; - $dst_sftp = $options{data}->{content}->{cache_dir} . '/' . $srcname; - - ($code, $message) = $self->local_command(command => "tar czf $localsrc -C '" . $src . "' ."); - return ($code, $message) if ($code == -1); - } else { - return (-1, { message => 'unknown source' }); - } - - if (($code = $self->{sftp}->copy_file(src => $localsrc, dst => $dst_sftp)) == -1) { - return (-1, { message => "cannot sftp copy file : " . $self->{sftp}->error() }); - } - - if (-d $options{data}->{content}->{source}) { - ($code, $data) = $self->action_command( - data => { - content => [ { command => "tar zxf $dst_sftp -C '" . $dst . "' ." } ] - } - ); - return ($code, $data) if ($code == -1); - } - - if (defined($options{data}->{content}->{metadata}->{centcore_proxy}) && $options{target_direct} == 0) { - $self->action_centcore( - data => { - content => { - command => $options{data}->{content}->{metadata}->{centcore_cmd}, - target => $options{target}, - } - } - ); - } - - return (0, { message => 'send remotecopy succeeded' }); -} - -sub action { - my ($self, %options) = @_; - - my $func = $self->can('action_' . lc($options{action})); - if (defined($func)) { - return $func->( - $self, - data => $options{data}, - target_direct => $options{target_direct}, - target => $options{target}, - token => $options{token} - ); - } - - $self->{logger}->writeLogError("[sshclient] Unsupported action '" . $options{action} . "'"); - return (-1, { message => 'unsupported action' }); -} - -sub close { - my ($self, %options) = @_; - - $self->disconnect(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/pull/class.pm b/centreon-gorgone/gorgone/modules/core/pull/class.pm deleted file mode 100644 index 230cf96dd9..0000000000 --- a/centreon-gorgone/gorgone/modules/core/pull/class.pm +++ /dev/null @@ -1,233 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::pull::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::class::db; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::clientzmq; -use JSON::XS; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{ping_timer} = time(); - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[pipeline] -class- $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub exit_process { - my ($self, %options) = @_; - - $self->{logger}->writeLogInfo("[pull] $$ has quit"); - - $self->{client}->send_message( - action => 'UNREGISTERNODES', - data => { nodes => [ { id => $self->get_core_config(name => 'id') } ] }, - json_encode => 1 - ); - $self->{client}->close(); - - exit(0); -} - -sub ping { - my ($self, %options) = @_; - - return if ((time() - $self->{ping_timer}) < 60); - - $self->{ping_timer} = time(); - - $self->{client}->ping( - poll => $self->{poll}, - action => 'REGISTERNODES', - data => { nodes => [ { id => $self->get_core_config(name => 'id'), type => 'pull', identity => $self->{client}->get_connect_identity() } ] }, - json_encode => 1 - ); -} - -sub transmit_back { - my (%options) = @_; - - return undef if (!defined($options{message})); - - if ($options{message} =~ /^\[ACK\]\s+\[(.*?)\]\s+(.*)/m) { - my $data; - eval { - $data = JSON::XS->new->decode($2); - }; - if ($@) { - return $options{message}; - } - - if (defined($data->{data}->{action}) && $data->{data}->{action} eq 'getlog') { - return '[SETLOGS] [' . $1 . '] [] ' . $2; - } - return undef; - } elsif ($options{message} =~ /^\[BCASTCOREKEY\]\s+\[.*?\]\s+\[.*?\]\s+(.*)/m) { - my $data; - eval { - $data = JSON::XS->new->decode($1); - }; - if ($@) { - $connector->{logger}->writeLogDebug("[pull] cannot decode BCASTCOREKEY: $@"); - return undef; - } - - $connector->action_bcastcorekey(data => $data); - return undef; - } elsif ($options{message} =~ /^\[(PONG|SYNCLOGS)\]/) { - return $options{message}; - } - return undef; -} - -sub read_message_client { - my (%options) = @_; - - # We skip. Dont need to send it in gorgone-core - if ($options{data} =~ /^\[ACK\]/) { - return undef; - } - - $connector->{logger}->writeLogDebug("[pull] read message from external: $options{data}"); - $connector->send_internal_action({ message => $options{data} }); -} - -sub event { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($message) = $self->read_message(); - $message = transmit_back(message => $message); - next if (!defined($message)); - - # Only send back SETLOGS and PONG - $self->{logger}->writeLogDebug("[pull] read message from internal: $message"); - $self->{client}->send_message(message => $message); - } -} - -sub periodic_exec { - my ($self, %options) = @_; - - if ($self->{stop} == 1) { - $self->exit_process(); - } - - $self->ping(); -} - -sub run { - my ($self, %options) = @_; - - # Connect internal - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-pull', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'PULLREADY', - data => {} - }); - - $self->{client} = gorgone::class::clientzmq->new( - context => $self->{zmq_context}, - core_loop => $self->{loop}, - identity => 'gorgone-' . $self->get_core_config(name => 'id'), - cipher => $self->{config}->{cipher}, - vector => $self->{config}->{vector}, - client_pubkey => - defined($self->{config}->{client_pubkey}) && $self->{config}->{client_pubkey} ne '' ? - $self->{config}->{client_pubkey} : $self->get_core_config(name => 'pubkey'), - client_privkey => - defined($self->{config}->{client_privkey}) && $self->{config}->{client_privkey} ne '' ? - $self->{config}->{client_privkey} : $self->get_core_config(name => 'privkey'), - target_type => $self->{config}->{target_type}, - target_path => $self->{config}->{target_path}, - config_core => $self->get_core_config(), - logger => $self->{logger}, - ping => $self->{config}->{ping}, - ping_timeout => $self->{config}->{ping_timeout} - ); - $self->{client}->init(callback => \&read_message_client); - - $self->{client}->send_message( - action => 'REGISTERNODES', - data => { nodes => [ { id => $self->get_core_config(name => 'id'), type => 'pull', identity => $self->{client}->get_connect_identity() } ] }, - json_encode => 1 - ); - - $self->periodic_exec(); - - my $watcher_timer = $self->{loop}->timer(5, 5, sub { $connector->periodic_exec() }); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/pull/hooks.pm b/centreon-gorgone/gorgone/modules/core/pull/hooks.pm deleted file mode 100644 index eb628261a9..0000000000 --- a/centreon-gorgone/gorgone/modules/core/pull/hooks.pm +++ /dev/null @@ -1,153 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::pull::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::pull::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'pull'; -use constant EVENTS => [ - { event => 'PULLREADY' } -]; - -my $config_core; -my $config; -my $pull = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'PULLREADY') { - $pull->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$pull->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-pull: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-pull', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($pull->{running}) && $pull->{running} == 1) { - $options{logger}->writeLogDebug("[pull] Send TERM signal $pull->{pid}"); - CORE::kill('TERM', $pull->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($pull->{running} == 1) { - $options{logger}->writeLogDebug("[pull] Send KILL signal for pool"); - CORE::kill('KILL', $pull->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - - return 0; -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($pull->{pid}) || $pull->{pid} != $pid); - - $pull = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($pull->{running}) && $pull->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[pull] Create module 'pull' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-pull'; - my $module = gorgone::modules::core::pull::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[pull] PID $child_pid (gorgone-pull)"); - $pull = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/pullwss/class.pm b/centreon-gorgone/gorgone/modules/core/pullwss/class.pm deleted file mode 100644 index 5745dd21d5..0000000000 --- a/centreon-gorgone/gorgone/modules/core/pullwss/class.pm +++ /dev/null @@ -1,282 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::pullwss::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::standard::misc; -use Mojo::UserAgent; -use IO::Socket::SSL; -use IO::Handle; -use JSON::XS; -use EV; -use HTML::Entities; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{ping_timer} = -1; - $connector->{connected} = 0; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogDebug("[pullwss] $$ Receiving order to stop..."); - $self->{stop} = 1; - - my $message = gorgone::standard::library::build_protocol( - action => 'UNREGISTERNODES', - data => { - nodes => [ - { - id => $self->get_core_config(name => 'id'), - type => 'wss', - identity => $self->get_core_config(name => 'id') - } - ] - }, - json_encode => 1 - ); - - if ($self->{connected} == 1) { - $self->{tx}->send({text => $message }); - $self->{tx}->on(drain => sub { Mojo::IOLoop->stop_gracefully(); }); - } else { - Mojo::IOLoop->stop_gracefully(); - } -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub send_message { - my ($self, %options) = @_; - my $message = HTML::Entities::encode_entities($options{message}); - $self->{tx}->send({text => $message }); -} - -sub ping { - my ($self, %options) = @_; - - return if ($self->{ping_timer} != -1 && (time() - $self->{ping_timer}) < 30); - - $self->{ping_timer} = time(); - - my $message = gorgone::standard::library::build_protocol( - action => 'REGISTERNODES', - data => { - nodes => [ - { - id => $self->get_core_config(name => 'id'), - type => 'wss', - identity => $self->get_core_config(name => 'id') - } - ] - }, - json_encode => 1 - ); - - $self->{tx}->send({text => $message }) if ($self->{connected} == 1); -} - -sub wss_connect { - my ($self, %options) = @_; - - return if ($connector->{connected} == 1); - - $self->{ua} = Mojo::UserAgent->new(); - $self->{ua}->transactor->name('gorgone mojo'); - - if (defined($self->{config}->{proxy}) && $self->{config}->{proxy} ne '') { - $self->{ua}->proxy->http($self->{config}->{proxy})->https($self->{config}->{proxy}); - } - - my $proto = 'ws'; - if (defined($self->{config}->{ssl}) && $self->{config}->{ssl} eq 'true') { - $proto = 'wss'; - $self->{ua}->insecure(1); - } - - $self->{ua}->websocket( - $proto . '://' . $self->{config}->{address} . ':' . $self->{config}->{port} . '/' => { Authorization => 'Bearer ' . $self->{config}->{token} } => sub { - my ($ua, $tx) = @_; - - $connector->{tx} = $tx; - $connector->{logger}->writeLogError('[pullwss] ' . $tx->res->error->{message}) if $tx->res->error; - $connector->{logger}->writeLogError('[pullwss] webSocket handshake failed') and return unless $tx->is_websocket; - - $connector->{tx}->on( - finish => sub { - my ($tx, $code, $reason) = @_; - - $connector->{connected} = 0; - $connector->{logger}->writeLogError('[pullwss] websocket closed with status ' . $code); - } - ); - $connector->{tx}->on( - message => sub { - my ($tx, $msg) = @_; - - # We skip. Dont need to send it in gorgone-core - return undef if ($msg =~ /^\[ACK\]/); - - if ($msg =~ /^\[.*\]/) { - $connector->{logger}->writeLogDebug('[pullwss] websocket message: ' . $msg); - $connector->send_internal_action({message => $msg}); - $self->read_zmq_events(); - } else { - $connector->{logger}->writeLogInfo('[pullwss] websocket message: ' . $msg); - } - } - ); - - $connector->{logger}->writeLogInfo('[pullwss] websocket connected'); - $connector->{connected} = 1; - $connector->{ping_timer} = -1; - $connector->ping(); - } - ); - $self->{ua}->inactivity_timeout(120); -} - -sub run { - my ($self, %options) = @_; - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-pullwss', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'PULLWSSREADY', - data => {} - }); - $self->read_zmq_events(); - - $self->wss_connect(); - - my $socket_fd = gorgone::standard::library::zmq_getfd(socket => $self->{internal_socket}); - my $socket = IO::Handle->new_from_fd($socket_fd, 'r'); - Mojo::IOLoop->singleton->reactor->io($socket => sub { - $connector->read_zmq_events(); - }); - Mojo::IOLoop->singleton->reactor->watch($socket, 1, 0); - - Mojo::IOLoop->singleton->recurring(60 => sub { - $connector->{logger}->writeLogDebug('[pullwss] recurring timeout loop'); - $connector->wss_connect(); - $connector->ping(); - }); - - Mojo::IOLoop->start() unless (Mojo::IOLoop->is_running); - - exit(0); -} - -sub transmit_back { - my (%options) = @_; - - return undef if (!defined($options{message})); - - if ($options{message} =~ /^\[ACK\]\s+\[(.*?)\]\s+(.*)/m) { - my $data; - eval { - $data = JSON::XS->new->decode($2); - }; - if ($@) { - return $options{message}; - } - - if (defined($data->{data}->{action}) && $data->{data}->{action} eq 'getlog') { - return '[SETLOGS] [' . $1 . '] [] ' . $2; - } - return undef; - } elsif ($options{message} =~ /^\[BCASTCOREKEY\]\s+\[.*?\]\s+\[.*?\]\s+(.*)/m) { - my $data; - eval { - $data = JSON::XS->new->decode($1); - }; - if ($@) { - $connector->{logger}->writeLogDebug("[pull] cannot decode BCASTCOREKEY: $@"); - return undef; - } - - $connector->action_bcastcorekey(data => $data); - return undef; - } elsif ($options{message} =~ /^\[(PONG|SYNCLOGS)\]/) { - return $options{message}; - } - return undef; -} - -sub read_zmq_events { - my ($self, %options) = @_; - - while ($self->{internal_socket}->has_pollin()) { - my ($message) = $connector->read_message(); - $message = transmit_back(message => $message); - next if (!defined($message)); - - # Only send back SETLOGS and PONG - $connector->{logger}->writeLogDebug("[pullwss] read message from internal: $message"); - $connector->send_message(message => $message); - } -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/pullwss/hooks.pm b/centreon-gorgone/gorgone/modules/core/pullwss/hooks.pm deleted file mode 100644 index 62199d5815..0000000000 --- a/centreon-gorgone/gorgone/modules/core/pullwss/hooks.pm +++ /dev/null @@ -1,169 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::pullwss::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::pullwss::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'pullwss'; -use constant EVENTS => [ - { event => 'PULLWSSREADY' } -]; - -my $config_core; -my $config; -my $pullwss = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - my $loaded = 1; - $config = $options{config}; - $config_core = $options{config_core}; - - if (!defined($config->{address}) || $config->{address} =~ /^\s*$/) { - $options{logger}->writeLogError('[pullwss] address option mandatory'); - $loaded = 0; - } - if (!defined($config->{port}) || $config->{port} !~ /^\d+$/) { - $options{logger}->writeLogError('[pullwss] port option mandatory'); - $loaded = 0; - } - if (!defined($config->{token}) || $config->{token} =~ /^\s*$/) { - $options{logger}->writeLogError('[pullwss] token option mandatory'); - $loaded = 0; - } - - return ($loaded, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'PULLWSSREADY') { - $pullwss->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$pullwss->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-pullwss: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-pullwss', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($pullwss->{running}) && $pullwss->{running} == 1) { - $options{logger}->writeLogDebug("[pullwss] Send TERM signal $pullwss->{pid}"); - CORE::kill('TERM', $pullwss->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($pullwss->{running} == 1) { - $options{logger}->writeLogDebug("[pullwss] Send KILL signal for $pullwss->{pid}"); - CORE::kill('KILL', $pullwss->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($pullwss->{pid}) || $pullwss->{pid} != $pid); - - $pullwss = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - - last; - } - - $count++ if (defined($pullwss->{running}) && $pullwss->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[pullwss] Create module 'pullwss' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-pullwss'; - my $module = gorgone::modules::core::pullwss::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[pullwss] PID $child_pid (gorgone-pullwss)"); - $pullwss = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/register/class.pm b/centreon-gorgone/gorgone/modules/core/register/class.pm deleted file mode 100644 index 8adab31c01..0000000000 --- a/centreon-gorgone/gorgone/modules/core/register/class.pm +++ /dev/null @@ -1,170 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::register::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use JSON::XS; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{register_nodes} = {}; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogInfo("[register] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub action_registerresync { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->send_log( - code => GORGONE_ACTION_BEGIN, - token => $options{token}, - data => { - message => 'action registerresync proceed' - } - ); - - my $config = gorgone::standard::library::read_config( - config_file => $self->{config}->{config_file}, - logger => $self->{logger} - ); - - my $register_temp = {}; - my $register_nodes = []; - if (defined($config->{nodes})) { - foreach (@{$config->{nodes}}) { - $self->{register_nodes}->{$_->{id}} = 1; - $register_temp->{$_->{id}} = 1; - push @{$register_nodes}, { %$_ }; - } - } - - my $unregister_nodes = []; - foreach (keys %{$self->{register_nodes}}) { - if (!defined($register_temp->{$_})) { - push @{$unregister_nodes}, { id => $_ }; - delete $self->{register_nodes}->{$_}; - } - } - - $self->send_internal_action({ - action => 'REGISTERNODES', - data => { - nodes => $register_nodes - } - }) if (scalar(@$register_nodes) > 0); - - $self->send_internal_action({ - action => 'UNREGISTERNODES', - data => { - nodes => $unregister_nodes - } - }) if (scalar(@$unregister_nodes) > 0); - - $self->{logger}->writeLogDebug("[register] Finish resync"); - $self->send_log( - code => GORGONE_ACTION_FINISH_OK, - token => $options{token}, - data => { - message => 'action registerresync finished' - } - ); - return 0; -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[register] $$ has quit"); - exit(0); - } -} - -sub run { - my ($self, %options) = @_; - - # Connect internal - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-register', - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'REGISTERREADY', - data => {} - }); - - $self->action_registerresync(); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/core/register/hooks.pm b/centreon-gorgone/gorgone/modules/core/register/hooks.pm deleted file mode 100644 index 82d49e2657..0000000000 --- a/centreon-gorgone/gorgone/modules/core/register/hooks.pm +++ /dev/null @@ -1,158 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::core::register::hooks; - -use warnings; -use strict; -use gorgone::class::core; -use gorgone::modules::core::register::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'core'; -use constant NAME => 'register'; -use constant EVENTS => [ - { event => 'REGISTERREADY' }, -]; - -my $config_core; -my $config; -my ($config_db_centreon); -my $register = {}; -my $stop = 0; - -sub register { - my (%options) = @_; - - my $loaded = 1; - $config = $options{config}; - $config_core = $options{config_core}; - if (!defined($config->{config_file}) || $config->{config_file} =~ /^\s*$/) { - $options{logger}->writeLogError("[register] Option 'config_file' mandatory"); - $loaded = 0; - } - return ($loaded, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - create_child(logger => $options{logger}); -} - -sub routing { - my (%options) = @_; - - if ($options{action} eq 'REGISTERREADY') { - $register->{ready} = 1; - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$register->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgoneregister: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-register', - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - if (defined($register->{running}) && $register->{running} == 1) { - $options{logger}->writeLogDebug("[register] Send TERM signal $register->{pid}"); - CORE::kill('TERM', $register->{pid}); - } -} - -sub kill { - my (%options) = @_; - - if ($register->{running} == 1) { - $options{logger}->writeLogDebug("[register] Send KILL signal for pool"); - CORE::kill('KILL', $register->{pid}); - } -} - -sub kill_internal { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($register->{pid}) || $register->{pid} != $pid); - - $register = {}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - create_child(logger => $options{logger}); - } - } - - $count++ if (defined($register->{running}) && $register->{running} == 1); - - return $count; -} - -sub broadcast { - my (%options) = @_; - - routing(%options); -} - -# Specific functions -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[register] Create module 'register' process"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-register'; - my $module = gorgone::modules::core::register::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[register] PID $child_pid (gorgone-register)"); - $register = { pid => $child_pid, ready => 0, running => 1 }; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/plugins/newtest/class.pm b/centreon-gorgone/gorgone/modules/plugins/newtest/class.pm deleted file mode 100644 index 2b45bbf5fe..0000000000 --- a/centreon-gorgone/gorgone/modules/plugins/newtest/class.pm +++ /dev/null @@ -1,662 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::plugins::newtest::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::misc; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::sqlquery; -use MIME::Base64; -use JSON::XS; -use Data::Dumper; -use gorgone::modules::plugins::newtest::libs::stubs::ManagementConsoleService; -use gorgone::modules::plugins::newtest::libs::stubs::errors; -use Date::Parse; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{config_newtest} = $options{config_newtest}; - - $connector->{resync_time} = $options{config_newtest}->{resync_time}; - $connector->{last_resync_time} = time() - $connector->{resync_time}; - - $connector->{endpoint} = $options{config_newtest}->{nmc_endpoint}; - $connector->{nmc_username} = $options{config_newtest}->{nmc_username}; - $connector->{nmc_password} = $options{config_newtest}->{nmc_password}; - $connector->{nmc_timeout} = $options{config_newtest}->{nmc_timeout}; - $connector->{poller_name} = $options{config_newtest}->{poller_name}; - $connector->{list_scenario_status} = $options{config_newtest}->{list_scenario_status}; - $connector->{host_template} = $options{config_newtest}->{host_template}; - $connector->{host_prefix} = $options{config_newtest}->{host_prefix}; - $connector->{service_template} = $options{config_newtest}->{service_template}; - $connector->{service_prefix} = $options{config_newtest}->{service_prefix}; - - $connector->{clapi_generate_config_timeout} = defined($options{config}->{clapi_generate_config_timeout}) ? $options{config}->{clapi_generate_config_timeout} : 180; - $connector->{clapi_timeout} = defined($options{config}->{clapi_timeout}) ? $options{config}->{clapi_timeout} : 10; - $connector->{clapi_command} = defined($options{config}->{clapi_command}) && $options{config}->{clapi_command} ne '' ? $options{config}->{clapi_command} : '/usr/bin/centreon'; - $connector->{clapi_username} = $options{config}->{clapi_username}; - $connector->{clapi_password} = $options{config}->{clapi_password}; - $connector->{clapi_action_applycfg} = $options{config}->{clapi_action_applycfg}; - $connector->{cmdFile} = defined($options{config}->{centcore_cmd}) && $options{config}->{centcore_cmd} ne '' ? $options{config}->{centcore_cmd} : '/var/lib/centreon/centcore.cmd'; - $connector->{illegal_characters} = defined($options{config}->{illegal_characters}) && $options{config}->{illegal_characters} ne '' ? $options{config}->{illegal_characters} : '~!$%^&*"|\'<>?,()='; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogInfo("[newtest] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -my %map_scenario_status = ( - Available => 0, Warning => 1, Failed => 2, Suspended => 2, - Canceled => 2, Unknown => 3, - OutOfRange => 0, # Not Scheduled scenario -); - -my %map_newtest_units = ( - Second => 's', Millisecond => 'ms', BytePerSecond => 'Bps', UnitLess => '', Unknown => '', -); - -my %map_service_status = ( - 0 => 'OK', 1 => 'WARNING', 2 => 'CRITICAL', 3 => 'UNKNOWN', 4 => 'PENDING', -); - -sub newtestresync_init { - my ($self, %options) = @_; - - # list from robot/scenario from db - # Format = { robot_name1 => { scenario1 => { last_execution_time => xxxx }, scenario2 => { } }, ... } - $self->{db_newtest} = {}; - $self->{api_newtest} = {}; - $self->{poller_id} = undef; - $self->{must_push_config} = 0; - $self->{external_commands} = []; - $self->{perfdatas} = []; - $self->{cache_robot_list_results} = undef; -} - -sub perfdata_add { - my ($self, %options) = @_; - - my $perfdata = {label => '', value => '', unit => '', warning => '', critical => '', min => '', max => ''}; - foreach (keys %options) { - next if (!defined($options{$_})); - $perfdata->{$_} = $options{$_}; - } - $perfdata->{label} =~ s/'/''/g; - push @{$self->{perfdatas}}, $perfdata; -} - -sub add_output { - my ($self, %options) = @_; - - my $str = $map_service_status{$self->{current_status}} . ': ' . $self->{current_text} . '|'; - foreach my $perf (@{$self->{perfdatas}}) { - $str .= " '" . $perf->{label} . "'=" . $perf->{value} . $perf->{unit} . ";" . $perf->{warning} . ";" . $perf->{critical} . ";" . $perf->{min} . ";" . $perf->{max}; - } - $self->{perfdatas} = []; - - $self->push_external_cmd( - cmd => 'PROCESS_SERVICE_CHECK_RESULT;' . $options{host_name} . ';' . - $options{service_name} . ';' . $self->{current_status} . ';' . $str, - time => $options{time} - ); -} - -sub convert_measure { - my ($self, %options) = @_; - - if (defined($map_newtest_units{$options{unit}}) && - $map_newtest_units{$options{unit}} eq 'ms') { - $options{value} /= 1000; - $options{unit} = 's'; - } - return ($options{value}, $options{unit}); -} - -sub get_poller_id { - my ($self, %options) = @_; - - my ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => 'SELECT id FROM nagios_server WHERE name = ?', - bind_values => [$self->{poller_name}], - mode => 2 - ); - if ($status == -1) { - $self->{logger}->writeLogError("[newtest] cannot get poller id for poller '" . $self->{poller_name} . "'."); - return 1; - } - - if (!defined($datas->[0])) { - $self->{logger}->writeLogError("[newtest] cannot find poller id for poller '" . $self->{poller_name} . "'."); - return 1; - } - - $self->{poller_id} = $datas->[0]->[0]; - return 0; -} - -sub get_centreondb_cache { - my ($self, %options) = @_; - - my $request = " - SELECT host.host_name, service.service_description - FROM host - LEFT JOIN (host_service_relation, service) ON - (host_service_relation.host_host_id = host.host_id AND - service.service_id = host_service_relation.service_service_id AND - service.service_description LIKE ?) - WHERE host_name LIKE ? AND host_register = '1'"; - $request =~ s/%s/%/g; - my ($status, $datas) = $self->{class_object_centreon}->custom_execute( - request => $request, - bind_values => [$self->{service_prefix}, $self->{host_prefix}], - mode => 2 - ); - if ($status == -1) { - $self->{logger}->writeLogError("[newtest] cannot get robot/scenarios list from centreon db."); - return 1; - } - - foreach (@$datas) { - $self->{db_newtest}->{$_->[0]} = {} if (!defined($self->{db_newtest}->{$_->[0]})); - if (defined($_->[1])) { - $self->{db_newtest}->{$_->[0]}->{$_->[1]} = {}; - } - } - - return 0; -} - -sub get_centstoragedb_cache { - my ($self, %options) = @_; - - my $request = 'SELECT hosts.name, services.description, services.last_check - FROM hosts LEFT JOIN services ON (services.host_id = hosts.host_id AND services.description LIKE ? - WHERE name like ?'; - $request =~ s/%s/%/g; - my ($status, $datas) = $self->{class_object_centstorage}->custom_execute( - request => $request, - bind_values => [$self->{service_prefix}, $self->{host_prefix}], - mode => 2 - ); - if ($status == -1) { - $self->{logger}->writeLogError("[newtest] cannot get robot/scenarios list from centstorage db."); - return 1; - } - - foreach (@$datas) { - if (!defined($self->{db_newtest}->{$_->[0]})) { - $self->{logger}->writeLogError("[newtest] host '" . $_->[0] . "'is in censtorage DB but not in centreon config..."); - next; - } - if (defined($_->[1]) && !defined($self->{db_newtest}->{$_->[0]}->{$_->[1]})) { - $self->{logger}->writeLogError("[newtest] host scenario '" . $_->[0] . "/" . $_->[1] . "' is in censtorage DB but not in centreon config..."); - next; - } - - if (defined($_->[1])) { - $self->{db_newtest}->{$_->[0]}->{$_->[1]}->{last_execution_time} = $_->[2]; - } - } - - return 0; -} - -sub clapi_execute { - my ($self, %options) = @_; - - my $cmd = $self->{clapi_command} . " -u '" . $self->{clapi_username} . "' -p '" . $self->{clapi_password} . "' " . $options{cmd}; - my ($lerror, $stdout, $exit_code) = gorgone::standard::misc::backtick( - command => $cmd, - logger => $self->{logger}, - timeout => $options{timeout}, - wait_exit => 1, - ); - if ($lerror == -1 || ($exit_code >> 8) != 0) { - $self->{logger}->writeLogError("[newtest] clapi execution problem for command $cmd : " . $stdout); - return -1; - } - - return 0; -} - -sub push_external_cmd { - my ($self, %options) = @_; - my $time = defined($options{time}) ? $options{time} : time(); - - push @{$self->{external_commands}}, - 'EXTERNALCMD:' . $self->{poller_id} . ':[' . $time . '] ' . $options{cmd}; -} - -sub submit_external_cmd { - my ($self, %options) = @_; - - foreach my $cmd (@{$self->{external_commands}}) { - my ($lerror, $stdout, $exit_code) = gorgone::standard::misc::backtick(command => '/bin/echo "' . $cmd . '" >> ' . $self->{cmdFile}, - logger => $self->{logger}, - timeout => 5, - wait_exit => 1 - ); - if ($lerror == -1 || ($exit_code >> 8) != 0) { - $self->{logger}->writeLogError("[newtest] clapi execution problem for command $cmd : " . $stdout); - return -1; - } - } -} - -sub push_config { - my ($self, %options) = @_; - - if ($self->{must_push_config} == 1) { - $self->{logger}->writeLogInfo("[newtest] generation config for '$self->{poller_name}':"); - if ($self->clapi_execute(cmd => '-a POLLERGENERATE -v ' . $self->{poller_id}, - timeout => $self->{clapi_generate_config_timeout}) != 0) { - $self->{logger}->writeLogError("[newtest] generation config for '$self->{poller_name}': failed"); - return ; - } - $self->{logger}->writeLogInfo("[newtest] generation config for '$self->{poller_name}': succeeded."); - - $self->{logger}->writeLogInfo("[newtest] move config for '$self->{poller_name}':"); - if ($self->clapi_execute(cmd => '-a CFGMOVE -v ' . $self->{poller_id}, - timeout => $self->{clapi_timeout}) != 0) { - $self->{logger}->writeLogError("[newtest] move config for '$self->{poller_name}': failed"); - return ; - } - $self->{logger}->writeLogInfo("[newtest] move config for '$self->{poller_name}': succeeded."); - - $self->{logger}->writeLogInfo("[newtest] restart/reload config for '$self->{poller_name}':"); - if ($self->clapi_execute(cmd => '-a ' . $self->{clapi_action_applycfg} . ' -v ' . $self->{poller_id}, - timeout => $self->{clapi_timeout}) != 0) { - $self->{logger}->writeLogError("[newtest] restart/reload config for '$self->{poller_name}': failed"); - return ; - } - $self->{logger}->writeLogInfo("[newtest] restart/reload config for '$self->{poller_name}': succeeded."); - } -} - -sub get_newtest_diagnostic { - my ($self, %options) = @_; - - my $result = $self->{instance}->ListMessages('Instance', 30, 'Diagnostics', [$options{scenario}, $options{robot}]); - if (defined(my $com_error = gorgone::modules::plugins::newtest::libs::stubs::errors::get_error())) { - $self->{logger}->writeLogError("[newtest] newtest API error 'ListMessages' method: " . $com_error); - return -1; - } - - if (!(ref($result) && defined($result->{MessageItem}))) { - $self->{logger}->writeLogError("[newtest] no diagnostic found for scenario: " . $options{scenario} . '/' . $options{robot}); - return 1; - } - if (ref($result->{MessageItem}) eq 'HASH') { - $result->{MessageItem} = [$result->{MessageItem}]; - } - - my $macro_value = ''; - my $macro_append = ''; - foreach my $item (@{$result->{MessageItem}}) { - if (defined($item->{SubCategory})) { - $macro_value .= $macro_append . $item->{SubCategory} . ':' . $item->{Id}; - $macro_append = '|'; - } - } - - if ($macro_value ne '') { - $self->push_external_cmd(cmd => - 'CHANGE_CUSTOM_SVC_VAR;' . $options{host_name} . ';' . - $options{service_name} . ';NEWTEST_MESSAGEID;' . $macro_value - ); - } - return 0; -} - -sub get_scenario_results { - my ($self, %options) = @_; - - # Already test the robot but no response - if (defined($self->{cache_robot_list_results}->{$options{robot}}) && - !defined($self->{cache_robot_list_results}->{$options{robot}}->{ResultItem})) { - $self->{current_text} = sprintf("[newtest] no result avaiblable for scenario '%s'", $options{scenario}); - $self->{current_status} = 3; - return 1; - } - if (!defined($self->{cache_robot_list_results}->{$options{robot}})) { - my $result = $self->{instance}->ListResults('Robot', 30, [$options{robot}]); - if (defined(my $com_error = gorgone::modules::plugins::newtest::libs::stubs::errors::get_error())) { - $self->{logger}->writeLogError("[newtest] newtest API error 'ListResults' method: " . $com_error); - return -1; - } - - if (!(ref($result) && defined($result->{ResultItem}))) { - $self->{cache_robot_list_results}->{$options{robot}} = {}; - $self->{logger}->writeLogError("[newtest] no results found for robot: " . $options{robot}); - return 1; - } - - if (ref($result->{ResultItem}) eq 'HASH') { - $result->{ResultItem} = [$result->{ResultItem}]; - } - $self->{cache_robot_list_results}->{$options{robot}} = $result; - } - - # stop at first - foreach my $result (@{$self->{cache_robot_list_results}->{$options{robot}}->{ResultItem}}) { - if ($result->{MeasureName} eq $options{scenario}) { - my ($value, $unit) = $self->convert_measure( - value => $result->{ExecutionValue}, - unit => $result->{MeasureUnit} - ); - $self->{current_text} = sprintf( - "Execution status '%s'. Scenario '%s' total duration is %d%s.", - $result->{ExecutionStatus}, $options{scenario}, - $value, $unit - ); - $self->perfdata_add( - label => $result->{MeasureName}, unit => $unit, - value => sprintf("%d", $value), - min => 0 - ); - - $self->get_newtest_extra_metrics( - scenario => $options{scenario}, - robot => $options{robot}, - id => $result->{Id} - ); - - $self->{logger}->writeLogInfo("[newtest] result found for scenario: " . $options{scenario} . '/' . $options{robot}); - return 0; - } - } - - $self->{logger}->writeLogError("[newtest] no result found for scenario: " . $options{scenario} . '/' . $options{robot}); - return 1; -} - -sub get_newtest_extra_metrics { - my ($self, %options) = @_; - - my $result = $self->{instance}->ListResultChildren($options{id}); - if (defined(my $com_error = gorgone::modules::plugins::newtest::libs::stubs::errors::get_error())) { - $self->{logger}->writeLogError("[newtest] newtest API error 'ListResultChildren' method: " . $com_error); - return -1; - } - - if (!(ref($result) && defined($result->{ResultItem}))) { - $self->{logger}->writeLogError("[newtest] no extra metrics found for scenario: " . $options{scenario} . '/' . $options{robot}); - return 1; - } - - if (ref($result->{ResultItem}) eq 'HASH') { - $result->{ResultItem} = [$result->{ResultItem}]; - } - foreach my $item (@{$result->{ResultItem}}) { - $self->perfdata_add( - label => $item->{MeasureName}, unit => $map_newtest_units{$item->{MeasureUnit}}, - value => $item->{ExecutionValue} - ); - } - return 0; -} - -sub get_newtest_scenarios { - my ($self, %options) = @_; - - eval { - $self->{instance}->proxy($self->{endpoint}, timeout => $self->{nmc_timeout}); - }; - if ($@) { - $self->{logger}->writeLogError('[newtest] newtest proxy error: ' . $@); - return -1; - } - - if (defined($self->{nmc_username}) && $self->{nmc_username} ne '' && - defined($self->{nmc_password}) && $self->{nmc_password} ne '') { - $self->{instance}->transport->http_request->header( - 'Authorization' => 'Basic ' . MIME::Base64::encode($self->{nmc_username} . ':' . $self->{nmc_password}, '') - ); - } - my $result = $self->{instance}->ListScenarioStatus( - $self->{list_scenario_status}->{search}, - 0, - $self->{list_scenario_status}->{instances} - ); - if (defined(my $com_error = gorgone::modules::plugins::newtest::libs::stubs::errors::get_error())) { - $self->{logger}->writeLogError("[newtest] newtest API error 'ListScenarioStatus' method: " . $com_error); - return -1; - } - - if (defined($result->{InstanceScenarioItem})) { - if (ref($result->{InstanceScenarioItem}) eq 'HASH') { - $result->{InstanceScenarioItem} = [$result->{InstanceScenarioItem}]; - } - - foreach my $scenario (@{$result->{InstanceScenarioItem}}) { - my $scenario_name = $scenario->{MeasureName}; - my $robot_name = $scenario->{RobotName}; - my $last_check = sprintf("%d", Date::Parse::str2time($scenario->{LastMessageUtc}, 'UTC')); - my $host_name = sprintf($self->{host_prefix}, $robot_name); - my $service_name = sprintf($self->{service_prefix}, $scenario_name); - $self->{current_status} = $map_scenario_status{$scenario->{Status}}; - $self->{current_text} = ''; - - $host_name =~ s/[\Q$self->{illegal_characters}\E]//g; - $service_name =~ s/[\Q$self->{illegal_characters}\E]//g; - - # Add host config - if (!defined($self->{db_newtest}->{$host_name})) { - $self->{logger}->writeLogInfo("[newtest] create host '$host_name'"); - if ($self->clapi_execute(cmd => '-o HOST -a ADD -v "' . $host_name . ';' . $host_name . ';127.0.0.1;' . $self->{host_template} . ';' . $self->{poller_name} . ';"', - timeout => $self->{clapi_timeout}) == 0) { - $self->{db_newtest}->{$host_name} = {}; - $self->{must_push_config} = 1; - $self->{logger}->writeLogInfo("[newtest] create host '$host_name' succeeded."); - } - } - - # Add service config - if (defined($self->{db_newtest}->{$host_name}) && !defined($self->{db_newtest}->{$host_name}->{$service_name})) { - $self->{logger}->writeLogInfo("[newtest] create service '$service_name' for host '$host_name':"); - if ($self->clapi_execute(cmd => '-o SERVICE -a ADD -v "' . $host_name . ';' . $service_name . ';' . $self->{service_template} . '"', - timeout => $self->{clapi_timeout}) == 0) { - $self->{db_newtest}->{$host_name}->{$service_name} = {}; - $self->{must_push_config} = 1; - $self->{logger}->writeLogInfo("[newtest] create service '$service_name' for host '$host_name' succeeded."); - $self->clapi_execute(cmd => '-o SERVICE -a setmacro -v "' . $host_name . ';' . $service_name . ';NEWTEST_MESSAGEID;"', - timeout => $self->{clapi_timeout}); - } - } - - # Check if new message - if (defined($self->{db_newtest}->{$host_name}->{$service_name}->{last_execution_time}) && - $last_check <= $self->{db_newtest}->{$host_name}->{$service_name}->{last_execution_time}) { - $self->{logger}->writeLogInfo("[newtest] skip: service '$service_name' for host '$host_name' already submitted."); - next; - } - - if ($scenario->{Status} eq 'OutOfRange') { - $self->{current_text} = sprintf("scenario '%s' not scheduled", $scenario_name); - } else { - if ($self->{current_status} == 2) { - $self->get_newtest_diagnostic( - scenario => $scenario_name, robot => $robot_name, - host_name => $host_name, service_name => $service_name - ); - } - - if ($self->get_scenario_results(scenario => $scenario_name, robot => $robot_name, - host_name => $host_name, service_name => $service_name) == 1) { - $self->{current_text} = sprintf("No result avaiblable for scenario '%s'", $scenario_name); - $self->{current_status} = 3; - } - } - $self->add_output(time => $last_check, host_name => $host_name, service_name => $service_name); - } - } - - return 0; -} - -sub action_newtestresync { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->{logger}->writeLogDebug("gorgone-newtest: container $self->{container_id}: begin resync"); - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action newtestresync proceed' }); - $self->newtestresync_init(); - - if ($self->get_poller_id()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get poller id' }); - return -1; - } - if ($self->get_centreondb_cache()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get centreon config cache' }); - return -1; - } - if ($self->get_centstoragedb_cache()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get centreon storage cache' }); - return -1; - } - - if ($self->get_newtest_scenarios(%options)) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get newtest scenarios' }); - return -1; - } - - $self->push_config(); - $self->submit_external_cmd(); - - $self->send_log(code => GORGONE_ACTION_FINISH_OK, token => $options{token}, data => { message => 'action newtestresync finished' }); - return 0; -} - -sub event { - while (1) { - my ($message) = $connector->read_message(); - last if (!defined($message)); - - $connector->{logger}->writeLogDebug("gorgone-newtest: class: $message"); - if ($message =~ /^\[(.*?)\]/) { - if ((my $method = $connector->can('action_' . lc($1)))) { - $message =~ /^\[(.*?)\]\s+\[(.*?)\]\s+\[.*?\]\s+(.*)$/m; - my ($action, $token) = ($1, $2); - my $data = JSON::XS->new->decode($3); - $method->($connector, token => $token, data => $data); - } - } - } -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[newtest] $$ has quit"); - exit(0); - } - - if (time() - $connector->{resync_time} > $connector->{last_resync_time}) { - $connector->{last_resync_time} = time(); - $connector->action_newtestresync(); - } -} - -sub run { - my ($self, %options) = @_; - - # Database creation. We stay in the loop still there is an error - $self->{db_centstorage} = gorgone::class::db->new( - dsn => $self->{config_db_centstorage}->{dsn}, - user => $self->{config_db_centstorage}->{username}, - password => $self->{config_db_centstorage}->{password}, - force => 2, - logger => $self->{logger} - ); - $self->{db_centreon} = gorgone::class::db->new( - dsn => $self->{config_db_centreon}->{dsn}, - user => $self->{config_db_centreon}->{username}, - password => $self->{config_db_centreon}->{password}, - force => 2, - logger => $self->{logger} - ); - ##### Load objects ##### - $self->{class_object_centstorage} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centstorage}); - $self->{class_object_centreon} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centreon}); - $SOAP::Constants::PREFIX_ENV = 'SOAP-ENV'; - $self->{instance} = gorgone::modules::plugins::newtest::libs::stubs::ManagementConsoleService->new(); - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-newtest-' . $self->{container_id}, - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'NEWTESTREADY', - data => { container_id => $self->{container_id} } - }); - - my $watcher_timer = $self->{loop}->timer(5, 5, \&periodic_exec); - my $watcher_io = $self->{loop}->io($self->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/plugins/newtest/hooks.pm b/centreon-gorgone/gorgone/modules/plugins/newtest/hooks.pm deleted file mode 100644 index 3265f86448..0000000000 --- a/centreon-gorgone/gorgone/modules/plugins/newtest/hooks.pm +++ /dev/null @@ -1,289 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::plugins::newtest::hooks; - -use warnings; -use strict; -use JSON::XS; -use gorgone::class::core; -use gorgone::modules::plugins::newtest::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'plugins'; -use constant NAME => 'newtest'; -use constant EVENTS => [ - { event => 'NEWTESTREADY' }, - { event => 'NEWTESTRESYNC', uri => '/resync', method => 'GET' }, -]; - -my ($config_core, $config); -my ($config_db_centreon, $config_db_centstorage); -my $last_containers = {}; # Last values from config ini -my $containers = {}; -my $containers_pid = {}; -my $stop = 0; -my $timer_check = time(); -my $config_check_containers_time; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centstorage = $options{config_db_centstorage}; - $config_db_centreon = $options{config_db_centreon}; - $config_check_containers_time = defined($config->{check_containers_time}) ? $config->{check_containers_time} : 3600; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - $last_containers = get_containers(logger => $options{logger}); - foreach my $container_id (keys %$last_containers) { - create_child(container_id => $container_id, logger => $options{logger}); - } -} - -sub routing { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - $options{logger}->writeLogError("[newtest] Cannot decode json data: $@"); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-newtest: cannot decode json' }, - json_encode => 1 - }); - return undef; - } - - if ($options{action} eq 'NEWTESTREADY') { - $containers->{ $data->{container_id} }->{ready} = 1; - return undef; - } - - if (!defined($data->{container_id}) || !defined($last_containers->{ $data->{container_id} })) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-newtest: need a valid container id' }, - json_encode => 1 - }); - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$containers->{ $data->{container_id} }->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-newtest: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-newtest-' . $data->{container_id}, - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - foreach my $container_id (keys %$containers) { - if (defined($containers->{$container_id}->{running}) && $containers->{$container_id}->{running} == 1) { - $options{logger}->writeLogDebug("[newtest] Send TERM signal for container '" . $container_id . "'"); - CORE::kill('TERM', $containers->{$container_id}->{pid}); - } - } -} - -sub kill_internal { - my (%options) = @_; - - foreach (keys %$containers) { - if ($containers->{$_}->{running} == 1) { - $options{logger}->writeLogDebug("[newtest] Send KILL signal for container '" . $_ . "'"); - CORE::kill('KILL', $containers->{$_}->{pid}); - } - } -} - -sub kill { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - if ($timer_check - time() > $config_check_containers_time) { - sync_container_childs(logger => $options{logger}); - $timer_check = time(); - } - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($containers_pid->{$pid})); - - # If someone dead, we recreate - delete $containers->{$containers_pid->{$pid}}; - delete $containers_pid->{$pid}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - # Need to check if we need to recreate (can be a container destruction)!!! - sync_container_childs(logger => $options{logger}); - } - } - - return $count; -} - -sub broadcast { - my (%options) = @_; - - foreach my $container_id (keys %$containers) { - next if ($containers->{$container_id}->{ready} != 1); - - $options{gorgone}->send_internal_message( - identity => 'gorgone-newtest-' . $container_id, - action => $options{action}, - frame => $options{frame}, - token => $options{token} - ); - } -} - -# Specific functions -sub get_containers { - my (%options) = @_; - - return $containers if (!defined($config->{containers})); - foreach (@{$config->{containers}}) { - next if (!defined($_->{name}) || $_->{name} eq ''); - - if (!defined($_->{nmc_endpoint}) || $_->{nmc_endpoint} eq '') { - $options{logger}->writeLogError("[newtest] cannot load container '" . $_->{name} . "' - please set nmc_endpoint option"); - next; - } - if (!defined($_->{poller_name}) || $_->{poller_name} eq '') { - $options{logger}->writeLogError("[newtest] cannot load container '" . $_->{name} . "' - please set poller_name option"); - next; - } - if (!defined($_->{list_scenario_status}) || $_->{list_scenario_status} eq '') { - $options{logger}->writeLogError("[newtest] cannot load container '" . $_->{name} . "' - please set list_scenario_status option"); - next; - } - - my $list_scenario; - eval { - $list_scenario = JSON::XS->new->decode($_->{list_scenario_status}); - }; - if ($@) { - $options{logger}->writeLogError("[newtest] cannot load container '" . $_->{name} . "' - cannot decode list scenario option"); - next; - } - - $containers->{$_->{name}} = { - nmc_endpoint => $_->{nmc_endpoint}, - nmc_timeout => (defined($_->{nmc_timeout}) && $_->{nmc_timeout} =~ /(\d+)/) ? - $1 : 10, - nmc_username => $_->{nmc_username}, - nmc_password => $_->{nmc_password}, - poller_name => $_->{poller_name}, - list_scenario_status => $list_scenario, - resync_time => - (defined($_->{resync_time}) && $_->{resync_time} =~ /(\d+)/) ? $1 : 300, - host_template => - defined($_->{host_template}) && $_->{host_template} ne '' ? $_->{host_template} : 'generic-active-host-custom', - host_prefix => - defined($_->{host_prefix}) && $_->{host_prefix} ne '' ? $_->{host_prefix} : 'Robot-%s', - service_template => - defined($_->{service_template}) && $_->{service_template} ne '' ? $_->{service_template} : 'generic-passive-service-custom', - service_prefix => - defined($_->{service_prefix}) && $_->{service_prefix} ne '' ? $_->{service_prefix} : 'Scenario-%s', - }; - } - - return $containers; -} - -sub sync_container_childs { - my (%options) = @_; - - $last_containers = get_containers(logger => $options{logger}); - foreach my $container_id (keys %$last_containers) { - if (!defined($containers->{$container_id})) { - create_child(container_id => $container_id, logger => $options{logger}); - } - } - - # Check if need to delete on containers - foreach my $container_id (keys %$containers) { - next if (defined($last_containers->{$container_id})); - - if ($containers->{$container_id}->{running} == 1) { - $options{logger}->writeLogDebug("[newtest] Send KILL signal for container '" . $container_id . "'"); - CORE::kill('KILL', $containers->{$container_id}->{pid}); - } - - delete $containers_pid->{ $containers->{$container_id}->{pid} }; - delete $containers->{$container_id}; - } -} - -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[newtest] Create 'gorgone-newtest' process for container '" . $options{container_id} . "'"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-newtest ' . $options{container_id}; - my $module = gorgone::modules::plugins::newtest::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - config_db_centreon => $config_db_centreon, - config_db_centstorage => $config_db_centstorage, - config_newtest => $last_containers->{$options{container_id}}, - container_id => $options{container_id} - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[newtest] PID $child_pid (gorgone-newtest) for container '" . $options{container_id} . "'"); - $containers->{$options{container_id}} = { pid => $child_pid, ready => 0, running => 1 }; - $containers_pid->{$child_pid} = $options{container_id}; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/plugins/newtest/libs/stubs/ManagementConsoleService.pm b/centreon-gorgone/gorgone/modules/plugins/newtest/libs/stubs/ManagementConsoleService.pm deleted file mode 100644 index 10688740d5..0000000000 --- a/centreon-gorgone/gorgone/modules/plugins/newtest/libs/stubs/ManagementConsoleService.pm +++ /dev/null @@ -1,392 +0,0 @@ -package gorgone::modules::plugins::newtest::libs::stubs::ManagementConsoleService; - -sub SOAP::Serializer::as_SearchMode { - my $self = shift; - my($value, $name, $type, $attr) = @_; - return [$name, {'xsi:type' => 'tns:SearchMode', %$attr}, $value]; -} - -sub SOAP::Serializer::as_MessageCategory { - my $self = shift; - my($value, $name, $type, $attr) = @_; - return [$name, {'xsi:type' => 'tns:MessageCategory', %$attr}, $value]; -} - -sub SOAP::Serializer::as_ArrayOfString { - my $self = shift; - my($value, $name, $type, $attr) = @_; - - my $args = []; - foreach (@$value) { - push @$args, SOAP::Data->new(name => 'string', type => 's:string', attr => {}, prefix => 'tns', value => $_); - } - return [$name, {'xsi:type' => 'tns:ArrayOfString', %$attr}, $args]; -} - -# Generated by SOAP::Lite (v0.712) for Perl -- soaplite.com -# Copyright (C) 2000-2006 Paul Kulchenko, Byrne Reese -# -- generated at [Tue Oct 7 11:04:21 2014] -# -- generated from http://192.168.6.84/nws/managementconsoleservice.asmx?wsdl -my %methods = ( -ListInformationRangesFromDWH => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListInformationRangesFromDWH', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end ListInformationRangesFromDWH -ListComponentStatus => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListComponentStatus', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end ListComponentStatus -IsOptionAllowed => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/IsOptionAllowed', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'optionId', type => 's:int', attr => {}), - ], # end parameters - }, # end IsOptionAllowed -SendCommand => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/SendCommand', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'commandType', type => 'tns:CommandType', attr => {}), - SOAP::Data->new(name => 'agentName', type => 's:string', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end SendCommand -ListInformationRanges => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListInformationRanges', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end ListInformationRanges -ListResources => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListResources', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end ListResources -GetLocationProperties => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/GetLocationProperties', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'locationPath', type => 's:string', attr => {}), - ], # end parameters - }, # end GetLocationProperties -ListLocationChildren => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListLocationChildren', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'locationPath', type => 's:string', attr => {}), - SOAP::Data->new(name => 'recursive', type => 's:boolean', attr => {}), - ], # end parameters - }, # end ListLocationChildren -ListBusinessChildren => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListBusinessChildren', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'businessPath', type => 's:string', attr => {}), - SOAP::Data->new(name => 'recursive', type => 's:boolean', attr => {}), - ], # end parameters - }, # end ListBusinessChildren -GetMeasureProperties => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/GetMeasureProperties', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'measurePath', type => 's:string', attr => {}), - ], # end parameters - }, # end GetMeasureProperties -GetBusinessProperties => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/GetBusinessProperties', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'businessPath', type => 's:string', attr => {}), - ], # end parameters - }, # end GetBusinessProperties -ListResults => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListResults', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}, prefix => 'tns'), - SOAP::Data->new(name => 'range', type => 's:int', attr => {}, prefix => 'tns'), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}, prefix => 'tns'), - ], # end parameters - }, # end ListResults -ListRobotStatus => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListRobotStatus', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end ListRobotStatus -ListAllResults => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListAllResults', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}), - SOAP::Data->new(name => 'start', type => 's:dateTime', attr => {}), - SOAP::Data->new(name => 'end', type => 's:dateTime', attr => {}), - SOAP::Data->new(name => 'types', type => 'tns:MeasureType', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end ListAllResults -ListScenariosStatus => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListScenariosStatus', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'businessPath', type => 's:string', attr => {}), - SOAP::Data->new(name => 'locationPath', type => 's:string', attr => {}), - ], # end parameters - }, # end ListScenariosStatus -ListAlarms => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListAlarms', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}), - SOAP::Data->new(name => 'range', type => 's:int', attr => {}), - SOAP::Data->new(name => 'types', type => 'tns:AlarmType', attr => {}), - SOAP::Data->new(name => 'levels', type => 'tns:AlarmLevel', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end ListAlarms -ListScenarios => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListScenarios', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'businessPath', type => 's:string', attr => {}), - ], # end parameters - }, # end ListScenarios -ListResultChildren => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListResultChildren', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'resultId', type => 's:long', attr => {}, prefix => 'tns'), - ], # end parameters - }, # end ListResultChildren -GetUserItem => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/GetUserItem', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'login', type => 's:string', attr => {}), - ], # end parameters - }, # end GetUserItem -ListCollectorStatus => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListCollectorStatus', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}), - ], # end parameters - }, # end ListCollectorStatus -GetDiagnostic => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/GetDiagnostic', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'messageId', type => 's:long', attr => {}), - ], # end parameters - }, # end GetDiagnostic -LogIn => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/LogIn', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'login', type => 's:string', attr => {}), - SOAP::Data->new(name => 'password', type => 's:string', attr => {}), - ], # end parameters - }, # end LogIn -ListCustomGroupChildren => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListCustomGroupChildren', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'customGroupPath', type => 's:string', attr => {}), - SOAP::Data->new(name => 'recursive', type => 's:boolean', attr => {}), - ], # end parameters - }, # end ListCustomGroupChildren -GetCustomGroupProperties => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/GetCustomGroupProperties', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'customGroupPath', type => 's:string', attr => {}), - ], # end parameters - }, # end GetCustomGroupProperties -ListMessages => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListMessages', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}, prefix => 'tns'), - SOAP::Data->new(name => 'range', type => 's:int', attr => {}, prefix => 'tns'), - SOAP::Data->new(name => 'categories', type => 'tns:MessageCategory', attr => {}, prefix => 'tns'), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}, prefix => 'tns'), - ], # end parameters - }, # end ListMessages -ListScenarioStatus => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListScenarioStatus', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'mode', type => 'tns:SearchMode', attr => {}, prefix => 'tns'), - SOAP::Data->new(name => 'range', type => 's:int', attr => {}, prefix => 'tns'), - SOAP::Data->new(name => 'args', type => 'tns:ArrayOfString', attr => {}, prefix => 'tns'), - ], # end parameters - }, # end ListScenarioStatus -ListMeasureResults => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListMeasureResults', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'measureId', type => 's:string', attr => {}), - SOAP::Data->new(name => 'locationPath', type => 's:string', attr => {}), - SOAP::Data->new(name => 'range', type => 's:int', attr => {}), - SOAP::Data->new(name => 'recursive', type => 's:boolean', attr => {}), - SOAP::Data->new(name => 'types', type => 'tns:MeasureType', attr => {}), - ], # end parameters - }, # end ListMeasureResults -GetUserProperties => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/GetUserProperties', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'login', type => 's:string', attr => {}), - ], # end parameters - }, # end GetUserProperties -ListMeasureChildren => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/ListMeasureChildren', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'measureId', type => 's:string', attr => {}), - SOAP::Data->new(name => 'types', type => 'tns:MeasureType', attr => {}), - SOAP::Data->new(name => 'recursive', type => 's:boolean', attr => {}), - SOAP::Data->new(name => 'measurePath', type => 's:string', attr => {}), - SOAP::Data->new(name => 'recursive', type => 's:boolean', attr => {}), - ], # end parameters - }, # end ListMeasureChildren -GetLicenceOptionValue => { - endpoint => '', - soapaction => 'http://www.auditec-newtest.com/GetLicenceOptionValue', - namespace => 'http://www.auditec-newtest.com', - parameters => [ - SOAP::Data->new(name => 'optionId', type => 's:int', attr => {}), - ], # end parameters - }, # end GetLicenceOptionValue -); # end my %methods - -use SOAP::Lite; -use gorgone::modules::plugins::newtest::libs::stubs::errors; -use Exporter; -use Carp (); - -use vars qw(@ISA $AUTOLOAD @EXPORT_OK %EXPORT_TAGS); -@ISA = qw(Exporter SOAP::Lite); -@EXPORT_OK = (keys %methods); -%EXPORT_TAGS = ('all' => [@EXPORT_OK]); - -sub _call { - my ($self, $method) = (shift, shift); - my $name = UNIVERSAL::isa($method => 'SOAP::Data') ? $method->name : $method; - my %method = %{$methods{$name}}; - $self->on_fault(\&gorgone::modules::plugins::newtest::libs::stubs::errors::soapGetBad); - $self->proxy($method{endpoint} || Carp::croak "No server address (proxy) specified") - unless $self->proxy; - my @templates = @{$method{parameters}}; - my @parameters = (); - foreach my $param (@_) { - if (@templates) { - my $template = shift @templates; - my ($prefix,$typename) = SOAP::Utils::splitqname($template->type); - my $method = 'as_'.$typename; - # TODO - if can('as_'.$typename) {...} - my $result = $self->serializer->$method($param, $template->name, $template->type, $template->attr); - #print Data::Dumper::Dumper($result); - push(@parameters, $template->value($result->[2])); - } - else { - push(@parameters, $param); - } - } - $self->endpoint($method{endpoint}) - ->ns($method{namespace}) - ->on_action(sub{qq!"$method{soapaction}"!}); - $self->serializer->register_ns("http://microsoft.com/wsdl/mime/textMatching/","tm"); - $self->serializer->register_ns("http://schemas.xmlsoap.org/wsdl/soap12/","soap12"); - $self->serializer->register_ns("http://schemas.xmlsoap.org/wsdl/mime/","mime"); - $self->serializer->register_ns("http://www.w3.org/2001/XMLSchema","s"); - $self->serializer->register_ns("http://schemas.xmlsoap.org/wsdl/soap/","soap"); - $self->serializer->register_ns("http://schemas.xmlsoap.org/wsdl/","wsdl"); - $self->serializer->register_ns("http://schemas.xmlsoap.org/soap/encoding/","soapenc"); - $self->serializer->register_ns("http://schemas.xmlsoap.org/wsdl/http/","http"); - $self->serializer->register_ns("http://www.auditec-newtest.com","tns"); - my $som = $self->SUPER::call($method => @parameters); - if ($self->want_som) { - return $som; - } - UNIVERSAL::isa($som => 'SOAP::SOM') ? wantarray ? $som->paramsall : $som->result : $som; -} - -sub BEGIN { - no strict 'refs'; - for my $method (qw(want_som)) { - my $field = '_' . $method; - *$method = sub { - my $self = shift->new; - @_ ? ($self->{$field} = shift, return $self) : return $self->{$field}; - } - } -} -no strict 'refs'; -for my $method (@EXPORT_OK) { - my %method = %{$methods{$method}}; - *$method = sub { - my $self = UNIVERSAL::isa($_[0] => __PACKAGE__) - ? ref $_[0] - ? shift # OBJECT - # CLASS, either get self or create new and assign to self - : (shift->self || __PACKAGE__->self(__PACKAGE__->new)) - # function call, either get self or create new and assign to self - : (__PACKAGE__->self || __PACKAGE__->self(__PACKAGE__->new)); - $self->_call($method, @_); - } -} - -sub AUTOLOAD { - my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::') + 2); - return if $method eq 'DESTROY' || $method eq 'want_som'; - die "Unrecognized method '$method'. List of available method(s): @EXPORT_OK\n"; -} - -1; diff --git a/centreon-gorgone/gorgone/modules/plugins/newtest/libs/stubs/errors.pm b/centreon-gorgone/gorgone/modules/plugins/newtest/libs/stubs/errors.pm deleted file mode 100644 index ba6b951f6d..0000000000 --- a/centreon-gorgone/gorgone/modules/plugins/newtest/libs/stubs/errors.pm +++ /dev/null @@ -1,31 +0,0 @@ - -package gorgone::modules::plugins::newtest::libs::stubs::errors; - -use strict; -use warnings; - -our $SOAP_ERRORS; - -sub soapGetBad { - my $soap = shift; - my $res = shift; - - if(ref($res)) { - chomp( my $err = $res->faultstring ); - $SOAP_ERRORS = "SOAP FAULT: $err"; - } else { - chomp( my $err = $soap->transport->status ); - $SOAP_ERRORS = "TRANSPORT ERROR: $err"; - } - return new SOAP::SOM; -} - -sub get_error { - my $error = $SOAP_ERRORS; - - $SOAP_ERRORS = undef; - return $error; -} - -1; - diff --git a/centreon-gorgone/gorgone/modules/plugins/newtest/libs/wsdl/newtest.wsdl b/centreon-gorgone/gorgone/modules/plugins/newtest/libs/wsdl/newtest.wsdl deleted file mode 100644 index f5cb180dae..0000000000 --- a/centreon-gorgone/gorgone/modules/plugins/newtest/libs/wsdl/newtest.wsdl +++ /dev/null @@ -1,2097 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Return user item (Obsolete). - - - - - Return a list of scenarios instances statuses (Obsolete). - - - - - Return a list of results for a specified measure/agent item. Ordering of results is as follows: results, subresults, measure rank within subresults (Obsolete). - - - - - Return a list of children for a specific Measure node. Result set is ordered first into a hierarchical structure (measure, sub-measure) with a post-ordering on the measures' rank and then display name (Obsolete). - - - - - Check Licence Options - - - - - Get Option Value - - - - - Method used to log user in - - - - - Return user item - - - - - Gets a list of children of a specified Business node. - - - - - Gets specified Business node properties. - - - - - Return a list of children of a specified Location node. - - - - - Return specified Location node properties. - - - - - Return a list of children of a specified CustomGroup node. - - - - - Return CustomGroup node properties. - - - - - Return a list of robots statuses. - - - - - Return a list of Collectors statuses. - - - - - Return a list of Components statuses. - - - - - Gets a list of children of a specified Business node. - - - - - Return a list of children for a specified Measure node. Result set is ordered first into a hierarchical structure (measure, sub-measure) with a post-ordering on the measures' rank and then display name. - - - - - Return measure properties. - - - - - Return a list of scenarios instances statuses. - - - - - Return a list of results for a specific measure item. Ordering of results is as follows: results, subresults, measure rank within subresults. - - - - - Return a list of results for a specific measure item. Ordering of results is as follows: results, subresults, measure rank within subresults. - - - - - Return a list of sub results for a specific result item - - - - - Returns a list of alarms for specified parameter - - - - - Returns a list of messages for specified item - - - - - Returns a list of messages for specified item - - - - - Returns a list of information ranges from Newtest DWH for specified item - - - - - Returns a list of resources for specified item - - - - - Return diagnostic content for given message Id - - - - - Sends a command to a couple measure/agent - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/centreon-gorgone/gorgone/modules/plugins/scom/class.pm b/centreon-gorgone/gorgone/modules/plugins/scom/class.pm deleted file mode 100644 index 96fd1af139..0000000000 --- a/centreon-gorgone/gorgone/modules/plugins/scom/class.pm +++ /dev/null @@ -1,518 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::plugins::scom::class; - -use base qw(gorgone::class::module); - -use strict; -use warnings; -use gorgone::standard::library; -use gorgone::standard::constants qw(:all); -use gorgone::class::sqlquery; -use gorgone::class::http::http; -use MIME::Base64; -use JSON::XS; -use EV; - -my %handlers = (TERM => {}, HUP => {}); -my ($connector); - -sub new { - my ($class, %options) = @_; - $connector = $class->SUPER::new(%options); - bless $connector, $class; - - $connector->{config_scom} = $options{config_scom}; - - $connector->{api_version} = $options{config_scom}->{api_version}; - $connector->{dsmhost} = $options{config_scom}->{dsmhost}; - $connector->{dsmslot} = $options{config_scom}->{dsmslot}; - $connector->{dsmmacro} = $options{config_scom}->{dsmmacro}; - $connector->{dsmalertmessage} = $options{config_scom}->{dsmalertmessage}; - $connector->{dsmrecoverymessage} = $options{config_scom}->{dsmrecoverymessage}; - $connector->{resync_time} = $options{config_scom}->{resync_time}; - $connector->{last_resync_time} = time() - $connector->{resync_time}; - $connector->{centcore_cmd} = - defined($connector->{config}->{centcore_cmd}) && $connector->{config}->{centcore_cmd} ne '' ? $connector->{config}->{centcore_cmd} : '/var/lib/centreon/centcore.cmd'; - - $connector->{scom_session_id} = undef; - - $connector->{dsmclient_bin} = - defined($connector->{config}->{dsmclient_bin}) ? $connector->{config}->{dsmclient_bin} : '/usr/share/centreon/bin/dsmclient.pl'; - - $connector->set_signal_handlers(); - return $connector; -} - -sub set_signal_handlers { - my $self = shift; - - $SIG{TERM} = \&class_handle_TERM; - $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; - $SIG{HUP} = \&class_handle_HUP; - $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; -} - -sub handle_HUP { - my $self = shift; - $self->{reload} = 0; -} - -sub handle_TERM { - my $self = shift; - $self->{logger}->writeLogInfo("[scom] $$ Receiving order to stop..."); - $self->{stop} = 1; -} - -sub class_handle_TERM { - foreach (keys %{$handlers{TERM}}) { - &{$handlers{TERM}->{$_}}(); - } -} - -sub class_handle_HUP { - foreach (keys %{$handlers{HUP}}) { - &{$handlers{HUP}->{$_}}(); - } -} - -sub http_check_error { - my ($self, %options) = @_; - - if ($options{status} == 1) { - $self->{logger}->writeLogError("[scom] Container $self->{container_id}: scom $options{method} issue"); - return 1; - } - - my $code = $self->{http}->get_code(); - if ($code !~ /^2/) { - $self->{logger}->writeLogError("[scom] Container $self->{container_id}: scom $options{method} issue - " . $self->{http}->get_message()); - return 1; - } - - return 0; -} - -sub get_httpauth { - my ($self, %options) = @_; - - my $httpauth = {}; - if ($self->{config_scom}->{httpauth} eq 'basic') { - $httpauth->{basic} = 1; - } elsif ($self->{config_scom}->{httpauth} eq 'ntlmv2') { - $httpauth->{ntlmv2} = 1; - } - return $httpauth; -} - -sub get_method { - my ($self, %options) = @_; - - my $api = 2016; - $api = 1801 if ($self->{api_version} == 1801); - return $self->can($options{method} . '_' . $api); -} - -sub submit_external_cmd { - my ($self, %options) = @_; - - my ($lerror, $stdout, $exit_code) = gorgone::standard::misc::backtick( - command => '/bin/echo "' . $options{cmd} . '" >> ' . $self->{centcore_cmd}, - logger => $self->{logger}, - timeout => 5, - wait_exit => 1 - ); - if ($lerror == -1 || ($exit_code >> 8) != 0) { - $self->{logger}->writeLogError("[scom] Command execution problem for command $options{cmd} : " . $stdout); - return -1; - } - - return 0; -} - -sub scom_authenticate_1801 { - my ($self, %options) = @_; - - my ($status) = $self->{http}->request( - method => 'POST', hostname => '', - full_url => $self->{config_scom}->{url} . '/OperationsManager/authenticate', - credentials => 1, username => $self->{config_scom}->{username}, password => $self->{config_scom}->{password}, ntlmv2 => 1, - query_form_post => '"' . MIME::Base64::encode_base64('Windows') . '"', - header => [ - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => ['CURLOPT_SSL_VERIFYPEER => 0'], - ); - - return 1 if ($self->http_check_error(status => $status, method => 'authenticate') == 1); - - my $header = $self->{http}->get_header(name => 'Set-Cookie'); - if (defined($header) && $header =~ /SCOMSessionId=([^;]+);/i) { - $connector->{scom_session_id} = $1; - } else { - $self->{logger}->writeLogError("[scom] Container $self->{container_id}: scom authenticate issue - error retrieving cookie"); - return 1; - } - - return 0; -} - -sub acknowledge_alert_2016 { - my ($self, %options) = @_; - - my $arguments = { - 'resolutionState' => $options{resolutionstate}, - }; - my ($status, $encoded_argument) = $self->json_encode(argument => $arguments); - return 1 if ($status == 1); - - my $curl_opts = []; - if (defined($self->{config_scom}->{curlopts})) { - foreach (keys %{$self->{config_scom}->{curlopts}}) { - push @{$curl_opts}, $_ . ' => ' . $self->{config_scom}->{curlopts}->{$_}; - } - } - my $httpauth = $self->get_httpauth(); - - ($status, my $response) = $self->{http}->request( - method => 'PUT', hostname => '', - full_url => $self->{config_scom}->{url} . 'alerts/' . $options{alert_id}, - query_form_post => $encoded_argument, - credentials => 1, - %$httpauth, - username => $self->{config_scom}->{username}, - password => $self->{config_scom}->{password}, - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => $curl_opts, - ); - - return 1 if ($self->http_check_error(status => $status, method => 'data/alert') == 1); - - return 0; -} - -sub acknowledge_alert_1801 { - my ($self, %options) = @_; - -} - -sub get_realtime_scom_alerts_1801 { - my ($self, %options) = @_; - - $self->{scom_realtime_alerts} = {}; - if (!defined($connector->{scom_session_id})) { - return 1 if ($self->scom_authenticate_1801() == 1); - } - - my $arguments = { - 'classId' => '', - 'criteria' => "((ResolutionState <> '255') OR (ResolutionState <> '254'))", - 'displayColumns' => [ - 'id', 'severity', 'resolutionState', 'monitoringobjectdisplayname', 'name', 'age', 'repeatcount', 'lastModified', - ] - }; - my ($status, $encoded_argument) = $self->json_encode(argument => $arguments); - return 1 if ($status == 1); - - my $curl_opts = []; - if (defined($self->{config_scom}->{curlopts})) { - foreach (keys %{$self->{config_scom}->{curlopts}}) { - push @{$curl_opts}, $_ . ' => ' . $self->{config_scom}->{curlopts}->{$_}; - } - } - ($status, my $response) = $self->{http}->request( - method => 'POST', hostname => '', - full_url => $self->{config_scom}->{url} . '/OperationsManager/data/alert', - query_form_post => $encoded_argument, - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - 'Cookie: SCOMSessionId=' . $self->{scom_session_id} . ';', - ], - curl_opt => $curl_opts, - ); - - return 1 if ($self->http_check_error(status => $status, method => 'data/alert') == 1); - - return 0; -} - -sub get_realtime_scom_alerts_2016 { - my ($self, %options) = @_; - - my $curl_opts = []; - if (defined($self->{config_scom}->{curlopts})) { - foreach (keys %{$self->{config_scom}->{curlopts}}) { - push @{$curl_opts}, $_ . ' => ' . $self->{config_scom}->{curlopts}->{$_}; - } - } - my $httpauth = $self->get_httpauth(); - - - $self->{scom_realtime_alerts} = {}; - my ($status, $response) = $self->{http}->request( - method => 'GET', hostname => '', - full_url => $self->{config_scom}->{url} . 'alerts', - credentials => 1, - %$httpauth, - username => $self->{config_scom}->{username}, - password => $self->{config_scom}->{password}, - header => [ - 'Accept-Type: application/json; charset=utf-8', - 'Content-Type: application/json; charset=utf-8', - ], - curl_opt => $curl_opts, - ); - - return 1 if ($self->http_check_error(status => $status, method => 'alerts') == 1); - - ($status, my $entries) = $self->json_decode(argument => $response); - return 1 if ($status == 1); - - # Resolution State: - # 0 => New - # 255 => Closed - # 254 => Resolved - # 250 => Scheduled - # 247 => Awaiting Evidence - # 248 => Assigned to Engineering - # 249 => Acknowledge - # Severity: - # 0 => Information - # 1 => Warning - # 2 => Critical - foreach (@$entries) { - next if (!defined($_->{alertGenerated}->{resolutionState})); - next if ($_->{alertGenerated}->{resolutionState} == 255); - next if ($_->{alertGenerated}->{severity} == 0); - - $self->{scom_realtime_alerts}->{$_->{alertGenerated}->{id}} = { - monitoringobjectdisplayname => $_->{alertGenerated}->{monitoringObjectDisplayName}, - resolutionstate => $_->{alertGenerated}->{resolutionState}, - name => $_->{alertGenerated}->{name}, - severity => $_->{alertGenerated}->{severity}, - timeraised => $_->{alertGenerated}->{timeRaised}, - description => $_->{alertGenerated}->{description}, - }; - } - - return 0; -} - -sub get_realtime_slots { - my ($self, %options) = @_; - - $self->{realtime_slots} = {}; - my $request = " - SELECT hosts.instance_id, hosts.host_id, hosts.name, services.description, services.state, cv.name, cv.value, services.acknowledged, hosts.instance_id - FROM hosts, services - LEFT JOIN customvariables cv ON services.host_id = cv.host_id AND services.service_id = cv.service_id AND cv.name = '$self->{dsmmacro}' - WHERE hosts.name = '$self->{dsmhost}' AND hosts.host_id = services.host_id AND services.enabled = '1' AND services.description LIKE '$self->{dsmslot}'; - "; - my ($status, $datas) = $self->{class_object}->custom_execute(request => $request, mode => 2); - return 1 if ($status == -1); - foreach (@$datas) { - my ($name, $id) = split('##', $$_[6]); - next if (!defined($id)); - $self->{realtime_slots}->{$id} = { - host_name => $$_[2], - host_id => $$_[1], - description => $$_[3], - state => $$_[4], - instance_id => $$_[0], - acknowledged => $$_[7], - instance_id => $$_[8], - }; - } - - return 0; -} - -sub sync_alerts { - my ($self, %options) = @_; - - my $func = $self->get_method(method => 'acknowledge_alert'); - # First we look closed alerts in centreon - foreach my $alert_id (keys %{$self->{realtime_slots}}) { - next if ($self->{realtime_slots}->{$alert_id}->{state} != 0); - next if (!defined($self->{scom_realtime_alerts}->{$alert_id}) || - $self->{scom_realtime_alerts}->{$alert_id}->{resolutionstate} == 254 || - $self->{scom_realtime_alerts}->{$alert_id}->{resolutionstate} == 255 - ); - $func->( - $self, - alert_id => $alert_id, - resolutionstate => 254, - ); - } - - # Look if scom alers is in centreon-dsm services - my $pool_prefix = $self->{dsmslot}; - $pool_prefix =~ s/%//g; - foreach my $alert_id (keys %{$self->{scom_realtime_alerts}}) { - if (!defined($self->{realtime_slots}->{$alert_id}) || - $self->{realtime_slots}->{$alert_id}->{state} == 0) { - my $output = $self->change_macros( - template => $self->{dsmalertmessage}, - macros => $self->{scom_realtime_alerts}->{$alert_id}, - escape => '[" . time() . "]"', - ); - $self->execute_shell_cmd( - cmd => $self->{config}->{dsmclient_bin} . - ' --Host "' . $connector->{dsmhost} . '"' . - ' --pool-prefix "' . $pool_prefix . '"' . - ' --status ' . $self->{scom_realtime_alerts}->{$alert_id}->{severity} . - ' --id "' . $alert_id . '"' . - ' --output "' . $output . '"' - ); - } - } - - # Close centreon alerts not present in scom - foreach my $alert_id (keys %{$self->{realtime_slots}}) { - next if ($self->{realtime_slots}->{$alert_id}->{state} == 0); - next if (defined($self->{scom_realtime_alerts}->{$alert_id}) && $self->{scom_realtime_alerts}->{$alert_id}->{resolutionstate} != 255); - my $output = $self->change_macros( - template => $self->{dsmrecoverymessage}, - macros => {}, - escape => '"', - ); - $self->execute_shell_cmd( - cmd => $self->{config}->{dsmclient_bin} . - ' --Host "' . $connector->{dsmhost} . '"' . - ' --pool-prefix "' . $pool_prefix . '"' . - ' --status 0 ' . - ' --id "' . $alert_id . '"' . - ' --output "' . $output . '"' - ); - } -} - -sub sync_acks { - my ($self, %options) = @_; - - my $func = $self->get_method(method => 'acknowledge_alert'); - foreach my $alert_id (keys %{$self->{realtime_slots}}) { - next if ($self->{realtime_slots}->{$alert_id}->{state} == 0); - next if ($self->{realtime_slots}->{$alert_id}->{acknowledged} == 0); - next if (!defined($self->{scom_realtime_alerts}->{$alert_id}) || - $self->{scom_realtime_alerts}->{$alert_id}->{resolutionstate} == 249); - $func->( - $self, - alert_id => $alert_id, - resolutionstate => 249, - ); - } - - foreach my $alert_id (keys %{$self->{scom_realtime_alerts}}) { - next if (!defined($self->{realtime_slots}->{$alert_id}) || - $self->{realtime_slots}->{$alert_id}->{state} == 0); - $self->submit_external_cmd( - cmd => sprintf( - 'EXTERNALCMD:%s:[%s] ACKNOWLEDGE_SVC_PROBLEM;%s;%s;%s;%s;%s;%s;%s', - $self->{realtime_slots}->{$alert_id}->{instance_id}, - time(), - $self->{realtime_slots}->{$alert_id}->{host_name}, - $self->{realtime_slots}->{$alert_id}->{description}, - 2, 0, 1, 'scom connector', 'ack from scom' - ) - ); - } -} - -sub action_scomresync { - my ($self, %options) = @_; - - $options{token} = $self->generate_token() if (!defined($options{token})); - - $self->send_log(code => GORGONE_ACTION_BEGIN, token => $options{token}, data => { message => 'action scomresync proceed' }); - $self->{logger}->writeLogDebug("[scom] Container $self->{container_id}: begin resync"); - - if ($self->get_realtime_slots()) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot find realtime slots' }); - $self->{logger}->writeLogError("[scom] Container $self->{container_id}: cannot find realtime slots"); - return 1; - } - - my $func = $self->get_method(method => 'get_realtime_scom_alerts'); - if ($func->($self)) { - $self->send_log(code => GORGONE_ACTION_FINISH_KO, token => $options{token}, data => { message => 'cannot get scom realtime alerts' }); - $self->{logger}->writeLogError("[scom] Container $self->{container_id}: cannot get scom realtime alerts"); - return 1; - } - - $self->sync_alerts(); - $self->sync_acks(); - - $self->{logger}->writeLogDebug("[scom] Container $self->{container_id}: finish resync"); - $self->send_log(code => GORGONE_ACTION_FINISH_OK, token => $options{token}, data => { message => 'action scomresync finished' }); - return 0; -} - -sub periodic_exec { - if ($connector->{stop} == 1) { - $connector->{logger}->writeLogInfo("[scom] $$ has quit"); - exit(0); - } - - if (time() - $self->{resync_time} > $connector->{last_resync_time}) { - $connector->{last_resync_time} = time(); - $connector->action_scomresync(); - } -} - -sub run { - my ($self, %options) = @_; - - # Database creation. We stay in the loop still there is an error - $self->{db_centstorage} = gorgone::class::db->new( - dsn => $self->{config_db_centstorage}->{dsn}, - user => $self->{config_db_centstorage}->{username}, - password => $self->{config_db_centstorage}->{password}, - force => 2, - logger => $self->{logger} - ); - ##### Load objects ##### - $self->{class_object} = gorgone::class::sqlquery->new(logger => $self->{logger}, db_centreon => $self->{db_centstorage}); - $self->{http} = gorgone::class::http::http->new(logger => $self->{logger}); - - $self->{internal_socket} = gorgone::standard::library::connect_com( - context => $self->{zmq_context}, - zmq_type => 'ZMQ_DEALER', - name => 'gorgone-scom-' . $self->{container_id}, - logger => $self->{logger}, - type => $self->get_core_config(name => 'internal_com_type'), - path => $self->get_core_config(name => 'internal_com_path') - ); - $self->send_internal_action({ - action => 'SCOMREADY', - data => { container_id => $self->{container_id} } - }); - - my $watcher_timer = $self->{loop}->timer(5, 2, \&periodic_exec); - my $watcher_io = $self->{loop}->io($connector->{internal_socket}->get_fd(), EV::READ, sub { $connector->event() } ); - $self->{loop}->run(); -} - -1; diff --git a/centreon-gorgone/gorgone/modules/plugins/scom/hooks.pm b/centreon-gorgone/gorgone/modules/plugins/scom/hooks.pm deleted file mode 100644 index 3c2d7414fc..0000000000 --- a/centreon-gorgone/gorgone/modules/plugins/scom/hooks.pm +++ /dev/null @@ -1,275 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::modules::plugins::scom::hooks; - -use warnings; -use strict; -use JSON::XS; -use gorgone::class::core; -use gorgone::modules::plugins::scom::class; -use gorgone::standard::constants qw(:all); - -use constant NAMESPACE => 'plugins'; -use constant NAME => 'scom'; -use constant EVENTS => [ - { event => 'SCOMREADY' }, - { event => 'SCOMRESYNC', uri => '/resync', method => 'GET' }, -]; - -my ($config_core, $config); -my $config_db_centstorage; -my $last_containers = {}; # Last values from config ini -my $containers = {}; -my $containers_pid = {}; -my $stop = 0; -my $timer_check = time(); -my $config_check_containers_time; - -sub register { - my (%options) = @_; - - $config = $options{config}; - $config_core = $options{config_core}; - $config_db_centstorage = $options{config_db_centstorage}; - $config_check_containers_time = defined($config->{check_containers_time}) ? $config->{check_containers_time} : 3600; - return (1, NAMESPACE, NAME, EVENTS); -} - -sub init { - my (%options) = @_; - - $last_containers = get_containers(logger => $options{logger}); - foreach my $container_id (keys %$last_containers) { - create_child(container_id => $container_id, logger => $options{logger}); - } -} - -sub routing { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - $options{logger}->writeLogError("[scom] Cannot decode json data: $@"); - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-scom: cannot decode json' }, - json_encode => 1 - }); - return undef; - } - - if ($options{action} eq 'SCOMREADY') { - $containers->{ $data->{container_id} }->{ready} = 1; - return undef; - } - - if (!defined($data->{container_id}) || !defined($last_containers->{ $data->{container_id} })) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-scom: need a valid container id' }, - json_encode => 1 - }); - return undef; - } - - if (gorgone::class::core::waiting_ready(ready => \$containers->{ $data->{container_id} }->{ready}) == 0) { - gorgone::standard::library::add_history({ - dbh => $options{dbh}, - code => GORGONE_ACTION_FINISH_KO, - token => $options{token}, - data => { message => 'gorgone-scom: still no ready' }, - json_encode => 1 - }); - return undef; - } - - $options{gorgone}->send_internal_message( - identity => 'gorgone-scom-' . $data->{container_id}, - action => $options{action}, - raw_data_ref => $options{frame}->getRawData(), - token => $options{token} - ); -} - -sub gently { - my (%options) = @_; - - $stop = 1; - foreach my $container_id (keys %$containers) { - if (defined($containers->{$container_id}->{running}) && $containers->{$container_id}->{running} == 1) { - $options{logger}->writeLogInfo("[scom] Send TERM signal for container '" . $container_id . "'"); - CORE::kill('TERM', $containers->{$container_id}->{pid}); - } - } -} - -sub kill_internal { - my (%options) = @_; - - foreach (keys %$containers) { - if ($containers->{$_}->{running} == 1) { - $options{logger}->writeLogInfo("[scom] Send KILL signal for container '" . $_ . "'"); - CORE::kill('KILL', $containers->{$_}->{pid}); - } - } -} - -sub kill { - my (%options) = @_; - -} - -sub check { - my (%options) = @_; - - if ($timer_check - time() > $config_check_containers_time) { - sync_container_childs(logger => $options{logger}); - $timer_check = time(); - } - - my $count = 0; - foreach my $pid (keys %{$options{dead_childs}}) { - # Not me - next if (!defined($containers_pid->{$pid})); - - # If someone dead, we recreate - delete $containers->{$containers_pid->{$pid}}; - delete $containers_pid->{$pid}; - delete $options{dead_childs}->{$pid}; - if ($stop == 0) { - # Need to check if we need to recreate (can be a container destruction)!!! - sync_container_childs(logger => $options{logger}); - } - } - - return $count; -} - -sub broadcast { - my (%options) = @_; - - foreach my $container_id (keys %$containers) { - next if ($containers->{$container_id}->{ready} != 1); - - $options{gorgone}->send_internal_message( - identity => 'gorgone-scom-' . $container_id, - action => $options{action}, - frame => $options{frame}, - token => $options{token} - ); - } -} - -# Specific functions -sub get_containers { - my (%options) = @_; - - my $containers = {}; - return $containers if (!defined($config->{containers})); - foreach (@{$config->{containers}}) { - next if (!defined($_->{name}) || $_->{name} eq ''); - - if (!defined($_->{url}) || $_->{url} eq '') { - $options{logger}->writeLogError("[scom] Cannot load container '" . $_->{name} . "' - please set url option"); - next; - } - if (!defined($_->{dsmhost}) || $_->{dsmhost} eq '') { - $options{logger}->writeLogError("[scom] Cannot load container '" . $_->{name} . "' - please set dsmhost option"); - next; - } - if (!defined($_->{dsmslot}) || $_->{dsmslot} eq '') { - $options{logger}->writeLogError("[scom] Cannot load container '" . $_->{name} . "' - please set dsmslot option"); - next; - } - - $containers->{$_->{name}} = { - url => $_->{url}, - username => $_->{username}, - password => $_->{password}, - httpauth => defined($_->{httpauth}) && $_->{httpauth} =~ /(basic|ntlmv2)/ ? $_->{httpauth} : 'basic', - resync_time => - (defined($_->{resync_time}) && $_->{resync_time} =~ /(\d+)/) ? $1 : 300, - api_version => (defined($_->{api_version}) && $_->{api_version} =~ /(2012|2016|1801)/) ? $1 : '2016', - dsmhost => $_->{dsmhost}, - dsmslot => $_->{dsmslot}, - dsmmacro => defined($_->{dsmmacro}) ? $_->{dsmmacro} : 'ALARM_ID', - dsmalertmessage => defined($_->{dsmalertmessage}) ? $_->{dsmalertmessage} : '%{monitoringobjectdisplayname} %{name}', - dsmrecoverymessage => defined($_->{dsmrecoverymessage}) ? $_->{dsmrecoverymessage} : 'slot ok', - curlopts => $_->{curlopts}, - }; - } - - return $containers; -} - -sub sync_container_childs { - my (%options) = @_; - - $last_containers = get_containers(logger => $options{logger}); - foreach my $container_id (keys %$last_containers) { - if (!defined($containers->{$container_id})) { - create_child(container_id => $container_id, logger => $options{logger}); - } - } - - # Check if need to delete on containers - foreach my $container_id (keys %$containers) { - next if (defined($last_containers->{$container_id})); - - if ($containers->{$container_id}->{running} == 1) { - $options{logger}->writeLogDebug("[scom] Send KILL signal for container '" . $container_id . "'"); - CORE::kill('KILL', $containers->{$container_id}->{pid}); - } - - delete $containers_pid->{ $containers->{$container_id}->{pid} }; - delete $containers->{$container_id}; - } -} - -sub create_child { - my (%options) = @_; - - $options{logger}->writeLogInfo("[scom] Create 'gorgone-scom' process for container '" . $options{container_id} . "'"); - my $child_pid = fork(); - if ($child_pid == 0) { - $0 = 'gorgone-scom ' . $options{container_id}; - my $module = gorgone::modules::plugins::scom::class->new( - logger => $options{logger}, - module_id => NAME, - config_core => $config_core, - config => $config, - config_db_centstorage => $config_db_centstorage, - config_scom => $last_containers->{$options{container_id}}, - container_id => $options{container_id}, - ); - $module->run(); - exit(0); - } - $options{logger}->writeLogDebug("[scom] PID $child_pid (gorgone-scom) for container '" . $options{container_id} . "'"); - $containers->{$options{container_id}} = { pid => $child_pid, ready => 0, running => 1 }; - $containers_pid->{$child_pid} = $options{container_id}; -} - -1; diff --git a/centreon-gorgone/gorgone/standard/api.pm b/centreon-gorgone/gorgone/standard/api.pm deleted file mode 100644 index 52f810a647..0000000000 --- a/centreon-gorgone/gorgone/standard/api.pm +++ /dev/null @@ -1,253 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::standard::api; - -use strict; -use warnings; -use gorgone::standard::library; -use Time::HiRes; -use JSON::XS; - -my $module; -my $socket; -my $action_token; - -sub set_module { - $module = $_[0]; -} - -sub root { - my (%options) = @_; - - $options{logger}->writeLogInfo("[api] Requesting '" . $options{uri} . "' [" . $options{method} . "]"); - - $options{module}->{tokens} = {}; - $socket = $options{socket}; - $module = $options{module}; - - my $response; - if ($options{method} eq 'GET' && $options{uri} =~ /^\/api\/(nodes\/(\w*)\/)?log\/(.*)$/) { - $response = get_log( - target => $2, - token => $3, - sync_wait => (defined($options{parameters}->{sync_wait})) ? $options{parameters}->{sync_wait} : undef, - parameters => $options{parameters}, - module => $options{module} - ); - } elsif ($options{uri} =~ /^\/api\/(nodes\/(\w*)\/)?internal\/(\w+)\/?([\w\/]*?)$/ - && defined($options{api_endpoints}->{$options{method} . '_/internal/' . $3})) { - my @variables = split(/\//, $4); - $response = call_internal( - action => $options{api_endpoints}->{$options{method} . '_/internal/' . $3}, - target => $2, - data => { - content => $options{content}, - parameters => $options{parameters}, - variables => \@variables - }, - log_wait => (defined($options{parameters}->{log_wait})) ? $options{parameters}->{log_wait} : undef, - sync_wait => (defined($options{parameters}->{sync_wait})) ? $options{parameters}->{sync_wait} : undef, - module => $options{module} - ); - } elsif ($options{uri} =~ /^\/api\/(nodes\/(\w*)\/)?(\w+)\/(\w+)\/(\w+)\/?([\w\/]*?)$/ - && defined($options{api_endpoints}->{$options{method} . '_/' . $3 . '/' . $4 . '/' . $5})) { - my @variables = split(/\//, $6); - $response = call_action( - action => $options{api_endpoints}->{$options{method} . '_/' . $3 . '/' . $4 . '/' . $5}, - target => $2, - data => { - content => $options{content}, - parameters => $options{parameters}, - variables => \@variables - }, - log_wait => (defined($options{parameters}->{log_wait})) ? $options{parameters}->{log_wait} : undef, - sync_wait => (defined($options{parameters}->{sync_wait})) ? $options{parameters}->{sync_wait} : undef, - module => $options{module} - ); - } else { - $response = '{"error":"method_unknown","message":"Method not implemented","http_response_code":"404"}'; - } - - return $response; -} - -sub stop_ev { - $module->{loop}->break(); -} - -sub call_action { - my (%options) = @_; - - $action_token = gorgone::standard::library::generate_token() if (!defined($options{token})); - - $options{module}->send_internal_action({ - socket => $socket, - action => $options{action}, - target => $options{target}, - token => $action_token, - data => $options{data}, - json_encode => 1 - }); - - my $response = '{"token":"' . $action_token . '"}'; - if (defined($options{log_wait}) && $options{log_wait} ne '') { - Time::HiRes::usleep($options{log_wait}); - $response = get_log( - target => $options{target}, - token => $action_token, - sync_wait => $options{sync_wait}, - parameters => $options{data}->{parameters}, - module => $options{module} - ); - } - - return $response; -} - -sub call_internal { - my (%options) = @_; - - $action_token = gorgone::standard::library::generate_token(); - if (defined($options{target}) && $options{target} ne '') { - return call_action( - target => $options{target}, - action => $options{action}, - token => $action_token, - data => $options{data}, - json_encode => 1, - log_wait => $options{log_wait}, - sync_wait => $options{sync_wait}, - module => $options{module} - ); - } - - $options{module}->send_internal_action({ - socket => $socket, - action => $options{action}, - token => $action_token, - data => $options{data}, - json_encode => 1 - }); - - $options{module}->{break_token} = $action_token; - - my $timeout = 5; - my $ctime = time(); - while (1) { - my $watcher_timer = $options{module}->{loop}->timer(1, 0, \&stop_ev); - $options{module}->{loop}->run(); - last if (time() > ($ctime + $timeout) || defined($options{module}->{tokens}->{$action_token})); - } - - $options{module}->{break_token} = undef; - - my $response = '{"error":"no_result", "message":"No result found for action \'' . $options{action} . '\'"}'; - if (defined($options{module}->{tokens}->{$action_token}->{data})) { - my $content; - eval { - $content = JSON::XS->new->decode($options{module}->{tokens}->{$action_token}->{data}); - }; - if ($@) { - $response = '{"error":"decode_error","message":"Cannot decode response","http_response_code":"400"}'; - } else { - if (defined($content->{data})) { - eval { - $response = JSON::XS->new->encode($content->{data}); - }; - if ($@) { - $response = '{"error":"encode_error","message":"Cannot encode response","http_response_code":"400"}'; - } - } else { - $response = ''; - } - } - } - - return $response; -} - -sub get_log { - my (%options) = @_; - - if (defined($options{target}) && $options{target} ne '') { - $options{module}->send_internal_action({ - socket => $socket, - target => $options{target}, - action => 'GETLOG', - json_encode => 1 - }); - - my $sync_wait = (defined($options{sync_wait}) && $options{sync_wait} ne '') ? $options{sync_wait} : 10000; - Time::HiRes::usleep($sync_wait); - } - - my $token_log = $options{token} . '-log'; - $options{module}->send_internal_action({ - socket => $socket, - action => 'GETLOG', - token => $token_log, - data => { - token => $options{token}, - %{$options{parameters}} - }, - json_encode => 1 - }); - - $options{module}->{break_token} = $token_log; - - my $timeout = 5; - my $ctime = time(); - while (1) { - my $watcher_timer = $options{module}->{loop}->timer(1, 0, \&stop_ev); - $options{module}->{loop}->run(); - last if (time() > ($ctime + $timeout) || defined($options{module}->{tokens}->{$token_log})); - } - - $options{module}->{break_token} = undef; - - my $response = '{"error":"no_log","message":"No log found for token","data":[],"token":"' . $options{token} . '"}'; - if (defined($options{module}->{tokens}->{$token_log}) && defined($options{module}->{tokens}->{ $token_log }->{data})) { - my $content; - eval { - $content = JSON::XS->new->decode($options{module}->{tokens}->{ $token_log }->{data}); - }; - if ($@) { - $response = '{"error":"decode_error","message":"Cannot decode response"}'; - } elsif (defined($content->{data}->{result}) && scalar(@{$content->{data}->{result}}) > 0) { - eval { - $response = JSON::XS->new->encode( - { - message => "Logs found", - token => $options{token}, - data => $content->{data}->{result} - } - ); - }; - if ($@) { - $response = '{"error":"encode_error","message":"Cannot encode response"}'; - } - } - } - - return $response; -} - -1; diff --git a/centreon-gorgone/gorgone/standard/constants.pm b/centreon-gorgone/gorgone/standard/constants.pm deleted file mode 100644 index 789863f944..0000000000 --- a/centreon-gorgone/gorgone/standard/constants.pm +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::standard::constants; - -use strict; -use warnings; -use base qw(Exporter); - -my %constants; -BEGIN { - %constants = ( - GORGONE_ACTION_BEGIN => 0, - GORGONE_ACTION_FINISH_KO => 1, - GORGONE_ACTION_FINISH_OK => 2, - GORGONE_STARTED => 3, - GORGONE_ACTION_CONTINUE => 4, - - GORGONE_MODULE_ACTION_COMMAND_RESULT => 100, - GORGONE_MODULE_ACTION_PROCESSCOPY_INPROGRESS => 101, - - GORGONE_MODULE_PIPELINE_RUN_ACTION => 200, - GORGONE_MODULE_PIPELINE_FINISH_ACTION => 201, - - GORGONE_MODULE_CENTREON_JUDGE_FAILOVER_RUNNING => 300, - GORGONE_MODULE_CENTREON_JUDGE_FAILBACK_RUNNING => 301, - - GORGONE_MODULE_CENTREON_AUTODISCO_SVC_PROGRESS => 400, - - GORGONE_MODULE_CENTREON_AUDIT_PROGRESS => 500, - - GORGONE_MODULE_CENTREON_MBIETL_PROGRESS => 600 - ); -} - -use constant \%constants; -our @EXPORT; -our @EXPORT_OK = keys %constants; - -our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] ); - -1; diff --git a/centreon-gorgone/gorgone/standard/library.pm b/centreon-gorgone/gorgone/standard/library.pm deleted file mode 100644 index b0ea3c8b9d..0000000000 --- a/centreon-gorgone/gorgone/standard/library.pm +++ /dev/null @@ -1,1011 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::standard::library; - -use strict; -use warnings; -use gorgone::standard::constants qw(:all); -use ZMQ::FFI qw(ZMQ_DEALER ZMQ_ROUTER ZMQ_ROUTER_HANDOVER ZMQ_IPV6 ZMQ_TCP_KEEPALIVE - ZMQ_CONNECT_TIMEOUT ZMQ_DONTWAIT ZMQ_SNDMORE ZMQ_IDENTITY ZMQ_FD ZMQ_EVENTS - ZMQ_LINGER ZMQ_SNDHWM ZMQ_RCVHWM ZMQ_RECONNECT_IVL); -use JSON::XS; -use File::Basename; -use Crypt::PK::RSA; -use Crypt::PRNG; -use Crypt::Mode::CBC; -use File::Path; -use File::Basename; -use MIME::Base64; -use Errno; -use Time::HiRes; -use Try::Tiny; -use YAML::XS; -use gorgone::class::frame; -$YAML::XS::Boolean = 'JSON::PP'; -$YAML::XS::LoadBlessed = 1; - -our $listener; -my %zmq_type = ('ZMQ_ROUTER' => ZMQ_ROUTER, 'ZMQ_DEALER' => ZMQ_DEALER); - -sub read_config { - my (%options) = @_; - - my $config; - try { - $config = YAML::XS::LoadFile($options{config_file}); - } catch { - $options{logger}->writeLogError("[core] Parsing config file error:"); - $options{logger}->writeLogError($@); - exit(1); - }; - - return $config; -} - -####################### -# Handshake functions -####################### - -sub generate_keys { - my (%options) = @_; - - my ($privkey, $pubkey); - try { - my $pkrsa = Crypt::PK::RSA->new(); - $pkrsa->generate_key(256, 65537); - $pubkey = $pkrsa->export_key_pem('public_x509'); - $privkey = $pkrsa->export_key_pem('private'); - } catch { - $options{logger}->writeLogError("[core] Cannot generate server keys: $_"); - return 0; - }; - - return (1, $privkey, $pubkey); -} - -sub loadpubkey { - my (%options) = @_; - my $quit = defined($options{noquit}) ? 0 : 1; - my $string_key = ''; - - if (defined($options{pubkey})) { - if (!open FILE, "<" . $options{pubkey}) { - $options{logger}->writeLogError("[core] Cannot read file '$options{pubkey}': $!") if (defined($options{logger})); - exit(1) if ($quit); - return 0; - } - while () { - $string_key .= $_; - } - close FILE; - } else { - $string_key = $options{pubkey_str}; - } - - my $pubkey; - try { - $pubkey = Crypt::PK::RSA->new(\$string_key); - } catch { - $options{logger}->writeLogError("[core] Cannot load pubkey '$options{pubkey}': $_") if (defined($options{logger})); - exit(1) if ($quit); - return 0; - }; - if ($pubkey->is_private()) { - $options{logger}->writeLogError("[core] '$options{pubkey}' is not a public key") if (defined($options{logger})); - exit(1) if ($quit); - return 0; - } - - return (1, $pubkey); -} - -sub loadprivkey { - my (%options) = @_; - my $string_key = ''; - my $quit = defined($options{noquit}) ? 0 : 1; - - if (!open FILE, "<" . $options{privkey}) { - $options{logger}->writeLogError("[core] Cannot read file '$options{privkey}': $!"); - exit(1) if ($quit); - return 0; - } - while () { - $string_key .= $_; - } - close FILE; - - my $privkey; - try { - $privkey = Crypt::PK::RSA->new(\$string_key); - } catch { - $options{logger}->writeLogError("[core] Cannot load privkey '$options{privkey}': $_"); - exit(1) if ($quit); - return 0; - }; - if (!$privkey->is_private()) { - $options{logger}->writeLogError("[core] '$options{privkey}' is not a private key"); - exit(1) if ($quit); - return 0; - } - - return (1, $privkey); -} - -sub zmq_core_pubkey_response { - my (%options) = @_; - - if (defined($options{identity})) { - $options{socket}->send(pack('H*', $options{identity}), ZMQ_DONTWAIT | ZMQ_SNDMORE); - } - my $client_pubkey = $options{pubkey}->export_key_pem('public'); - my $msg = '[PUBKEY] [' . MIME::Base64::encode_base64($client_pubkey, '') . ']'; - - $options{socket}->send($msg, ZMQ_DONTWAIT); - return 0; -} - -sub zmq_get_routing_id { - my (%options) = @_; - - return $options{socket}->get_identity(); -} - -sub zmq_getfd { - my (%options) = @_; - - return $options{socket}->get_fd(); -} - -sub zmq_events { - my (%options) = @_; - - return $options{socket}->get(ZMQ_EVENTS, 'int'); -} - -sub generate_token { - my (%options) = @_; - - my $length = (defined($options{length})) ? $options{length} : 64; - my $token = Crypt::PRNG::random_bytes_hex($length); - return $token; -} - -sub generate_symkey { - my (%options) = @_; - - my $random_key = Crypt::PRNG::random_bytes($options{keysize}); - return (0, $random_key); -} - -sub client_helo_encrypt { - my (%options) = @_; - my $ciphertext; - - my $client_pubkey = $options{client_pubkey}->export_key_pem('public'); - try { - $ciphertext = $options{server_pubkey}->encrypt('HELO', 'v1.5'); - } catch { - return (-1, "Encoding issue: $_"); - }; - - return (0, '[' . $options{identity} . '] [' . MIME::Base64::encode_base64($client_pubkey, '') . '] [' . MIME::Base64::encode_base64($ciphertext, '') . ']'); -} - -sub is_client_can_connect { - my (%options) = @_; - my $plaintext; - - if ($options{message} !~ /\[(.+)\]\s+\[(.+)\]\s+\[(.+)\]$/ms) { - $options{logger}->writeLogError("[core] Decoding issue. Protocol not good: $options{message}"); - return -1; - } - - my ($client, $client_pubkey_str, $cipher_text) = ($1, $2, $3); - try { - $plaintext = $options{privkey}->decrypt(MIME::Base64::decode_base64($cipher_text), 'v1.5'); - } catch { - $options{logger}->writeLogError("[core] Decoding issue: $_"); - return -1; - }; - if ($plaintext ne 'HELO') { - $options{logger}->writeLogError("[core] Encrypted issue for HELO"); - return -1; - } - - my ($client_pubkey); - $client_pubkey_str = MIME::Base64::decode_base64($client_pubkey_str); - try { - $client_pubkey = Crypt::PK::RSA->new(\$client_pubkey_str); - } catch { - $options{logger}->writeLogError("[core] Cannot load client pubkey '$client_pubkey': $_"); - return -1; - }; - - my $is_authorized = 0; - my $thumbprint = $client_pubkey->export_key_jwk_thumbprint('SHA256'); - if (defined($options{authorized_clients})) { - foreach (@{$options{authorized_clients}}) { - if ($_->{key} eq $thumbprint) { - $is_authorized = 1; - last; - } - } - } - - if ($is_authorized == 0) { - $options{logger}->writeLogError("[core] Client pubkey is not authorized. Thumbprint is '$thumbprint'"); - return -1; - } - - $options{logger}->writeLogInfo("[core] Connection from $client"); - return (0, $client_pubkey); -} - -####################### -# internal functions -####################### - -sub addlistener { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - foreach (@$data) { - $options{gorgone}->{listener}->add_listener( - identity => $options{identity}, - event => $_->{event}, - target => $_->{target}, - token => $_->{token}, - log_pace => $_->{log_pace}, - timeout => $_->{timeout} - ); - } - - return (GORGONE_ACTION_FINISH_OK, { action => 'addlistener', message => 'ok', data => $data }); -} - -sub getthumbprint { - my (%options) = @_; - - if ($options{gorgone}->{keys_loaded} == 0) { - return (GORGONE_ACTION_FINISH_KO, { action => 'getthumbprint', message => 'no public key loaded' }, 'GETTHUMBPRINT'); - } - my $thumbprint = $options{gorgone}->{server_pubkey}->export_key_jwk_thumbprint('SHA256'); - return (GORGONE_ACTION_FINISH_OK, { action => 'getthumbprint', message => 'ok', data => { thumbprint => $thumbprint } }, 'GETTHUMBPRINT'); -} - -sub information { - my (%options) = @_; - - my $data = { - counters => $options{gorgone}->{counters}, - modules => $options{gorgone}->{modules_id}, - api_endpoints => $options{gorgone}->{api_endpoints} - }; - return (GORGONE_ACTION_FINISH_OK, { action => 'information', message => 'ok', data => $data }, 'INFORMATION'); -} - -sub unloadmodule { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - if (defined($data->{content}->{package}) && defined($options{gorgone}->{modules_register}->{ $data->{content}->{package} })) { - $options{gorgone}->{modules_register}->{ $data->{content}->{package} }->{gently}->(logger => $options{gorgone}->{logger}); - return (GORGONE_ACTION_BEGIN, { action => 'unloadmodule', message => "module '$data->{content}->{package}' unload in progress" }, 'UNLOADMODULE'); - } - if (defined($data->{content}->{name}) && - defined($options{gorgone}->{modules_id}->{$data->{content}->{name}}) && - defined($options{gorgone}->{modules_register}->{ $options{gorgone}->{modules_id}->{$data->{content}->{name}} })) { - $options{gorgone}->{modules_register}->{ $options{gorgone}->{modules_id}->{$data->{content}->{name}} }->{gently}->(logger => $options{gorgone}->{logger}); - return (GORGONE_ACTION_BEGIN, { action => 'unloadmodule', message => "module '$data->{content}->{name}' unload in progress" }, 'UNLOADMODULE'); - } - - return (GORGONE_ACTION_FINISH_KO, { action => 'unloadmodule', message => 'cannot find unload module' }, 'UNLOADMODULE'); -} - -sub loadmodule { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - if ($options{gorgone}->load_module(config_module => $data->{content})) { - $options{gorgone}->{modules_register}->{ $data->{content}->{package} }->{init}->( - id => $options{gorgone}->{id}, - logger => $options{gorgone}->{logger}, - poll => $options{gorgone}->{poll}, - external_socket => $options{gorgone}->{external_socket}, - internal_socket => $options{gorgone}->{internal_socket}, - dbh => $options{gorgone}->{db_gorgone}, - api_endpoints => $options{gorgone}->{api_endpoints} - ); - return (GORGONE_ACTION_BEGIN, { action => 'loadmodule', message => "module '$data->{content}->{name}' is loaded" }, 'LOADMODULE'); - } - - return (GORGONE_ACTION_FINISH_KO, { action => 'loadmodule', message => "cannot load module '$data->{content}->{name}'" }, 'LOADMODULE'); -} - -sub synclogs { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - if (!defined($data->{data}->{id})) { - return (GORGONE_ACTION_FINISH_KO, { action => 'synclog', message => 'please set id for synclog' }); - } - - if (defined($options{gorgone_config}->{gorgonecore}->{proxy_name}) && defined($options{gorgone}->{modules_id}->{$options{gorgone_config}->{gorgonecore}->{proxy_name}})) { - my $name = $options{gorgone}->{modules_id}->{$options{gorgone_config}->{gorgonecore}->{proxy_name}}; - my $method; - if (defined($name) && ($method = $name->can('synclog'))) { - $method->( - gorgone => $options{gorgone}, - dbh => $options{gorgone}->{db_gorgone}, - logger => $options{gorgone}->{logger} - ); - return (GORGONE_ACTION_BEGIN, { action => 'synclog', message => 'synclog launched' }); - } - } - - return (GORGONE_ACTION_FINISH_KO, { action => 'synclog', message => 'no proxy module' }); -} - -sub constatus { - my (%options) = @_; - - if (defined($options{gorgone_config}->{gorgonecore}->{proxy_name}) && defined($options{gorgone}->{modules_id}->{$options{gorgone_config}->{gorgonecore}->{proxy_name}})) { - my $name = $options{gorgone}->{modules_id}->{$options{gorgone_config}->{gorgonecore}->{proxy_name}}; - my $method; - if (defined($name) && ($method = $name->can('get_constatus_result'))) { - return (GORGONE_ACTION_FINISH_OK, { action => 'constatus', message => 'ok', data => $method->() }, 'CONSTATUS'); - } - } - - return (GORGONE_ACTION_FINISH_KO, { action => 'constatus', message => 'cannot get value' }, 'CONSTATUS'); -} - -sub setmodulekey { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - if (!defined($data->{key})) { - return (GORGONE_ACTION_FINISH_KO, { action => 'setmodulekey', message => 'please set key' }); - } - - my $id = pack('H*', $options{identity}); - $options{gorgone}->{config}->{configuration}->{gorgone}->{gorgonecore}->{internal_com_identity_keys}->{$id} = { - key => pack('H*', $data->{key}), - ctime => time() - }; - - $options{logger}->writeLogInfo('[core] module key ' . $id . ' changed'); - return (GORGONE_ACTION_FINISH_OK, { action => 'setmodulekey', message => 'setmodulekey changed' }); -} - -sub setcoreid { - my (%options) = @_; - - if (defined($options{gorgone}->{config}->{configuration}->{gorgone}->{gorgonecore}->{id}) && - $options{gorgone}->{config}->{configuration}->{gorgone}->{gorgonecore}->{id} =~ /\d+/) { - return (GORGONE_ACTION_FINISH_OK, { action => 'setcoreid', message => 'setcoreid unchanged, use config value' }) - } - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - if (!defined($data->{id})) { - return (GORGONE_ACTION_FINISH_KO, { action => 'setcoreid', message => 'please set id for setcoreid' }); - } - - if (defined($options{gorgone_config}->{gorgonecore}->{proxy_name}) && defined($options{gorgone}->{modules_id}->{$options{gorgone_config}->{gorgonecore}->{proxy_name}})) { - my $name = $options{gorgone}->{modules_id}->{$options{gorgone_config}->{gorgonecore}->{proxy_name}}; - my $method; - if (defined($name) && ($method = $name->can('setcoreid'))) { - $method->(dbh => $options{dbh}, core_id => $data->{id}, logger => $options{logger}); - } - } - - $options{logger}->writeLogInfo('[core] Setcoreid changed ' . $data->{id}); - $options{gorgone}->{id} = $data->{id}; - return (GORGONE_ACTION_FINISH_OK, { action => 'setcoreid', message => 'setcoreid changed' }); -} - -sub ping { - my (%options) = @_; - - my $constatus = {}; - if (defined($options{gorgone_config}->{gorgonecore}->{proxy_name}) && defined($options{gorgone}->{modules_id}->{$options{gorgone_config}->{gorgonecore}->{proxy_name}})) { - my $name = $options{gorgone}->{modules_id}->{$options{gorgone_config}->{gorgonecore}->{proxy_name}}; - my $method; - if (defined($name) && ($method = $name->can('get_constatus_result'))) { - $constatus = $method->(); - } - if (defined($name) && ($method = $name->can('add_parent_ping'))) { - $method->(router_type => $options{router_type}, identity => $options{identity}, logger => $options{logger}); - } - } - - return (GORGONE_ACTION_BEGIN, { action => 'ping', message => 'ping ok', id => $options{id}, hostname => $options{gorgone}->{hostname}, data => $constatus }, 'PONG'); -} - -sub putlog { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - my $status = add_history({ - dbh => $options{gorgone}->{db_gorgone}, - etime => $data->{etime}, - token => $data->{token}, - instant => $data->{instant}, - data => json_encode(data => $data->{data}, logger => $options{logger}), - code => $data->{code} - }); - if ($status == -1) { - return (GORGONE_ACTION_FINISH_KO, { message => 'database issue' }); - } - return (GORGONE_ACTION_BEGIN, { message => 'message inserted' }); -} - -sub getlog { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - my %filters = (); - my ($filter, $filter_append) = ('', ''); - my @bind_values = (); - foreach ((['id', '>'], ['token', '='], ['ctime', '>'], ['etime', '>'], ['code', '='])) { - if (defined($data->{$_->[0]}) && $data->{$_->[0]} ne '') { - $filter .= $filter_append . $_->[0] . ' ' . $_->[1] . ' ?'; - $filter_append = ' AND '; - push @bind_values, $data->{ $_->[0] }; - } - } - - if ($filter eq '') { - return (GORGONE_ACTION_FINISH_KO, { message => 'need at least one filter' }); - } - - my $query = "SELECT * FROM gorgone_history WHERE " . $filter; - $query .= " ORDER BY id DESC LIMIT " . $data->{limit} if (defined($data->{limit}) && $data->{limit} ne ''); - - my ($status, $sth) = $options{gorgone}->{db_gorgone}->query({ query => $query, bind_values => \@bind_values }); - if ($status == -1) { - return (GORGONE_ACTION_FINISH_KO, { message => 'database issue' }); - } - - my @result; - my $results = $sth->fetchall_hashref('id'); - foreach (sort keys %{$results}) { - push @result, $results->{$_}; - } - - return (GORGONE_ACTION_BEGIN, { action => 'getlog', result => \@result, id => $options{gorgone}->{id} }); -} - -sub kill { - my (%options) = @_; - - my $data = $options{frame}->decodeData(); - if (!defined($data)) { - return (GORGONE_ACTION_FINISH_KO, { message => 'request not well formatted' }); - } - - if (defined($data->{content}->{package}) && defined($options{gorgone}->{modules_register}->{ $data->{content}->{package} })) { - $options{gorgone}->{modules_register}->{ $data->{content}->{package} }->{kill}->(logger => $options{gorgone}->{logger}); - return (GORGONE_ACTION_FINISH_OK, { action => 'kill', message => "module '$data->{content}->{package}' kill in progress" }); - } - if (defined($data->{content}->{name}) && - defined($options{gorgone}->{modules_id}->{ $data->{content}->{name} }) && - defined($options{gorgone}->{modules_register}->{ $options{gorgone}->{modules_id}->{ $data->{content}->{name} } })) { - $options{gorgone}->{modules_register}->{ $options{gorgone}->{modules_id}->{ $data->{content}->{name} } }->{kill}->(logger => $options{gorgone}->{logger}); - return (GORGONE_ACTION_FINISH_OK, { action => 'kill', message => "module '$data->{content}->{name}' kill in progress" }); - } - - return (GORGONE_ACTION_FINISH_KO, { action => 'kill', message => 'cannot find module' }); -} - -####################### -# Database functions -####################### - -sub update_identity_attrs { - my (%options) = @_; - - my @fields = (); - my @bind_values = (); - foreach ('key', 'oldkey', 'iv', 'oldiv', 'ctime') { - next if (!defined($options{$_})); - - if ($options{$_} eq 'NULL') { - push @fields, "`$_` = NULL"; - } else { - push @fields, "`$_` = ?"; - push @bind_values, $options{$_}; - } - } - push @bind_values, $options{identity}, $options{identity}; - - my ($status, $sth) = $options{dbh}->query({ - query => "UPDATE gorgone_identity SET " . join(', ', @fields) . - " WHERE `identity` = ? AND " . - " `id` = (SELECT `id` FROM gorgone_identity WHERE `identity` = ? ORDER BY `id` DESC LIMIT 1)", - bind_values => \@bind_values - }); - - return $status; -} - -sub update_identity_mtime { - my (%options) = @_; - - my ($status, $sth) = $options{dbh}->query({ - query => "UPDATE gorgone_identity SET `mtime` = ?" . - " WHERE `identity` = ? AND " . - " `id` = (SELECT `id` FROM gorgone_identity WHERE `identity` = ? ORDER BY `id` DESC LIMIT 1)", - bind_values => [time(), $options{identity}, $options{identity}] - }); - return $status; -} - -sub add_identity { - my (%options) = @_; - - my $time = time(); - my ($status, $sth) = $options{dbh}->query({ - query => "INSERT INTO gorgone_identity (`ctime`, `mtime`, `identity`, `key`, `iv`) VALUES (?, ?, ?, ?, ?)", - bind_values => [$time, $time, $options{identity}, unpack('H*', $options{key}), unpack('H*', $options{iv})] - }); - return $status; -} - -sub add_history { - my ($options) = (shift); - - if (defined($options->{data}) && defined($options->{json_encode})) { - return -1 if (!($options->{data} = json_encode(data => $options->{data}, logger => $options->{logger}))); - } - if (!defined($options->{ctime})) { - $options->{ctime} = Time::HiRes::time(); - } - if (!defined($options->{etime})) { - $options->{etime} = time(); - } - - my $fields = ''; - my $placeholder = ''; - my $append = ''; - my @bind_values = (); - foreach (('data', 'token', 'ctime', 'etime', 'code', 'instant')) { - if (defined($options->{$_})) { - $fields .= $append . $_; - $placeholder .= $append . '?'; - $append = ', '; - push @bind_values, $options->{$_}; - } - } - my ($status, $sth) = $options->{dbh}->query({ - query => "INSERT INTO gorgone_history ($fields) VALUES ($placeholder)", - bind_values => \@bind_values - }); - - if (defined($options->{token}) && $options->{token} ne '') { - $listener->event_log( - { - token => $options->{token}, - code => $options->{code}, - data => \$options->{data} - } - ); - } - - return $status; -} - -####################### -# Misc functions -####################### - -sub json_encode { - my (%options) = @_; - - try { - $options{data} = JSON::XS->new->encode($options{data}); - } catch { - if (defined($options{logger})) { - $options{logger}->writeLogError("[core] Cannot encode json data: $_"); - } - return undef; - }; - - return $options{data}; -} - -sub json_decode { - my (%options) = @_; - - try { - $options{data} = JSON::XS->new->decode($options{data}); - } catch { - if (defined($options{logger})) { - $options{logger}->writeLogError("[$options{module}] Cannot decode json data: $_"); - } - return undef; - }; - - return $options{data}; -} - -####################### -# Global ZMQ functions -####################### - -sub connect_com { - my (%options) = @_; - - my $socket = $options{context}->socket($zmq_type{$options{zmq_type}}); - if (!defined($socket)) { - $options{logger}->writeLogError("Can't setup server: $!"); - exit(1); - } - $socket->die_on_error(0); - - $socket->set_identity($options{name}); - $socket->set(ZMQ_LINGER, 'int', defined($options{zmq_linger}) ? $options{zmq_linger} : 0); # 0 we discard - $socket->set(ZMQ_SNDHWM, 'int', defined($options{zmq_sndhwm}) ? $options{zmq_sndhwm} : 0); - $socket->set(ZMQ_RCVHWM, 'int', defined($options{zmq_rcvhwm}) ? $options{zmq_rcvhwm} : 0); - $socket->set(ZMQ_RECONNECT_IVL, 'int', 1000); - $socket->set(ZMQ_CONNECT_TIMEOUT, 'int', defined($options{zmq_connect_timeout}) ? $options{zmq_connect_timeout} : 30000); - if ($options{zmq_type} eq 'ZMQ_ROUTER') { - $socket->set(ZMQ_ROUTER_HANDOVER, 'int', defined($options{zmq_router_handover}) ? $options{zmq_router_handover} : 1); - } - if ($options{type} eq 'tcp') { - $socket->set(ZMQ_TCP_KEEPALIVE, 'int', defined($options{zmq_tcp_keepalive}) ? $options{zmq_tcp_keepalive} : -1); - } - - $socket->connect($options{type} . '://' . $options{path}); - return $socket; -} - -sub create_com { - my (%options) = @_; - - my $socket = $options{context}->socket($zmq_type{$options{zmq_type}}); - if (!defined($socket)) { - $options{logger}->writeLogError("Can't setup server: $!"); - exit(1); - } - $socket->die_on_error(0); - - $socket->set_identity($options{name}); - $socket->set_linger(0); - $socket->set(ZMQ_ROUTER_HANDOVER, 'int', defined($options{zmq_router_handover}) ? $options{zmq_router_handover} : 1); - - if ($options{type} eq 'tcp') { - $socket->set(ZMQ_IPV6, 'int', defined($options{zmq_ipv6}) && $options{zmq_ipv6} =~ /true|1/i ? 1 : 0); - $socket->set(ZMQ_TCP_KEEPALIVE, 'int', defined($options{zmq_tcp_keepalive}) ? $options{zmq_tcp_keepalive} : -1); - - $socket->bind('tcp://' . $options{path}); - } elsif ($options{type} eq 'ipc') { - $socket->bind('ipc://' . $options{path}); - if ($socket->has_error) { - $options{logger}->writeLogDebug("[core] Cannot bind IPC '$options{path}': $!"); - # try create dir - $options{logger}->writeLogDebug("[core] Maybe directory not exist. We try to create it"); - if (!mkdir(dirname($options{path}))) { - $options{logger}->writeLogError("[core] Cannot create IPC file directory '$options{path}'"); - exit(1); - } - $socket->bind('ipc://' . $options{path}); - if ($socket->has_error) { - $options{logger}->writeLogError("[core] Cannot bind IPC '$options{path}': " . $socket->last_strerror); - exit(1); - } - } - } else { - $options{logger}->writeLogError("[core] ZMQ type '$options{type}' not managed"); - exit(1); - } - - return $socket; -} - -sub build_protocol { - my (%options) = @_; - my $data = $options{data}; - my $token = defined($options{token}) ? $options{token} : ''; - my $action = defined($options{action}) ? $options{action} : ''; - my $target = defined($options{target}) ? $options{target} : ''; - - if (defined($options{raw_data_ref})) { - return '[' . $action . '] [' . $token . '] [' . $target . '] ' . ${$options{raw_data_ref}}; - } elsif (defined($data)) { - if (defined($options{json_encode})) { - $data = json_encode(data => $data, logger => $options{logger}); - } - } else { - $data = json_encode(data => {}, logger => $options{logger}); - } - - return '[' . $action . '] [' . $token . '] [' . $target . '] ' . $data; -} - -sub zmq_dealer_read_message { - my (%options) = @_; - - my $data = $options{socket}->recv(ZMQ_DONTWAIT); - if ($options{socket}->has_error) { - return 1; - } - - if (defined($options{frame})) { - $options{frame}->setFrame(\$data); - return 0; - } - - return (0, $data); -} - -sub zmq_read_message { - my (%options) = @_; - - # Process all parts of the message - my $identity = $options{socket}->recv(ZMQ_DONTWAIT); - if ($options{socket}->has_error()) { - return undef if ($options{socket}->last_errno == Errno::EAGAIN); - - $options{logger}->writeLogError("[core] zmq_recvmsg error: $!"); - return undef; - } - - $identity = defined($identity) ? $identity : 'undef'; - if ($identity !~ /^gorgone-/) { - $options{logger}->writeLogError("[core] unknown identity: $identity"); - return undef; - } - - my $data = $options{socket}->recv(ZMQ_DONTWAIT); - if ($options{socket}->has_error()) { - return undef if ($options{socket}->last_errno == Errno::EAGAIN); - - $options{logger}->writeLogError("[core] zmq_recvmsg error: $!"); - return undef; - } - - my $frame = gorgone::class::frame->new(); - $frame->setFrame(\$data); - - return (unpack('H*', $identity), $frame); -} - -sub create_schema { - my (%options) = @_; - - $options{logger}->writeLogInfo("[core] create schema $options{version}"); - my $schema = [ - q{ - PRAGMA encoding = "UTF-8" - }, - q{ - CREATE TABLE `gorgone_information` ( - `key` varchar(1024) DEFAULT NULL, - `value` varchar(1024) DEFAULT NULL - ); - }, - qq{ - INSERT INTO gorgone_information (`key`, `value`) VALUES ('version', '$options{version}'); - }, - q{ - CREATE TABLE `gorgone_identity` ( - `id` INTEGER PRIMARY KEY, - `ctime` int(11) DEFAULT NULL, - `mtime` int(11) DEFAULT NULL, - `identity` varchar(2048) DEFAULT NULL, - `key` varchar(1024) DEFAULT NULL, - `oldkey` varchar(1024) DEFAULT NULL, - `iv` varchar(1024) DEFAULT NULL, - `oldiv` varchar(1024) DEFAULT NULL, - `parent` int(11) DEFAULT '0' - ); - }, - q{ - CREATE INDEX idx_gorgone_identity ON gorgone_identity (identity); - }, - q{ - CREATE INDEX idx_gorgone_parent ON gorgone_identity (parent); - }, - q{ - CREATE TABLE `gorgone_history` ( - `id` INTEGER PRIMARY KEY, - `token` varchar(2048) DEFAULT NULL, - `code` int(11) DEFAULT NULL, - `etime` int(11) DEFAULT NULL, - `ctime` FLOAT DEFAULT NULL, - `instant` int(11) DEFAULT '0', - `data` TEXT DEFAULT NULL - ); - }, - q{ - CREATE INDEX idx_gorgone_history_id ON gorgone_history (id); - }, - q{ - CREATE INDEX idx_gorgone_history_token ON gorgone_history (token); - }, - q{ - CREATE INDEX idx_gorgone_history_etime ON gorgone_history (etime); - }, - q{ - CREATE INDEX idx_gorgone_history_code ON gorgone_history (code); - }, - q{ - CREATE INDEX idx_gorgone_history_ctime ON gorgone_history (ctime); - }, - q{ - CREATE INDEX idx_gorgone_history_instant ON gorgone_history (instant); - }, - q{ - CREATE TABLE `gorgone_synchistory` ( - `id` int(11) NOT NULL, - `ctime` FLOAT DEFAULT NULL, - `last_id` int(11) DEFAULT NULL - ); - }, - q{ - CREATE UNIQUE INDEX idx_gorgone_synchistory_id ON gorgone_synchistory (id); - }, - q{ - CREATE TABLE `gorgone_target_fingerprint` ( - `id` INTEGER PRIMARY KEY, - `target` varchar(2048) DEFAULT NULL, - `fingerprint` varchar(4096) DEFAULT NULL - ); - }, - q{ - CREATE INDEX idx_gorgone_target_fingerprint_target ON gorgone_target_fingerprint (target); - }, - q{ - CREATE TABLE `gorgone_centreon_judge_spare` ( - `cluster_name` varchar(2048) NOT NULL, - `status` int(11) NOT NULL, - `data` TEXT DEFAULT NULL - ); - }, - q{ - CREATE INDEX idx_gorgone_centreon_judge_spare_cluster_name ON gorgone_centreon_judge_spare (cluster_name); - } - ]; - foreach (@$schema) { - my ($status, $sth) = $options{gorgone}->{db_gorgone}->query({ query => $_ }); - if ($status == -1) { - $options{logger}->writeLogError("[core] create schema issue"); - exit(1); - } - } -} - -sub init_database { - my (%options) = @_; - - if ($options{type} =~ /sqlite/i && $options{db} =~ /dbname=(.*)/i) { - my $sdb_path = File::Basename::dirname($1); - File::Path::make_path($sdb_path); - } - $options{gorgone}->{db_gorgone} = gorgone::class::db->new( - type => $options{type}, - db => $options{db}, - host => $options{host}, - port => $options{port}, - user => $options{user}, - password => $options{password}, - force => 2, - logger => $options{logger} - ); - $options{gorgone}->{db_gorgone}->set_inactive_destroy(); - if ($options{gorgone}->{db_gorgone}->connect() == -1) { - $options{logger}->writeLogError("[core] Cannot connect. We quit!!"); - exit(1); - } - - return if (!defined($options{autocreate_schema}) || $options{autocreate_schema} != 1); - - my $db_version = '1.0'; - my ($status, $sth) = $options{gorgone}->{db_gorgone}->query({ query => q{SELECT `value` FROM gorgone_information WHERE `key` = 'version'} }); - if ($status == -1) { - ($status, $sth) = $options{gorgone}->{db_gorgone}->query({ query => q{SELECT 1 FROM gorgone_identity LIMIT 1} }); - if ($status == -1) { - create_schema(gorgone => $options{gorgone}, logger => $options{logger}, version => $options{version}); - return ; - } - } else { - my $row = $sth->fetchrow_arrayref(); - $db_version = $row->[0] if (defined($row)); - } - - $options{logger}->writeLogInfo("[core] update schema $db_version -> $options{version}"); - - if ($db_version eq '1.0') { - my $schema = [ - q{ - PRAGMA encoding = "UTF-8" - }, - q{ - CREATE TABLE `gorgone_information` ( - `key` varchar(1024) DEFAULT NULL, - `value` varchar(1024) DEFAULT NULL - ); - }, - qq{ - INSERT INTO gorgone_information (`key`, `value`) VALUES ('version', '$options{version}'); - }, - q{ - ALTER TABLE `gorgone_identity` ADD COLUMN `mtime` int(11) DEFAULT NULL DEFAULT NULL; - }, - q{ - ALTER TABLE `gorgone_identity` ADD COLUMN `oldkey` varchar(1024) DEFAULT NULL; - }, - q{ - ALTER TABLE `gorgone_identity` ADD COLUMN `oldiv` varchar(1024) DEFAULT NULL; - }, - q{ - ALTER TABLE `gorgone_identity` ADD COLUMN `iv` varchar(1024) DEFAULT NULL; - } - ]; - foreach (@$schema) { - my ($status, $sth) = $options{gorgone}->{db_gorgone}->query({ query => $_ }); - if ($status == -1) { - $options{logger}->writeLogError("[core] update schema issue"); - exit(1); - } - } - $db_version = '22.04.0'; - } - - if ($db_version ne $options{version}) { - $options{gorgone}->{db_gorgone}->query({ query => "UPDATE gorgone_information SET `value` = '$options{version}' WHERE `key` = 'version'" }); - } -} - -1; diff --git a/centreon-gorgone/gorgone/standard/misc.pm b/centreon-gorgone/gorgone/standard/misc.pm deleted file mode 100644 index cbc5342b9d..0000000000 --- a/centreon-gorgone/gorgone/standard/misc.pm +++ /dev/null @@ -1,325 +0,0 @@ -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -package gorgone::standard::misc; - -use strict; -use warnings; -use vars qw($centreon_config); -use POSIX ":sys_wait_h"; -use File::Path; -use File::Basename; -use Try::Tiny; - -sub reload_db_config { - my ($logger, $config_file, $cdb, $csdb) = @_; - my ($cdb_mod, $csdb_mod) = (0, 0); - - unless (my $return = do $config_file) { - $logger->writeLogError("[core] Couldn't parse $config_file: $@") if $@; - $logger->writeLogError("[core] Couldn't do $config_file: $!") unless defined $return; - $logger->writeLogError("[core] Couldn't run $config_file") unless $return; - return -1; - } - - if (defined($cdb)) { - if ($centreon_config->{centreon_db} ne $cdb->db() || - $centreon_config->{db_host} ne $cdb->host() || - $centreon_config->{db_user} ne $cdb->user() || - $centreon_config->{db_passwd} ne $cdb->password() || - $centreon_config->{db_port} ne $cdb->port()) { - $logger->writeLogInfo("[core] Database centreon config has been modified"); - $cdb->db($centreon_config->{centreon_db}); - $cdb->host($centreon_config->{db_host}); - $cdb->user($centreon_config->{db_user}); - $cdb->password($centreon_config->{db_passwd}); - $cdb->port($centreon_config->{db_port}); - $cdb_mod = 1; - } - } - - if (defined($csdb)) { - if ($centreon_config->{centstorage_db} ne $csdb->db() || - $centreon_config->{db_host} ne $csdb->host() || - $centreon_config->{db_user} ne $csdb->user() || - $centreon_config->{db_passwd} ne $csdb->password() || - $centreon_config->{db_port} ne $csdb->port()) { - $logger->writeLogInfo("[core] Database centstorage config has been modified"); - $csdb->db($centreon_config->{centstorage_db}); - $csdb->host($centreon_config->{db_host}); - $csdb->user($centreon_config->{db_user}); - $csdb->password($centreon_config->{db_passwd}); - $csdb->port($centreon_config->{db_port}); - $csdb_mod = 1; - } - } - - return (0, $cdb_mod, $csdb_mod); -} - -sub get_all_options_config { - my ($extra_config, $centreon_db_centreon, $prefix) = @_; - - my $save_force = $centreon_db_centreon->force(); - $centreon_db_centreon->force(0); - - my ($status, $stmt) = $centreon_db_centreon->query({ - query => 'SELECT `key`, `value` FROM options WHERE `key` LIKE ? LIMIT 1', - bind_values => [$prefix . '_%'] - }); - if ($status == -1) { - $centreon_db_centreon->force($save_force); - return ; - } - while ((my $data = $stmt->fetchrow_hashref())) { - if (defined($data->{value}) && length($data->{value}) > 0) { - $data->{key} =~ s/^${prefix}_//; - $extra_config->{$data->{key}} = $data->{value}; - } - } - - $centreon_db_centreon->force($save_force); -} - -sub get_option_config { - my ($extra_config, $centreon_db_centreon, $prefix, $key) = @_; - my $data; - - my $save_force = $centreon_db_centreon->force(); - $centreon_db_centreon->force(0); - - my ($status, $stmt) = $centreon_db_centreon->query({ - query => 'SELECT value FROM options WHERE `key` = ? LIMIT 1', - bind_values => [$prefix . '_' . $key] - }); - if ($status == -1) { - $centreon_db_centreon->force($save_force); - return ; - } - if (($data = $stmt->fetchrow_hashref()) && defined($data->{value})) { - $extra_config->{$key} = $data->{value}; - } - - $centreon_db_centreon->force($save_force); -} - -sub check_debug { - my ($logger, $key, $cdb, $name) = @_; - - my ($status, $sth) = $cdb->query({ - query => 'SELECT `value` FROM options WHERE `key` = ?', - bind_values => [$key] - }); - return -1 if ($status == -1); - my $data = $sth->fetchrow_hashref(); - if (defined($data->{'value'}) && $data->{'value'} == 1) { - if (!$logger->is_debug()) { - $logger->severity("debug"); - $logger->writeLogInfo("[core] Enable Debug in $name"); - } - } else { - if ($logger->is_debug()) { - $logger->set_default_severity(); - $logger->writeLogInfo("[core] Disable Debug in $name"); - } - } - return 0; -} - -sub backtick { - my %arg = ( - command => undef, - arguments => [], - timeout => 30, - wait_exit => 0, - redirect_stderr => 0, - @_, - ); - my @output; - my $pid; - my $return_code; - - my $sig_do; - if ($arg{wait_exit} == 0) { - $sig_do = 'IGNORE'; - $return_code = undef; - } else { - $sig_do = 'DEFAULT'; - } - local $SIG{CHLD} = $sig_do; - $SIG{TTOU} = 'IGNORE'; - $| = 1; - - if (!defined($pid = open( KID, "-|" ))) { - $arg{logger}->writeLogError("[core] Cant fork: $!"); - return (-1000, "cant fork: $!"); - } - - if ($pid) { - try { - local $SIG{ALRM} = sub { die "Timeout by signal ALARM\n"; }; - alarm( $arg{timeout} ); - while () { - chomp; - push @output, $_; - } - - alarm(0); - } catch { - if ($pid != -1) { - kill -9, $pid; - } - - alarm(0); - return (-1000, "Command too long to execute (timeout)...", -1); - }; - if ($arg{wait_exit} == 1) { - # We're waiting the exit code - waitpid($pid, 0); - $return_code = ($? >> 8); - } - close KID; - } else { - # child - # set the child process to be a group leader, so that - # kill -9 will kill it and all its descendents - # We have ignore SIGTTOU to let write background processes - setpgrp(0, 0); - - if ($arg{redirect_stderr} == 1) { - open STDERR, ">&STDOUT"; - } - if (scalar(@{$arg{arguments}}) <= 0) { - exec($arg{command}); - } else { - exec($arg{command}, @{$arg{arguments}}); - } - # Exec is in error. No such command maybe. - exit(127); - } - - return (0, join("\n", @output), $return_code); -} - -sub mymodule_load { - my (%options) = @_; - my $file; - ($file = ($options{module} =~ /\.pm$/ ? $options{module} : $options{module} . '.pm')) =~ s{::}{/}g; - - eval { - local $SIG{__DIE__} = 'IGNORE'; - require $file; - $file =~ s{/}{::}g; - $file =~ s/\.pm$//; - }; - if ($@) { - $options{logger}->writeLogError('[core] ' . $options{error_msg} . ' - ' . $@); - return 1; - } - return wantarray ? (0, $file) : 0; -} - -sub write_file { - my (%options) = @_; - - File::Path::make_path(File::Basename::dirname($options{filename})); - my $fh; - if (!open($fh, '>', $options{filename})) { - $options{logger}->writeLogError("[core] Cannot open file '$options{filename}': $!"); - return 0; - } - print $fh $options{content}; - close $fh; - return 1; -} - -sub trim { - my ($value) = $_[0]; - - # Sometimes there is a null character - $value =~ s/\x00$//; - $value =~ s/^[ \t\n]+//; - $value =~ s/[ \t\n]+$//; - return $value; -} - -sub slurp { - my (%options) = @_; - - my ($fh, $size); - if (!open($fh, '<', $options{file})) { - return (0, "Could not open $options{file}: $!"); - } - my $buffer = do { local $/; <$fh> }; - close $fh; - return (1, 'ok', $buffer); -} - -sub scale { - my (%options) = @_; - - my ($src_quantity, $src_unit) = (undef, 'B'); - if (defined($options{src_unit}) && $options{src_unit} =~ /([kmgtpe])?(b)/i) { - $src_quantity = $1; - $src_unit = $2; - } - my ($dst_quantity, $dst_unit) = ('auto', $src_unit); - if (defined($options{dst_unit}) && $options{dst_unit} =~ /([kmgtpe])?(b)/i) { - $dst_quantity = $1; - $dst_unit = $2; - } - - my $base = 1024; - $options{value} *= 8 if ($dst_unit eq 'b' && $src_unit eq 'B'); - $options{value} /= 8 if ($dst_unit eq 'B' && $src_unit eq 'b'); - $base = 1000 if ($dst_unit eq 'b'); - - my %expo = (k => 1, m => 2, g => 3, t => 4, p => 5, e => 6); - my $src_expo = 0; - $src_expo = $expo{ lc($src_quantity) } if (defined($src_quantity)); - - if (defined($dst_quantity) && $dst_quantity eq 'auto') { - my @auto = ('', 'k', 'm', 'g', 't', 'p', 'e'); - for (; $src_expo < scalar(@auto); $src_expo++) { - last if ($options{value} < $base); - $options{value} = $options{value} / $base; - } - - if (defined($options{format}) && $options{format} ne '') { - $options{value} = sprintf($options{format}, $options{value}); - } - return ($options{value}, uc($auto[$src_expo]) . $dst_unit); - } - - my $dst_expo = 0; - $dst_expo = $expo{ lc($dst_quantity) } if (defined($dst_quantity)); - if ($dst_expo - $src_expo > 0) { - $options{value} = $options{value} / ($base ** ($dst_expo - $src_expo)); - } elsif ($dst_expo - $src_expo < 0) { - $options{value} = $options{value} * ($base ** (($dst_expo - $src_expo) * -1)); - } - - if (defined($options{format}) && $options{format} ne '') { - $options{value} = sprintf($options{format}, $options{value}); - } - return ($options{value}, $options{dst_unit}); -} - -1; diff --git a/centreon-gorgone/gorgoned b/centreon-gorgone/gorgoned deleted file mode 100644 index fdb423af47..0000000000 --- a/centreon-gorgone/gorgoned +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/perl -# -# Copyright 2019 Centreon (http://www.centreon.com/) -# -# Centreon is a full-fledged industry-strength solution that meets -# the needs in IT infrastructure and application monitoring for -# service performance. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use strict; -use warnings; - -use FindBin; -use lib "$FindBin::Bin"; -use gorgone::class::core; - -gorgone::class::core->new()->run(); - -__END__ - -=head1 NAME - -gorgoned - a daemon to handle so many things. - -=head1 SYNOPSIS - -gorgoned [options] - -=head1 OPTIONS - -=over 8 - -=item B<--config> - -Specify the path to the yaml configuration file (default: ''). - -=item B<--help> - -Print a brief help message and exits. - -=item B<--version> - -Print version message and exits. - -=back - -=head1 DESCRIPTION - -B will survive - -=cut diff --git a/centreon-gorgone/inputvars.env b/centreon-gorgone/inputvars.env deleted file mode 100644 index b679f11436..0000000000 --- a/centreon-gorgone/inputvars.env +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# -# Centreon installation variables user specific values. -# Uncomment variables to define values. Values are defaults. - -# INSTALLATION_TYPE="central" -# GORGONE_USER="centreon-gorgone" -# GORGONE_GROUP="centreon-gorgone" -# GORGONE_ETC_DIR="/etc/centreon-gorgone" -# GORGONE_LOG_DIR="/var/log/centreon-gorgone" -# GORGONE_VARLIB_DIR="/var/lib/centreon-gorgone" -# GORGONE_CACHE_DIR="/var/cache/centreon-gorgone" -# CENTREON_USER="centreon" -# CENTREON_HOME="/var/spool/centreon" -# CENTREON_ETC_DIR="/etc/centreon" -# CENTREON_SERVICE="centreon" -# ENGINE_USER="centreon-engine" -# ENGINE_GROUP="centreon-engine" -# BROKER_USER="centreon-broker" -# BROKER_GROUP="centreon-broker" -# BINARY_DIR="/usr/bin" -# PERL_BINARY="/usr/bin/perl" -# SYSTEMD_ETC_DIR="/etc/systemd/system" -# SYSCONFIG_ETC_DIR="/etc/sysconfig" -# LOGROTATED_ETC_DIR="/etc/logrotate.d" -# TMP_DIR="/tmp/centreon-setup" -# LOG_FILE="$BASE_DIR/log/install.log" \ No newline at end of file diff --git a/centreon-gorgone/install.sh b/centreon-gorgone/install.sh deleted file mode 100755 index 149f46d577..0000000000 --- a/centreon-gorgone/install.sh +++ /dev/null @@ -1,495 +0,0 @@ -#!/bin/bash -#---- -## @Synopsis Install Script for Gorgone project -## @Copyright Copyright 2008, Guillaume Watteeux -## @Copyright Copyright 2008-2021, Centreon -## @License GPL : http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt -## Centreon Install Script -#---- -## Centreon is developed with GPL Licence 2.0 -## -## GPL License: http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt -## -## Developed by : Julien Mathis - Romain Le Merlus -## Contributors : Guillaume Watteeux - Maximilien Bersoult -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## For information : infos@centreon.com -# - -#---- -## Usage information for install.sh -## @Sdtout Usage information -#---- -usage() { - local program=$0 - echo -e "Usage: $program" - echo -e " -i\tinstall Gorgone with interactive interface" - echo -e " -u\tupgrade Gorgone specifying the directory of instGorgone.conf file" - echo -e " -s\tinstall/upgrade Gorgone silently" - echo -e " -e\textra variables, 'VAR=value' format (overrides input files)" - exit 1 -} - -## Use TRAPs to call clean_and_exit when user press -## CRTL+C or exec kill -TERM. -trap clean_and_exit SIGINT SIGTERM - -## Valid if you are root -if [ "${FORCE_NO_ROOT:-0}" -ne 0 ]; then - USERID=$(id -u) - if [ "$USERID" != "0" ]; then - echo -e "You must launch this script using a root user" - exit 1 - fi -fi - -## Define where are Gorgone sources -BASE_DIR=$(dirname $0) -BASE_DIR=$( cd $BASE_DIR; pwd ) -if [ -z "${BASE_DIR#/}" ] ; then - echo -e "You cannot select the filesystem root folder" - exit 1 -fi -INSTALL_DIR="$BASE_DIR/install" - -_tmp_install_opts="0" -silent_install="0" -upgrade="0" - -## Get options -while getopts "isu:e:h" Options -do - case ${Options} in - i ) silent_install="0" - _tmp_install_opts="1" - ;; - s ) silent_install="1" - _tmp_install_opts="1" - ;; - u ) silent_install="0" - UPGRADE_FILE="${OPTARG%/}" - upgrade="1" - _tmp_install_opts="1" - ;; - e ) env_opts+=("$OPTARG") - ;; - \?|h) usage ; exit 0 ;; - * ) usage ; exit 1 ;; - esac -done -shift $((OPTIND -1)) - -if [ "$_tmp_install_opts" -eq 0 ] ; then - usage - exit 1 -fi - -INSTALLATION_MODE="install" -if [ ! -z "$upgrade" ] && [ "$upgrade" -eq 1 ]; then - INSTALLATION_MODE="upgrade" -fi - -## Load default input variables -source $INSTALL_DIR/inputvars.default.env -## Load all functions used in this script -source $INSTALL_DIR/functions - -## Define a default log file -if [ ! -z $LOG_FILE ] ; then - LOG_FILE="$BASE_DIR/log/install.log" -fi -LOG_DIR=$(dirname $LOG_FILE) -[ ! -d "$LOG_DIR" ] && mkdir -p "$LOG_DIR" - -## Init LOG_FILE -if [ -e "$LOG_FILE" ] ; then - mv "$LOG_FILE" "$LOG_FILE.`date +%Y%m%d-%H%M%S`" -fi -${CAT} << __EOL__ > "$LOG_FILE" -__EOL__ - -# Checking installation script requirements -BINARIES="rm cp mv chmod chown echo more mkdir find grep cat sed tr" -binary_fail="0" -# For the moment, I check if all binary exists in PATH. -# After, I must look a solution to use complet path by binary -for binary in $BINARIES; do - if [ ! -e ${binary} ] ; then - pathfind_ret "$binary" "PATH_BIN" - if [ "$?" -ne 0 ] ; then - echo_error "${binary}" "FAILED" - binary_fail=1 - fi - fi -done - -## Script stop if one binary is not found -if [ "$binary_fail" -eq 1 ] ; then - echo_info "Please check failed binary and retry" - exit 1 -else - echo_success "Script requirements" "OK" -fi - -## Search distribution and version -if [ -z "$DISTRIB" ] || [ -z "$DISTRIB_VERSION" ] ; then - find_os -fi -echo_info "Found distribution" "$DISTRIB $DISTRIB_VERSION" - -## Load specific variables based on distribution -if [ -f $INSTALL_DIR/inputvars.$DISTRIB.env ]; then - echo_info "Loading distribution specific input variables" "install/inputvars.$DISTRIB.env" - source $INSTALL_DIR/inputvars.$DISTRIB.env -fi - -## Load specific variables based on version -if [ -f $INSTALL_DIR/inputvars.$DISTRIB.$DISTRIB_VERSION.env ]; then - echo_info "Loading version specific input variables" "install/inputvars.$DISTRIB.$DISTRIB_VERSION.env" - source $INSTALL_DIR/inputvars.$DISTRIB.$DISTRIB_VERSION.env -fi - -## Load specific variables defined by user -if [ -f $INSTALL_DIR/../inputvars.env ]; then - echo_info "Loading user specific input variables" "inputvars.env" - source $INSTALL_DIR/../inputvars.env -fi - -## Load previous installation input variables if upgrade -if [ "$upgrade" -eq 1 ] ; then - test_file "$UPGRADE_FILE" "Gorgone upgrade file" - if [ "$?" -eq 0 ] ; then - echo_info "Loading previous installation input variables" "$UPGRADE_FILE" - source $UPGRADE_FILE - else - echo_error "Missing previous installation input variables" "FAILED" - echo_info "Either specify it in command line or using UPGRADE_FILE input variable" - exit 1 - fi -fi - -## Load variables provided in command line -for env_opt in "${env_opts[@]}"; do - if [[ "${env_opt}" =~ .+=.+ ]] ; then - variable=$(echo $env_opt | cut -f1 -d "=") - value=$(echo $env_opt | cut -f2 -d "=") - if [ ! -z "$variable" ] && [ ! -z "$value" ] ; then - echo_info "Loading command line input variables" "${variable}=${value}" - eval ${variable}=${value} - fi - fi -done - -## Check installation mode -if [ -z "$INSTALLATION_TYPE" ] ; then - echo_error "Installation mode" "NOT DEFINED" - exit 1 -fi -if [[ ! "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - echo_error "Installation mode" "$INSTALLATION_TYPE" - exit 1 -fi -echo_info "Installation type" "$INSTALLATION_TYPE" -echo_info "Installation mode" "$INSTALLATION_MODE" - -## Check space of tmp dir -check_tmp_disk_space -if [ "$?" -eq 1 ] ; then - if [ "$silent_install" -eq 1 ] ; then - purge_centreon_tmp_dir "silent" - else - purge_centreon_tmp_dir - fi -fi - -## Installation is interactive -if [ "$silent_install" -ne 1 ] ; then - echo -e "\n" - echo_info "Welcome to Centreon installation script!" - yes_no_default "Should we start?" "$yes" - if [ "$?" -ne 0 ] ; then - echo_info "Exiting" - exit 1 - fi -fi - -# Start installation - -ERROR_MESSAGE="" - -# Centreon installation requirements -echo_title "Centreon installation requirements" - -if [[ "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - # System - test_dir_from_var "LOGROTATED_ETC_DIR" "Logrotate directory" - test_dir_from_var "SYSTEMD_ETC_DIR" "SystemD directory" - test_dir_from_var "SYSCONFIG_ETC_DIR" "Sysconfig directory" - test_dir_from_var "BINARY_DIR" "System binary directory" - - ## Perl information - find_perl_info - test_file_from_var "PERL_BINARY" "Perl binary" - test_dir_from_var "PERL_LIB_DIR" "Perl libraries directory" -fi - -if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "Installation requirements" "FAILED" - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - exit 1 -fi - -echo_success "Installation requirements" "OK" - -## Gorgone information -echo_title "Gorgone information" - -if [[ "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - test_var_and_show "GORGONE_USER" "Gorgone user" - test_var_and_show "GORGONE_GROUP" "Gorgone group" - test_var_and_show "GORGONE_ETC_DIR" "Gorgone configuration directory" - test_var_and_show "GORGONE_LOG_DIR" "Gorgone log directory" - test_var_and_show "GORGONE_VARLIB_DIR" "Gorgone variable library directory" - test_var_and_show "GORGONE_CACHE_DIR" "Gorgone cache directory" - test_var_and_show "CENTREON_USER" "Centreon user" - test_var_and_show "CENTREON_HOME" "Centreon home directory" - test_var_and_show "CENTREON_ETC_DIR" "Centreon configuration directory" - test_var_and_show "CENTREON_SERVICE" "Centreon service" - test_var_and_show "ENGINE_USER" "Engine user" - test_var_and_show "ENGINE_GROUP" "Engine group" - test_var_and_show "BROKER_USER" "Broker user" - test_var_and_show "BROKER_GROUP" "Broker group" -fi - -if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - exit 1 -fi - -if [ "$silent_install" -ne 1 ] ; then - yes_no_default "Everything looks good, proceed to installation?" - if [ "$?" -ne 0 ] ; then - purge_centreon_tmp_dir "silent" - exit 1 - fi -fi - -# Start installation - -## Build files -echo_title "Build files" -echo_line "Copying files to '$TMP_DIR'" - -if [ -d $TMP_DIR ] ; then - mv $TMP_DIR $TMP_DIR.`date +%Y%m%d-%k%m%S` -fi - -create_dir "$TMP_DIR/source" - -if [[ "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - { - copy_dir "$BASE_DIR/config" "$TMP_DIR/source/" && - copy_dir "$BASE_DIR/gorgone" "$TMP_DIR/source/" && - copy_dir "$BASE_DIR/install" "$TMP_DIR/source/" && - copy_file "$BASE_DIR/gorgoned" "$TMP_DIR/source/" - } || { - echo_error_on_line "FAILED" - if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - fi - purge_centreon_tmp_dir "silent" - exit 1 - } -fi -echo_success_on_line "OK" - -echo_line "Replacing macros" -eval "echo \"$(cat "$TMP_DIR/source/install/src/instGorgone.conf")\"" > $TMP_DIR/source/install/src/instGorgone.conf -if [[ "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - { - replace_macro "install/src" - } || { - echo_error_on_line "FAILED" - if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - fi - purge_centreon_tmp_dir "silent" - exit 1 - } -fi -echo_success_on_line "OK" - -test_user "$GORGONE_USER" -if [ $? -ne 0 ]; then - { - ### Create user and group - create_dir "$GORGONE_VARLIB_DIR" && - create_group "$GORGONE_GROUP" && - create_user "$GORGONE_USER" "$GORGONE_GROUP" "$GORGONE_VARLIB_DIR" && - set_ownership "$GORGONE_VARLIB_DIR" "$GORGONE_USER" "$GORGONE_GROUP" && - set_permissions "$GORGONE_VARLIB_DIR" "755" - } || { - if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - fi - purge_centreon_tmp_dir "silent" - exit 1 - } -fi - -echo_line "Building installation tree" -BUILD_DIR="$TMP_DIR/build" -create_dir "$BUILD_DIR" - -if [[ "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - { - ### Configuration diretories and base file - create_dir "$BUILD_DIR/$GORGONE_ETC_DIR" "$GORGONE_USER" "$GORGONE_GROUP" "755" && - create_dir "$BUILD_DIR/$GORGONE_ETC_DIR/config.d" "$GORGONE_USER" "$GORGONE_GROUP" "775" && - create_dir "$BUILD_DIR/$GORGONE_ETC_DIR/config.d/cron.d" "$GORGONE_USER" "$GORGONE_GROUP" "775" && - copy_file "$TMP_DIR/source/install/src/config.yaml" "$BUILD_DIR/$GORGONE_ETC_DIR/config.yaml" \ - "$GORGONE_USER" "$GORGONE_GROUP" && - - ### Install save file - copy_file "$TMP_DIR/source/install/src/instGorgone.conf" \ - "$BUILD_DIR/$GORGONE_ETC_DIR/instGorgone.conf" \ - "$GORGONE_USER" "$GORGONE_GROUP" "644" && - - ### Log directory - create_dir "$BUILD_DIR/$GORGONE_LOG_DIR" "$GORGONE_USER" "$GORGONE_GROUP" "755" && - - ### Cache directories - create_dir "$BUILD_DIR/$GORGONE_CACHE_DIR" "$GORGONE_USER" "$GORGONE_GROUP" "755" && - create_dir "$BUILD_DIR/$GORGONE_CACHE_DIR/autodiscovery" "$GORGONE_USER" "$GORGONE_GROUP" "755" - } || { - echo_error_on_line "FAILED" - if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - fi - purge_centreon_tmp_dir "silent" - exit 1 - } -fi -echo_success_on_line "OK" - -## Install files -echo_title "Install builded files" -echo_line "Copying files from '$TMP_DIR' to final directory" -copy_dir "$BUILD_DIR/*" "/" -if [ "$?" -ne 0 ] ; then - echo_error_on_line "FAILED" - if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - fi - purge_centreon_tmp_dir "silent" - exit 1 -fi -echo_success_on_line "OK" - -## Install remaining files -echo_title "Install remaining files" - -if [[ "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - ### Configurations - copy_file_no_replace "$TMP_DIR/source/install/src/centreon.yaml" \ - "$GORGONE_ETC_DIR/config.d/30-centreon.yaml" \ - "Centreon configuration" \ - "$GORGONE_USER" "$GORGONE_GROUP" "644" - copy_file_no_replace "$TMP_DIR/source/install/src/centreon-api.yaml" \ - "$GORGONE_ETC_DIR/config.d/31-centreon-api.yaml" \ - "Centreon API configuration" \ - "$GORGONE_USER" "$GORGONE_GROUP" "644" - - ### Perl libraries - copy_dir "$TMP_DIR/source/gorgone" "$PERL_LIB_DIR/gorgone" - - ### Gorgoned binary - copy_file "$TMP_DIR/source/gorgoned" "$BINARY_DIR" - - ### Systemd files - restart_gorgoned="0" - copy_file "$TMP_DIR/source/install/src/gorgoned.systemd" \ - "$SYSTEMD_ETC_DIR/gorgoned.service" && restart_gorgoned="1" - copy_file_no_replace "$TMP_DIR/source/install/src/gorgoned.sysconfig" "$SYSCONFIG_ETC_DIR/gorgoned" \ - "Sysconfig Gorgoned configuration" && restart_gorgoned="1" - - ### Logrotate configuration - copy_file_no_replace "$TMP_DIR/source/install/src/gorgoned.logrotate" "$LOGROTATED_ETC_DIR/gorgoned" \ - "Logrotate Gorgoned configuration" -fi - -if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - ERROR_MESSAGE="" -fi - -## Update groups memberships -echo_title "Update groups memberships" -if [[ "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - add_user_to_group "$GORGONE_USER" "$BROKER_GROUP" - add_user_to_group "$GORGONE_USER" "$ENGINE_GROUP" - add_user_to_group "$ENGINE_USER" "$GORGONE_GROUP" - add_user_to_group "$BROKER_USER" "$GORGONE_GROUP" -fi - -if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - ERROR_MESSAGE="" -fi - -## Retrieve Centreon SSH key -if [ ! -d "$GORGONE_VARLIB_DIR/.ssh" ] && [ -d "$CENTREON_HOME/.ssh" ] ; then - echo_title "Retrieve Centreon SSH key" - copy_file "$CENTREON_HOME/.ssh/*" "$GORGONE_VARLIB_DIR/.ssh" "$GORGONE_USER" "$GORGONE_GROUP" && - set_permissions "$GORGONE_VARLIB_DIR/.ssh/id_rsa" "600" -fi - -## Configure and restart services -echo_title "Configure and restart services" -if [[ "${INSTALLATION_TYPE}" =~ ^central|poller$ ]] ; then - ### Gorgoned - enable_service "gorgoned" - - if [ "$restart_gorgoned" -eq 1 ] ; then - reload_daemon - restart_service "gorgoned" - fi -fi - -if [ ! -z "$ERROR_MESSAGE" ] ; then - echo_error "\nErrors:" - echo_error "$ERROR_MESSAGE" - ERROR_MESSAGE="" -fi - -## Purge working directories -purge_centreon_tmp_dir "silent" - -# End -echo_title "You're done!" -echo_info "" -echo_info "Take a look at the documentation" -echo_info "https://docs.centreon.com/current." -echo_info "Thanks for using Gorgone!" -echo_info "Follow us on https://github.com/centreon/centreon-gorgone!" - -exit 0 diff --git a/centreon-gorgone/install/functions b/centreon-gorgone/install/functions deleted file mode 100755 index 97e5495f60..0000000000 --- a/centreon-gorgone/install/functions +++ /dev/null @@ -1,1122 +0,0 @@ -#!/bin/bash -#---- -## @Synopsis This file contains functions to be used by Gorgone install script -## @Copyright Copyright 2008, Guillaume Watteeux -## @Copyright Copyright 2008-2021, Centreon -## @Licence GPLv2 -## This file contains functions to be used by Centreon install script -#---- -## Centreon is developed with GPL Licence 2.0 -## -## GPL License: http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt -## -## Developed by : Julien Mathis - Romain Le Merlus -## Contributors : Guillaume Watteeux - Maximilien Bersoult -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## For information : infos@centreon.com - -## VARS -yes="y" -no="n" - -## COLOR FUNCTIONS -RES_COL="70" -MOVE_TO_COL="\\033[${RES_COL}G" -SETCOLOR_INFO="\\033[1;38m" -SETCOLOR_SUCCESS="\\033[1;32m" -SETCOLOR_ERROR="\\033[1;31m" -SETCOLOR_WARNING="\\033[1;33m" -SETCOLOR_NORMAL="\\033[0;39m" - -#---- -## echo_title -## Print string in a title way. Also log in log file. -## @param string to display -## @stdout titled string -#---- -echo_title() { - [ "$silent_install" -eq 0 ] && echo -e "\n" - [ "$silent_install" -eq 0 ] && echo -e "$1" - [ "$silent_install" -eq 0 ] && printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - - log "INFO" "$1" -} - -#---- -## echo_line -## Print message to screen and keep position, and in log file. -## @param message -## @stdout message -#---- -echo_line() { - [ "$silent_install" -eq 0 ] && echo -en "${1}" - log "INFO" "$1" -} - -#---- -## echo_success_on_line -## Print message to screen on right-end side, and in log file. -## @param message -## @stdout message -#---- -echo_success_on_line() { - [ "$silent_install" -eq 0 ] && echo -e "${MOVE_TO_COL}${SETCOLOR_SUCCESS}${1}${SETCOLOR_NORMAL}" - log "SUCCESS" "$1" -} - -#---- -## echo_succeecho_error_on_liness_on_line -## Print message to screen on right-end side, and in log file. -## @param message -## @stdout message -#---- -echo_error_on_line() { - [ "$silent_install" -eq 0 ] && echo -e "${MOVE_TO_COL}${SETCOLOR_ERROR}${1}${SETCOLOR_NORMAL}" - log "ERROR" "$1" -} - -#---- -## echo_info -## Print info message to screen and in log file. -## @param message -## @param type info (ex: INFO, username...) -## @stdout info message -#---- -echo_info() { - [ "$silent_install" -eq 0 ] && echo -e "${1}${MOVE_TO_COL}${SETCOLOR_INFO}${2}${SETCOLOR_NORMAL}" - log "INFO" "$1 : $2" -} - -#---- -## echo_success -## Print success message to screen and in log file. -## @param message -## @param word to specify success (ex: OK) -## @stdout success message -#---- -echo_success() { - [ "$silent_install" -eq 0 ] && echo -e "${1}${MOVE_TO_COL}${SETCOLOR_SUCCESS}${2}${SETCOLOR_NORMAL}" - log "SUCCESSS" "$1 : $2" -} - -#---- -## echo_warning -## Print warning message to screen and in log file. -## @param message -## @param word to specify warning (ex: warn) -## @stdout warning message -#---- -echo_warning() { - [ "$silent_install" -eq 0 ] && echo -e "${1}${MOVE_TO_COL}${SETCOLOR_WARNING}${2}${SETCOLOR_NORMAL}" - log "WARNING" "$1 : $2" -} - -#---- -## echo_error -## Print failure message to screen and in log file. -## @param message -## @param word to specify failure (ex: fail) -## @stdout failure message -#---- -echo_error() { - [ "$silent_install" -eq 0 ] && echo -e "${1}${MOVE_TO_COL}${SETCOLOR_ERROR}${2}${SETCOLOR_NORMAL}" - log "ERROR" "$1 : $2" -} - -#---- -## log -## Add message in log file -## @param type of message level (debug, info, ...) -## @param message -## @globals LOG_FILE -#---- -log() { - local type="$1" - shift - local message="$@" - echo -e "["`date +"%m-%d-%y %T"`"] [$type] $message" >> $LOG_FILE -} - -#---- -## trim -## Trim whitespaces and tabulations -## @param string to trim -## @return string -#---- -trim() { - echo "$1" | sed 's/^[ \t]*\(.*\)[ \t]*$/\1/' -} - -#---- -## yes_no_default -## Create a question with yes/no possiblity. Uses "no" response by default. -## @param message to print -## @param default response (default to no) -## @return 0 yes -## @return 1 no -#---- -yes_no_default() { - local message=$1 - local default=${2:-$no} - local res="not_define" - - while [ "$res" != "$yes" ] && [ "$res" != "$no" ] && [ ! -z "$res" ] ; do - echo -en "\n$message" - [ "$default" = "$yes" ] && echo " [Y/n]" - [ "$default" = "$no" ] && echo " [y/N]" - echo -en "> " - read res - [ -z "$res" ] && res="$default" - done - if [ "$res" = "$yes" ] ; then - return 0 - else - return 1 - fi -} - -#---- -## add_error_message -## Add an error message in global variable ERROR_MESSAGE. -## See this as an exceptions management. Used by test_* functions. -## @param message -## @globals ERROR_MESSAGE -#---- -add_error_message() { - local append="" - local message="$1" - - if [ ! -z "$ERROR_MESSAGE" ] ; then - append="\n" - fi - ERROR_MESSAGE="${ERROR_MESSAGE}$append $message" -} - -#---- -## test_var -## Test a global variable valueexists. -## @param global variable (as string) -## @param message to display as part of the returned error -## @return 0 show the message and value -## @return 1 add an error using add_error_message -#---- -test_var() { - local var="$1" - local message="$2" - local value=$(eval echo \$$var) - - if [ -z "$value" ] ; then - add_error_message "Missing value for variable '$var' ($message)" - return 1 - fi - - return 0 -} - -#---- -## test_var_and_show -## Test a global variable value exists and show this value in a echo_info format. -## @param global variable (as string) -## @param message to display as part of the echo_info or returned error -## @return 0 show the message and value -## @return 1 add an error using add_error_message -#---- -test_var_and_show() { - local var="$1" - local message="$2" - local value=$(eval echo \$$var) - - if [ -z "$value" ] ; then - add_error_message "Missing value for variable '$var' ($message)" - return 1 - fi - - echo_info "$message ($var)" "$value" - - return 0 -} - -#---- -## test_file -## Test a file existence. -## @param file absolute path -## @param message to display as part of the returned error -## @return 0 file found -## @return 1 add an error using add_error_message -#---- -test_file() { - local file="$1" - local message="$2" - - if [ -z "$file" ] ; then - add_error_message "Missing value for test_file function" - return 1 - fi - if [ ! -f $file ] ; then - add_error_message "Cannot find file '$file' ($message)" - return 1 - fi - - return 0 -} - -#---- -## test_file_from_var -## Test a file existence from a global variable. -## @param global variable (as string) -## @param message to display as part of the returned error -## @return 0 file found -## @return 1 add an error using add_error_message -#---- -test_file_from_var() { - local var="$1" - local message="$2" - local file=$(eval echo \$$var) - - if [ -z "$file" ] ; then - add_error_message "Missing value for variable '$var' ($message)" - return 1 - fi - if [ ! -f $file ] ; then - add_error_message "Cannot find file '$file' from variable '$var' ($message)" - return 1 - fi - - return 0 -} - -#---- -## test_dir -## Test a directory existence. -## @param directory absolute path -## @param message to display as part of the returned error -## @return 0 directory found -## @return 1 add an error using add_error_message -#---- -test_dir() { - local dir="$1" - local message="$2" - - if [ -z "$dir" ] ; then - add_error_message "Missing value for test_dir function" - return 1 - fi - if [ ! -d "$dir" ] ; then - add_error_message "Cannot find directory '$dir' ($message)" - return 1 - fi - - return 0 -} - -#---- -## test_dir_from_var -## Test a directory existence from a global variable. -## @param global variable (as string) -## @param message to display as part of the returned error -## @return 0 directory found -## @return 1 add an error using add_error_message -#---- -test_dir_from_var() { - local var="$1" - local message="$2" - local dir=$(eval echo \$$var) - - if [ -z "$dir" ] ; then - add_error_message "Missing value for variable '$var' ($message)" - return 1 - fi - if [ ! -d "$dir" ] ; then - add_error_message "Cannot find directory '$dir' from variable '$var' ($message)" - return 1 - fi - - return 0 -} - -#---- -## test_user_from_var -## Test a user existence from a global variable. -## @param global variable (as string) -## @param message to display as part of the returned error -## @return 0 user found -## @return 1 add an error using add_error_message -#---- -test_user_from_var() { - local var="$1" - local message="$2" - local user=$(eval echo \$$var) - - if [ -z "$user" ] ; then - add_error_message "Missing value for variable '$var' ($message)" - return 1 - fi - grep "^$user:" /etc/passwd &>/dev/null - if [ $? -ne 0 ] ; then - add_error_message "Cannot find user '$user' from variable '$var' ($message)" - return 1 - fi - - return 0 -} - -#---- -## test_group_from_var -## Test a group existence from a global variable. -## @param global variable (as string) -## @param message to display as part of the returned error -## @return 0 group found -## @return 1 add an error using add_error_message -#---- -test_group_from_var() { - local var="$1" - local message="$2" - local group=$(eval echo \$$var) - - if [ -z "$group" ] ; then - add_error_message "Missing value for variable '$var' ($message)" - return 1 - fi - grep "^$group:" /etc/group &>/dev/null - if [ $? -ne 0 ] ; then - add_error_message "Cannot find group '$group' from variable '$var' ($message)" - return 1 - fi - - return 0 -} - -#---- -## create_dir -## Create a directory if it does not exist. -## @param directory absolute path -## @param user to set ownership (optional) -## @param group to set ownership (optional) -## @param mode to set permisions (optional) -## @return 0 directory created -## @return 1 error message using echo_error -#---- -create_dir() { - local dirname="$1" - local user="$2" - local group="$3" - local mode="$4" - - if [ ! -d "$dirname" ] ; then - result="$(mkdir -p "$dirname" > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Could not create directory '$dirname': $result" - return 1 - fi - fi - if [ ! -z "$user" ] && [ ! -z "$group" ] ; then - set_ownership "$dirname" "$user" "$group" - [ $? -ne 0 ] && return 1 - fi - if [ ! -z "$mode" ] ; then - set_permissions "$dirname" "$mode" - [ $? -ne 0 ] && return 1 - fi - - return 0 -} - -#---- -## delete_file -## Delete a file or multiple files if wildcard specified. -## @param file absolute path -## @return 0 file deleted -## @return 1 error message using echo_error -#---- -delete_file() { - local file="$1" - - if [ ! -f "$file" ] && [[ ! "$file" =~ \*$ ]] ; then - echo_error "Not a file '$file'" "FAILED" - return 1 - else - result="$(rm -f $file 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - echo_error "Could not delete file '$file'" "FAILED" - echo_error "$result" - return 1 - fi - fi - - return 0 -} - -#---- -## copy_file -## Copy a file or multiple files (using wildcard) to a defined location. -## Simplistic but handles the needed cases. -## @param source, unique file absolute path or directory absolute path plus wildcard -## @param destination, can be unique file absolute path or directory absolute path -## @param user to set ownership (optional) -## @param group to set ownership (optional) -## @param mode to set permisions (optional) -## @return 0 copy done successfully -## @return 1 error message using echo_error -#---- -copy_file() { - local file="$1" - local dest="$2" - local user="$3" - local group="$4" - local mode="$5" - - if [ ! -f "$file" ] && [[ ! "$file" =~ \*$ ]] ; then - add_error_message "File '$file' does not exist" - return 1 - else - result="$(cp -f $file $dest 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Copy of '$file' to '$dest' failed: $result" - return 1 - fi - if [ ! -z "$user" ] && [ ! -z "$group" ] ; then - set_ownership "$dest" "$user" "$group" - [ $? -ne 0 ] && return 1 - fi - if [ ! -z "$mode" ] ; then - set_permissions "$dest" "$mode" - [ $? -ne 0 ] && return 1 - fi - fi - - return 0 -} - -#---- -## copy_file_no_replace -## Copy a file to a defined location. -## Simplistic but handles the needed cases. -## @param source, unique file absolute path -## @param destination, unique file absolute path -## @return 0 copy done successfully, returning echo_success message -## @return 1 error message using echo_error -## @return 2 message copied as .new, returning echo_info message -#---- -copy_file_no_replace() { - local file="$1" - local dest="$2" - local message="$3" - local exist=0 - - if [ ! -f "$file" ] ; then - add_error_message "File '$file' does not exist" - return 1 - elif [ -f "$dest" ] ; then - dest=${dest}".new" - exist=1 - fi - result="$(cp -f $file $dest 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Copy of '$file' to '$dest' failed: $result" - return 1 - elif [ $exist == "1" ] ; then - echo_info "$message" "$dest" - return 2 - else - echo_success "$message" "OK" - return 0 - fi -} - -#---- -## copy_dir -## Copy a directory or a directory content (using wildcard) to a defined location. -## Simplistic but handles the needed cases. -## @param source, unique directory absolute path or directory absolute path plus wildcard -## @param destination, directory absolute path -## @param user to set ownership (optional) -## @param group to set ownership (optional) -## @param mode to set permisions (optional) -## @return 0 copy done successfully -## @return 1 error message using echo_error -#---- -copy_dir() { - local dir="$1" - local dest="$2" - local user="$3" - local group="$4" - local mode="$5" - - if [ ! -d "$dir" ] && [[ ! "$dir" =~ \*$ ]] ; then - add_error_message "Directory '$dir' does not exist" - return 1 - else - result="$(cp -rpf $dir $dest 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Copy of '$dir' to '$dest' failed: $result" - return 1 - fi - if [ ! -z "$user" ] && [ ! -z "$group" ] ; then - set_ownership "$dest" "$user" "$group" - [ $? -ne 0 ] && return 1 - fi - if [ ! -z "$mode" ] ; then - set_permissions "$dest" "$mode" - [ $? -ne 0 ] && return 1 - fi - fi - - return 0 -} - -#---- -## create_symlink -## Create a symbolic link for a file. -## @param file absolute path -## @param link absolute path -## @param user to set ownership (optional) -## @param group to set ownership (optional) -## @param mode to set permisions (optional) -## @return 0 directory created -## @return 1 error message using echo_error -#---- -create_symlink() { - local file="$1" - local link="$2" - local user="$3" - local group="$4" - local mode="$5" - - if [ -f "$file" ] && [ ! -L "$link" ]; then - result="$(ln -s "$file" "$link" 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Could not create symbolic link '$file' to '$link': $result" - return 1 - fi - if [ ! -z "$user" ] && [ ! -z "$group" ] ; then - set_ownership "$link" "$user" "$group" - [ $? -ne 0 ] && return 1 - fi - if [ ! -z "$mode" ] ; then - set_permissions "$link" "$mode" - [ $? -ne 0 ] && return 1 - fi - fi - - return 0 -} - -#---- -## set_ownership -## Set the ownership on a unique file or on a directory. -## Simplistic but handles the needed cases. -## @param file or directory -## @param user -## @param group -## @return 0 ownership set successfully -## @return 1 error message using echo_error -#---- -set_ownership() { - local dir_file="$1" - local user="$2" - local group="$3" - - if [ -z "$dir_file" ] ; then - echo_info "File or directory not defined" - return 1 - fi - if [ -f "$dir_file" ] || [[ "$dir_file" =~ \*$ ]] ; then - result="$(chown -h $user:$group $dir_file 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Set ownership '$user:$group' on file '$dir_file' failed: $result" - return 1 - fi - elif [ -d "$dir_file" ] ; then - result="$(chown -R $user:$group $dir_file 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Set ownership '$user:$group' on directory '$dir_file' failed: $result" - return 1 - fi - fi - - return 0 -} - -#---- -## set_permissions -## Set the permissions on a unique file, on a directory and its content (recursively) -## or on files in directories (recursively) if using wildcard. -## Simplistic but handles the needed cases. -## @param file or directory -## @param mode -## @return 0 permissions set successfully -## @return 1 error message using echo_error -#---- -set_permissions() { - local dir_file="$1" - local mode="$2" - - if [ -z "$dir_file" ] ; then - add_error_message "File or directory not defined" - return 1 - fi - if [ -f "$dir_file" ] ; then - result="$(chmod $mode $dir_file 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Set permissions '$mode' on file '$dir_file' failed: $result" - return 1 - fi - elif [ -d "$dir_file" ] ; then - result="$(find $dir_file -type d -print | xargs -I '{}' chmod $mode '{}' 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Set permissions '$mode' on directories in '$dir_file' failed: $result" - return 1 - fi - elif [[ "$dir_file" =~ \*$ ]] ; then - result="$(find $dir_file -type f -print | xargs -I '{}' chmod $mode '{}' 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - add_error_message "Set permissions '$mode' on files in '$dir_file' failed: $result" - return 1 - fi - else - add_error_message "Not a file or a directory '$dir_file'" - return 1 - fi - - return 0 -} - -#---- -## create_user -## Create a user if does not exist (checked using test_user). -## @param username -## @param groupname -## @param user's home -## @return 0 user created successfully -## @return 1 creation failed -#---- -create_user() { - local username="$1" - local groupname="$2" - local home="$3" - - test_user $username - if [ $? -ne 0 ]; then - echo_line "Create user '$username'" - result="$(useradd -r -s "/bin/sh" -d "$home" -g "$groupname" "$username" 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - echo_error_on_line "FAILED" - add_error_message "Create user '$username' failed: $result" - return 1 - fi - echo_success_on_line "OK" - fi - - return 0 -} - -#---- -## create_group -## Create a group if does not exist (checked using test_group). -## @param groupname -## @return 0 group created successfully -## @return 1 creation failed -#---- -create_group() { - local groupname="$1" - - test_group $groupname - if [ $? -ne 0 ]; then - echo_line "Create group '$groupname'" - result="$(groupadd -r "$groupname" 2>&1 > /dev/null)" - if [ $? -ne 0 ] ; then - echo_error_on_line "FAILED" - add_error_message "Create group '$groupname' failed: $result" - return 1 - fi - echo_success_on_line "OK" - fi - - return 0 -} - -#---- -## test_user -## Test a user existence. -## @param user -## @return 0 user exists -## @return 1 user does not exist -#---- -test_user() { - result="$(grep "^$1:" /etc/passwd 2>&1 > /dev/null)" - return $? -} - -#---- -## test_group -## Test a group existence. -## @param user -## @return 0 group exists -## @return 1 group does not exist -#---- -test_group() { - result="$(grep "^$1:" /etc/group 2>&1 > /dev/null)" - return $? -} - -#---- -## add_user_to_group -## Add a user in a group -## @param user -## @param group -## @return 0 add successfull -## @return 1 add failed -#---- -add_user_to_group() { - local user=$1 - local group=$2 - echo_line "Add user '$user' to group '$group'" - if [ -z "$user" -o -z "$group" ]; then - echo_error_on_line "FAILED" - add_error_message "User or group not defined" - return 1 - fi - test_user $user - if [ $? -ne 0 ]; then - echo_error_on_line "FAILED" - add_error_message "Add user '$user' to group '$group' failed: user '$user' does not exist" - return 1 - fi - test_group $group - if [ $? -ne 0 ]; then - echo_error_on_line "FAILED" - add_error_message "Add user '$user' to group '$group' failed: group '$group' does not exist" - return 1 - fi - - result="$(usermod -a -G $group $user 2>&1 > /dev/null)" - local ret=$? - if [ "$ret" -ne 0 ] ; then - echo_error_on_line "FAILED" - add_error_message "Add user '$user' to group '$group' failed: $result" - else - echo_success_on_line "OK" - fi - return $ret -} - -#---- -## find_perl_info -## Find Perl information. -## @return 0 search done -## @globals PERL_LIB_DIR -#---- -find_perl_info() { - if [ -z $PERL_LIB_DIR ] ; then - PERL_LIB_DIR=$(perl -V:installvendorlib | cut -d "'" -f 2) - # for freebsd - if [ "$PERL_LIB_DIR" = "" -o "$PERL_LIB_DIR" = "UNKNOWN" ]; then - PERL_LIB_DIR=$(perl -V:installsitelib | cut -d "'" -f 2) - fi - fi - - PERL_LIB_DIR=${PERL_LIB_DIR%/} - - return 0 -} - -#---- -## enable_service -## Enable a systemd service. -## @return 0 enabling ok -## @return 0 enabling failed -#---- -enable_service() { - local service="$1" - - if [ -x /bin/systemctl ] ; then - echo_line "Enabling service '$service'" - result="$(/bin/systemctl enable $service 2>&1 > /dev/null)" - local ret=$? - if [ "$ret" -ne 0 ] ; then - echo_error_on_line "FAILED" - add_error_message "Enabling service '$service' failed: $result" - else - echo_success_on_line "OK" - fi - return $ret - fi - - return 1 -} - -#---- -## reload_service -## Reload a systemd service. -## @return 0 reloading ok -## @return 0 reloading failed -#---- -reload_service() { - local service="$1" - - if [ -x /bin/systemctl ] ; then - echo_line "Reloading service '$service'" - result="$(/bin/systemctl reload $service 2>&1 > /dev/null)" - local ret=$? - if [ "$ret" -ne 0 ] ; then - echo_error_on_line "FAILED" - add_error_message "Reloading service '$service' failed: $result" - else - echo_success_on_line "OK" - fi - return $ret - fi - - return 1 -} - -#---- -## restart_service -## Restart a systemd service. -## @return 0 restarting ok -## @return 0 restarting failed -#---- -restart_service() { - local service="$1" - - if [ -x /bin/systemctl ] ; then - echo_line "Restarting service '$service'" - result="$(/bin/systemctl restart $service 2>&1 > /dev/null)" - local ret=$? - if [ "$ret" -ne 0 ] ; then - echo_error_on_line "FAILED" - add_error_message "Restarting service '$service' failed: $result" - else - echo_success_on_line "OK" - fi - return $ret - fi - - return 1 -} - -#---- -## reload_daemon -## Reload systemd daemon. -## @return 0 reload ok -## @return 0 reload failed -#---- -reload_daemon() { - if [ -x /bin/systemctl ] ; then - echo_line "Reloading systemctl daemon" - result="$(/bin/systemctl daemon-reload 2>&1 > /dev/null)" - local ret=$? - if [ "$ret" -ne 0 ] ; then - echo_error_on_line "FAILED" - add_error_message "Reloading systemctl daemon failed: $result" - else - echo_success_on_line "OK" - fi - return $ret - fi - - return 1 -} - -#---- -## replace_macro -## Replace @@ macros in all needed files in temporary directory. -## @return 0 replacement done successfully -## @return 1 replacement failed -## @globals TMP_DIR -#---- -replace_macro() { - local srclistcp="$1" - - { - for folder in $srclistcp ; do - result="$(find $TMP_DIR/source/$folder -type f | xargs --delimiter='\n' sed -i \ - -e 's|@GORGONE_USER@|'"$GORGONE_USER"'|gi' \ - -e 's|@GORGONE_LOG_DIR@|'"$GORGONE_LOG_DIR"'|gi' \ - -e 's|@GORGONE_ETC_DIR@|'"$GORGONE_ETC_DIR"'|gi' \ - -e 's|@CENTREON_ETC_DIR@|'"$CENTREON_ETC_DIR"'|gi' \ - -e 's|@CENTREON_SERVICE@|'"$CENTREON_SERVICE"'|gi' \ - -e 's|@SYSCONFIG_ETC_DIR@|'"$SYSCONFIG_ETC_DIR"'|gi' \ - -e 's|@PERL_BINARY@|'"$PERL_BINARY"'|gi' \ - -e 's|@BINARY_DIR@|'"$BINARY_DIR"'|gi' 2>&1 > /dev/null)" - done - } || { - add_error_message "Replacing macros failed: $result" - return 1 - } - - return 0 -} - -#---- -## find_os -## Search OS distribution and version. -## @return 0 search done -## @globals DISTRIB DISTRIB_VERSION -#---- -find_os() { - # From https://unix.stackexchange.com/questions/6345/how-can-i-get-distribution-name-and-version-number-in-a-simple-shell-script - if [ -f /etc/os-release ]; then - # freedesktop.org and systemd - . /etc/os-release - DISTRIB=${ID} - DISTRIB_VERSION=${VERSION_ID} - elif type lsb_release >/dev/null 2>&1; then - # linuxbase.org - DISTRIB=$(lsb_release -si | sed -e 's/\(.*\)/\L\1/') - DISTRIB_VERSION=$(lsb_release -sr) - elif [ -f /etc/lsb-release ]; then - # For some versions of Debian/Ubuntu without lsb_release command - . /etc/lsb-release - DISTRIB=${DISTRIB_ID} - DISTRIB_VERSION=${DISTRIB_RELEASE} - elif [ -f /etc/debian_version ]; then - # Older Debian/Ubuntu/etc. - DISTRIB=debian - DISTRIB_VERSION=$(cat /etc/debian_version | cut -d "." -f 1) - elif [ -f /etc/centos-release ]; then - # CentOS - DISTRIB=centos - DISTRIB_VERSION=$(cat /etc/centos-release | cut -d " " -f 4 | cut -d "." -f 1) - elif [ -f /etc/redhat-release ]; then - # Older Red Hat, CentOS, etc. - DISTRIB=centos - DISTRIB_VERSION=$(cat /etc/redhat-release | cut -d " " -f 4 | cut -d "." -f 1) - else - # Fall back to uname, e.g. "Linux ", also works for BSD, etc. - DISTRIB=$(uname -s) - DISTRIB_VERSION=$(uname -r) - fi - - return 0 -} - -#---- -## clean_and_exit -## Function to clean and exit Centreon install using purge_centreon_tmp_dir functionn, and exit. -#---- -clean_and_exit() { - local trap_sig=${1:-0} - - if [ $trap_sig -eq 0 ] ; then - echo -e "\nTrap interrupt, Centreon'll exit now and clean installation" - yes_no_default "Do you really want to quit Centreon installation?" "$no" - if [ $? -eq 1 ] ; then - echo "Continue..." - return 1 - fi - fi - - purge_centreon_tmp_dir "silent" - - exit 1 -} - -#---- -## check_tmp_disk_space -## Check space left for working directory. -## @return 0 space ok -## @return 1 no Space left -## @globals TMP_DIR -#---- -check_tmp_disk_space() { - local min_space="35584" - local free_space="" - local tmp_dir="" - - tmp_dir=$(dirname $TMP_DIR) - - free_space=$(df -P $tmp_dir | tail -1 | awk '{print $4}') - - if [ "$free_space" -lt "$min_space" ] ; then - echo_error "No space left on temporary directory '$tmp_dir' (<$min_space Ko)" "FAILED" - return 1 - else - return 0 - fi -} - -#---- -## purge_centreon_tmp_dir -## Ask to remove all temporaries working directory. -## @param silent option (silent) -## @return 0 remove done -## @return 1 don't remove (abort by user) -## @globals TMP_DIR -#---- -purge_centreon_tmp_dir() { - local silent="$1" - local not_clean="1" - local rc="0" - while [ $not_clean -ne 0 ] ; do - if [ "$silent" != "silent" ] ; then - yes_no_default "Do you want to remove the Centreon temporary working space to continue installation?" "$yes" - rc=$? - else - rc=0 - fi - if [ $rc -eq 0 ] ; then - local tmp_base_dir=`dirname $TMP_DIR` - local tmp_dir=`basename $TMP_DIR` - find $tmp_base_dir -name "$tmp_dir*" -type d \ - -exec rm -rf {} \; 2>/dev/null - not_clean="0" - else - return 1 - fi - done - return 0 -} - -#---- -## pathfind_ret -## Find in $PATH if binary exist and return dirname. -## @param file to test -## @param global variable to set a result -## @return 0 found -## @return 1 not found -## @Globals PATH -#---- -pathfind_ret() { - local bin=$1 - local var_ref=$2 - local OLDIFS="$IFS" - IFS=: - for p in $PATH; do - if [ -x "$p/$bin" ]; then - IFS="$OLDIFS" - eval $var_ref=$p - return 0 - fi - done - IFS="$OLDIFS" - return 1 -} - -#---- -## check_result -## Check result and print a message using echo_success or echo_error -## @param return code to check -## @param message to print -#---- -check_result() { - local code=$1 - shift - local message=$@ - - if [ $code -eq 0 ] ; then - echo_success "$message" "OK" - else - echo_error "$message" "FAILED" - fi - return 0 -} diff --git a/centreon-gorgone/install/inputvars.centos.env b/centreon-gorgone/install/inputvars.centos.env deleted file mode 100644 index 04bbf24bd6..0000000000 --- a/centreon-gorgone/install/inputvars.centos.env +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -# -# Centreon installation variables specific values for CentOS. -# DO NOT EDIT! Edit inputvars.env file instead! diff --git a/centreon-gorgone/install/inputvars.debian.env b/centreon-gorgone/install/inputvars.debian.env deleted file mode 100644 index f42ab29d10..0000000000 --- a/centreon-gorgone/install/inputvars.debian.env +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -# -# Centreon installation variables specific values for Debian. -# DO NOT EDIT! Edit inputvars.env file instead! - -SYSTEMD_ETC_DIR="/lib/systemd/system" -SYSCONFIG_ETC_DIR="/etc/default" diff --git a/centreon-gorgone/install/inputvars.default.env b/centreon-gorgone/install/inputvars.default.env deleted file mode 100755 index b0c27111c5..0000000000 --- a/centreon-gorgone/install/inputvars.default.env +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# -# Gorgone installation variables default values. -# DO NOT EDIT! Edit inputvars.env file instead! - -INSTALLATION_TYPE="central" -GORGONE_USER="centreon-gorgone" -GORGONE_GROUP="centreon-gorgone" -GORGONE_ETC_DIR="/etc/centreon-gorgone" -GORGONE_LOG_DIR="/var/log/centreon-gorgone" -GORGONE_VARLIB_DIR="/var/lib/centreon-gorgone" -GORGONE_CACHE_DIR="/var/cache/centreon-gorgone" -CENTREON_USER="centreon" -CENTREON_HOME="/var/spool/centreon" -CENTREON_ETC_DIR="/etc/centreon" -CENTREON_SERVICE="centreon" -ENGINE_USER="centreon-engine" -ENGINE_GROUP="centreon-engine" -BROKER_USER="centreon-broker" -BROKER_GROUP="centreon-broker" -BINARY_DIR="/usr/bin" -PERL_BINARY="/usr/bin/perl" -SYSTEMD_ETC_DIR="/etc/systemd/system" -SYSCONFIG_ETC_DIR="/etc/sysconfig" -LOGROTATED_ETC_DIR="/etc/logrotate.d" -TMP_DIR="/tmp/centreon-setup" -LOG_FILE="$BASE_DIR/log/install.log" diff --git a/centreon-gorgone/install/inputvars.opensuse-leap.env b/centreon-gorgone/install/inputvars.opensuse-leap.env deleted file mode 100644 index e8b10d5b58..0000000000 --- a/centreon-gorgone/install/inputvars.opensuse-leap.env +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -# -# Centreon installation variables specific values for OpenSUSE Leap. -# DO NOT EDIT! Edit inputvars.env file instead! - diff --git a/centreon-gorgone/install/inputvars.ubuntu.env b/centreon-gorgone/install/inputvars.ubuntu.env deleted file mode 100644 index 9cd0068550..0000000000 --- a/centreon-gorgone/install/inputvars.ubuntu.env +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -# -# Centreon installation variables specific values for Ubuntu. -# DO NOT EDIT! Edit inputvars.env file instead! - -SYSTEMD_ETC_DIR="/lib/systemd/system" -SYSCONFIG_ETC_DIR="/etc/default" diff --git a/centreon-gorgone/install/src/centreon-api.yaml b/centreon-gorgone/install/src/centreon-api.yaml deleted file mode 100644 index 39b7eb1ab0..0000000000 --- a/centreon-gorgone/install/src/centreon-api.yaml +++ /dev/null @@ -1,9 +0,0 @@ -gorgone: - tpapi: - - name: centreonv2 - base_url: "http://127.0.0.1/centreon/api/latest/" - username: admin - password: Centreon!2021 - - name: clapi - username: admin - password: Centreon!2021 diff --git a/centreon-gorgone/install/src/centreon.yaml b/centreon-gorgone/install/src/centreon.yaml deleted file mode 100644 index 4cb705e38d..0000000000 --- a/centreon-gorgone/install/src/centreon.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: centreon.yaml -description: Configure Centreon Gorgone to work with Centreon Web. -centreon: !include @CENTREON_ETC_DIR@/config.d/*.yaml diff --git a/centreon-gorgone/install/src/config.yaml b/centreon-gorgone/install/src/config.yaml deleted file mode 100644 index 7675ec7b23..0000000000 --- a/centreon-gorgone/install/src/config.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: config.yaml -description: Configuration brought by Centreon Gorgone install. SHOULD NOT BE EDITED! USE CONFIG.D DIRECTORY! -configuration: !include @GORGONE_ETC_DIR@/config.d/*.yaml diff --git a/centreon-gorgone/install/src/gorgoned.logrotate b/centreon-gorgone/install/src/gorgoned.logrotate deleted file mode 100644 index ee2210cc14..0000000000 --- a/centreon-gorgone/install/src/gorgoned.logrotate +++ /dev/null @@ -1,10 +0,0 @@ -@GORGONE_LOG_DIR@/gorgoned.log { - copytruncate - weekly - rotate 52 - compress - delaycompress - notifempty - missingok - su root root -} diff --git a/centreon-gorgone/install/src/gorgoned.sysconfig b/centreon-gorgone/install/src/gorgoned.sysconfig deleted file mode 100644 index b120006635..0000000000 --- a/centreon-gorgone/install/src/gorgoned.sysconfig +++ /dev/null @@ -1,4 +0,0 @@ -# Configuration file for Centreon Gorgone. - -# OPTIONS for the daemon launch -OPTIONS="--config=@GORGONE_ETC_DIR@/config.yaml --logfile=@GORGONE_LOG_DIR@/gorgoned.log --severity=info" diff --git a/centreon-gorgone/install/src/gorgoned.systemd b/centreon-gorgone/install/src/gorgoned.systemd deleted file mode 100644 index 6c228be2bb..0000000000 --- a/centreon-gorgone/install/src/gorgoned.systemd +++ /dev/null @@ -1,33 +0,0 @@ -## -## Copyright 2019-2021 Centreon -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## -## For more information : contact@centreon.com -## - -[Unit] -Description=Centreon Gorgone -PartOf=@CENTREON_SERVICE@.service -After=@CENTREON_SERVICE@.service -ReloadPropagatedFrom=@CENTREON_SERVICE@.service - -[Service] -EnvironmentFile=@SYSCONFIG_ETC_DIR@/gorgoned -ExecStart=@PERL_BINARY@ @BINARY_DIR@/gorgoned $OPTIONS -Type=simple -User=@GORGONE_USER@ - -[Install] -WantedBy=multi-user.target -WantedBy=@CENTREON_SERVICE@.service diff --git a/centreon-gorgone/install/src/instGorgone.conf b/centreon-gorgone/install/src/instGorgone.conf deleted file mode 100644 index 8dea74f7bc..0000000000 --- a/centreon-gorgone/install/src/instGorgone.conf +++ /dev/null @@ -1,22 +0,0 @@ -# Centreon installation variables saved from previous installation. - -INSTALLATION_TYPE=$INSTALLATION_TYPE -GORGONE_USER=$GORGONE_USER -GORGONE_GROUP=$GORGONE_GROUP -GORGONE_ETC_DIR=$GORGONE_ETC_DIR -GORGONE_LOG_DIR=$GORGONE_LOG_DIR -GORGONE_VARLIB_DIR=$GORGONE_VARLIB_DIR -GORGONE_CACHE_DIR=$GORGONE_CACHE_DIR -CENTREON_USER=$CENTREON_USER -CENTREON_HOME=$CENTREON_HOME -CENTREON_ETC_DIR=$CENTREON_ETC_DIR -CENTREON_SERVICE=$CENTREON_SERVICE -ENGINE_USER=$ENGINE_USER -ENGINE_GROUP=$ENGINE_GROUP -BROKER_USER=$BROKER_USER -BROKER_GROUP=$BROKER_GROUP -BINARY_DIR=$BINARY_DIR -PERL_BINARY=$PERL_BINARY -SYSTEMD_ETC_DIR=$SYSTEMD_ETC_DIR -SYSCONFIG_ETC_DIR=$SYSCONFIG_ETC_DIR -LOGROTATED_ETC_DIR=$LOGROTATED_ETC_DIR \ No newline at end of file diff --git a/centreon-gorgone/keys/central/privkey.pem b/centreon-gorgone/keys/central/privkey.pem deleted file mode 100644 index 72d6ae80b9..0000000000 --- a/centreon-gorgone/keys/central/privkey.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKgIBAAKCAgEAuQ0EjIm2FXh6Z/JtjBkJ1PHFdZcw1QBss0KQ1/NIYfg0dAl1 -X1SSDYGVTVvqr2Z5AiE5rwpDMZjUjxh2WLTzVpVbLAWIzsmc54RtaEYbB2QCi/p+ -uvOr7JGzf5PVRIgA+McnghSYmcqZsyWVi6sR2LhTLA4ndlNH32tJDKQ6lnXM43EA -vd9BiKDEzp4CzDehg8HWSaC36wv8OPCQ9EbOFmIDWU4kL6xE3ThyHbRPGfEKFykE -5PmPCuYKWmPGVkbB2OipBmwOuJ6C/MgIYhQBLH61e7aXnytoLw5NG/xb4IXyOOvV -U8gtmo4bjxeEmGBzIoiOXxTeb643rJpPLkjvub0PRlYvgHzIuBt3Zj3pBhfmlm7V -1mNwba0PAxJ6AU4sXskBxYEeWq6gNWOpGIxi4+fAF2MQ35OTjEBJp/rv5zY2weCS -KYby3xO6TrGRCZZyxmrYErcUFIqnfZNkfe7HUUEx6dCKA/wfmGucaHI+I2z/+iJN -bi3n59Rj6rQvf0PsETmiahjIGhDt0y+/F7dzCsKfMVsA07vO+uFWpF6uYmjoB5Zh -zBjn7BiIdpCc7tnJE4L2ctc4YQRNi5xqu0O2VtfqGwtb3fy6dEPge/Femp7/NGgj -bbGloLXiHCnujXpPHoaib9T0ryIGAMrRPPYrgGv+od1qZfDlw3UpnrodLe0CAwEA -AQKCAgB3y1+Yg0Xm3FmRlTUprsPYoLNNjpTEL0QvP/Z4djvzgDSkscLT9fGe4LaA -n/JrnhDUOiIXmLMrFl70S8fBYVLuSD3/X43TIF182xPgnxG8VRf4+i60ZC52NVRY -UKGNfeXzJyoCYcbwOGILwVbwVcx12c2uBXOye/NZRSDDGEX9RUFgM7VhNXg9NKZz -g4MYJSNgIknQ3ERz2wxq6AFOwc+EWesFEzsFyaXC+FmXtTRH/OylVZ6fhJb/XTBy -l4i8LY4sF2HkkGtvRN5TOkODCqQ/478k2W2KUxVc8QsmBNaNoOjPxIwTctFi7oAU -wArMghPG1VQlZWMiNUxBZpu/wOO+5WFzAg2hrR6SoYa/X8Hpk3+H44fmZ4sHGjLA -Tm+mCassH4F2PPxUsC2OaWa2jdYuJNZqb5FydOPtKV314ukSc7YBfLQTafuKv37Z -A7IMteYLsGGzhmLSvSLliTvXEkz/c5mPcJE1RW6fhMkLI1/PLvgQT44XeJQR3bJY -qaDbVQkm6YEjQ28aA4Lhu1zpC1f9bFzlY3nP6cw/d5Nx6bPtbn3qs9WaI2LlgIGx -9xQ4TQTJF/qf3qVTXFeVtvVh0xfyIoObP99CMnb0wAklpbenYStd97T0ZkHKnapk -ND7p5s8W+8OiyBFHjgvNR5pw3Ufk32t9OFT0CGVzJK3IJrCz2QKCAQEA634PL8y1 -Z9fZ44ErpLy2HLboeivhznK8T8fhDIzVTm+iKoW0CZuFFgm3pbLIcnu4W/EnLF2H -Ry1lF1msvL/B9GNQF2vP4zcFJDo6famtyfXTQz85Sh2QHSdhL0h3pqGUKdDtRsf0 -zXXhlTKYqxq6rJrIIoRXQniBUPUX+bk6TceEX7b4FJU+c0HgEOP/CgN4uvdFlR73 -NTjSdt66BijWiqGu6DDGWxmaKJEx7nW9NAqL3GjVxWesW1CnrNFEo0FnlMqTvYar -PEVr33CrhKdUrLP7dt6Qe/mCJ6/6mevR8gOm+Mo31Tra1pbFqT8yZojOr/eABj/U -bEHrjVYkSwhCvwKCAQEAySpw/sZO6Kx3vGaNlmCq8RpMcHWd1w4W5dEg1VQfKaRx -7PpWh5tAAlzvW25/xEmlS3VAuEnJDGM+hyh9FxHVmmcgVYQkeriBCS8ApjGr29Jx -SZ7iSHeN7PEEBls8OapR6UK5vZYlAnI4L8xS4gUv93E7RQ3GWWPfbMF2kI1vLR86 -fqkgbssyTBL0iwe4vzGbuwJ7NjqQwK5oNXKoJT7SE+jDbI0pjbJEvQ43/lPyMreH -nBqbEhkBZymy41TpecrEdDe24SghLq4SO+BpQvbwEKons+jLz+/19jRXIP1fmXlH -VkR0OGvcGD7g12bb3xM3TtufeF7bcGF+83dYeLT2UwKCAQEAs4YJO85aKMzjvU0W -oWJ/jopd1e0oGkNbjZJ53SBr6Hyv6qy84Gof3foQd5BAwQ3SML05uNegLkHMBC4H -wmiJCq6/OuuksrmaANEnD+9Pnlv57xT+rqK035TKwMoE9RHOqsYsbL44wHzyONQ2 -kJIy5yykD7RF9VV6d+Ywnd54NR05q+IHY2GXFzSMBTRalB6rZhTlhdXybS9hOt92 -fwWY8Fxrw3STcpWk8PInV3uIfmjf0GpXNUNgoMhu2w85vR86QLLiSCSm266sms0A -5ILPyUz4Edl/2hMPBwRgDgE5rr7cBmPahoJ0nAyaqPiVipcWwgzzG1CDtvfWA4w8 -5LpqbwKCAQEAha4FftkLkQUjYHiJ+HduwV/nkggnBsVfJAOQHROUzdhwuLk3DVB2 -/dsCWLEaiLcj9/wIMS8fQnMlFy4pyk3Ys416aDmzADZh0VeBx+9UNHUpQXIrD1sb -Xmxfb1XrtKphWnAz/C+tkm2StvjBz18BHB8L8vyPZdG/pIb/olnKmqKY/Zioa9fu -Ka2jAkz0UWHHCkRA2q2aieCccYArCu0vL3nLe/Rmu7nOgg/T19ezKE7b+DmZ+THS -w9pq/TTtHjlHya9IgWFog5u7lDyx1oVAzOI2FhFKd3kP6zem+s5FXDjC1ioRTXkn -vpjyU1IQJLKhW28JDzWB/7FaarJRgY1H7wKCAQEAtJp1vAw2IomD02EfDiTDi90M -I5EIaVf4z5Kw9YkYKX3D/gXBr3KKba4QQhVg5oO5S9RrpRGBnbKuE6sJNqoxCvxP -ro22Y0KpesYdaFuVv8x8AB3LnYSGgNrkl68hNgC/8z69ZJRRdhpcY3GofxMbfVhV -MMtUF6l/oEAOKNT+LCHWlBwGrGtswsBXo7Y1GRUBOfMYUzQoqGyV9QvrdPAHjzvE -VR2/A/pQTbDW9DumWbiU/QVAhXlgY5/VZ/DadWHzLcY7Kpfzcp2O0AmdH4qwSL2Y -ZDLtSMNuRAUmkX1HL4c06qCCOHxKT1ZZNrBbvsWI+X7z1BvU37yO2x5UY4vlVg== ------END RSA PRIVATE KEY----- diff --git a/centreon-gorgone/keys/central/pubkey.crt b/centreon-gorgone/keys/central/pubkey.crt deleted file mode 100644 index 7fb3f963e9..0000000000 --- a/centreon-gorgone/keys/central/pubkey.crt +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuQ0EjIm2FXh6Z/JtjBkJ -1PHFdZcw1QBss0KQ1/NIYfg0dAl1X1SSDYGVTVvqr2Z5AiE5rwpDMZjUjxh2WLTz -VpVbLAWIzsmc54RtaEYbB2QCi/p+uvOr7JGzf5PVRIgA+McnghSYmcqZsyWVi6sR -2LhTLA4ndlNH32tJDKQ6lnXM43EAvd9BiKDEzp4CzDehg8HWSaC36wv8OPCQ9EbO -FmIDWU4kL6xE3ThyHbRPGfEKFykE5PmPCuYKWmPGVkbB2OipBmwOuJ6C/MgIYhQB -LH61e7aXnytoLw5NG/xb4IXyOOvVU8gtmo4bjxeEmGBzIoiOXxTeb643rJpPLkjv -ub0PRlYvgHzIuBt3Zj3pBhfmlm7V1mNwba0PAxJ6AU4sXskBxYEeWq6gNWOpGIxi -4+fAF2MQ35OTjEBJp/rv5zY2weCSKYby3xO6TrGRCZZyxmrYErcUFIqnfZNkfe7H -UUEx6dCKA/wfmGucaHI+I2z/+iJNbi3n59Rj6rQvf0PsETmiahjIGhDt0y+/F7dz -CsKfMVsA07vO+uFWpF6uYmjoB5ZhzBjn7BiIdpCc7tnJE4L2ctc4YQRNi5xqu0O2 -VtfqGwtb3fy6dEPge/Femp7/NGgjbbGloLXiHCnujXpPHoaib9T0ryIGAMrRPPYr -gGv+od1qZfDlw3UpnrodLe0CAwEAAQ== ------END PUBLIC KEY----- diff --git a/centreon-gorgone/keys/poller/privkey.pem b/centreon-gorgone/keys/poller/privkey.pem deleted file mode 100644 index 72d6ae80b9..0000000000 --- a/centreon-gorgone/keys/poller/privkey.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKgIBAAKCAgEAuQ0EjIm2FXh6Z/JtjBkJ1PHFdZcw1QBss0KQ1/NIYfg0dAl1 -X1SSDYGVTVvqr2Z5AiE5rwpDMZjUjxh2WLTzVpVbLAWIzsmc54RtaEYbB2QCi/p+ -uvOr7JGzf5PVRIgA+McnghSYmcqZsyWVi6sR2LhTLA4ndlNH32tJDKQ6lnXM43EA -vd9BiKDEzp4CzDehg8HWSaC36wv8OPCQ9EbOFmIDWU4kL6xE3ThyHbRPGfEKFykE -5PmPCuYKWmPGVkbB2OipBmwOuJ6C/MgIYhQBLH61e7aXnytoLw5NG/xb4IXyOOvV -U8gtmo4bjxeEmGBzIoiOXxTeb643rJpPLkjvub0PRlYvgHzIuBt3Zj3pBhfmlm7V -1mNwba0PAxJ6AU4sXskBxYEeWq6gNWOpGIxi4+fAF2MQ35OTjEBJp/rv5zY2weCS -KYby3xO6TrGRCZZyxmrYErcUFIqnfZNkfe7HUUEx6dCKA/wfmGucaHI+I2z/+iJN -bi3n59Rj6rQvf0PsETmiahjIGhDt0y+/F7dzCsKfMVsA07vO+uFWpF6uYmjoB5Zh -zBjn7BiIdpCc7tnJE4L2ctc4YQRNi5xqu0O2VtfqGwtb3fy6dEPge/Femp7/NGgj -bbGloLXiHCnujXpPHoaib9T0ryIGAMrRPPYrgGv+od1qZfDlw3UpnrodLe0CAwEA -AQKCAgB3y1+Yg0Xm3FmRlTUprsPYoLNNjpTEL0QvP/Z4djvzgDSkscLT9fGe4LaA -n/JrnhDUOiIXmLMrFl70S8fBYVLuSD3/X43TIF182xPgnxG8VRf4+i60ZC52NVRY -UKGNfeXzJyoCYcbwOGILwVbwVcx12c2uBXOye/NZRSDDGEX9RUFgM7VhNXg9NKZz -g4MYJSNgIknQ3ERz2wxq6AFOwc+EWesFEzsFyaXC+FmXtTRH/OylVZ6fhJb/XTBy -l4i8LY4sF2HkkGtvRN5TOkODCqQ/478k2W2KUxVc8QsmBNaNoOjPxIwTctFi7oAU -wArMghPG1VQlZWMiNUxBZpu/wOO+5WFzAg2hrR6SoYa/X8Hpk3+H44fmZ4sHGjLA -Tm+mCassH4F2PPxUsC2OaWa2jdYuJNZqb5FydOPtKV314ukSc7YBfLQTafuKv37Z -A7IMteYLsGGzhmLSvSLliTvXEkz/c5mPcJE1RW6fhMkLI1/PLvgQT44XeJQR3bJY -qaDbVQkm6YEjQ28aA4Lhu1zpC1f9bFzlY3nP6cw/d5Nx6bPtbn3qs9WaI2LlgIGx -9xQ4TQTJF/qf3qVTXFeVtvVh0xfyIoObP99CMnb0wAklpbenYStd97T0ZkHKnapk -ND7p5s8W+8OiyBFHjgvNR5pw3Ufk32t9OFT0CGVzJK3IJrCz2QKCAQEA634PL8y1 -Z9fZ44ErpLy2HLboeivhznK8T8fhDIzVTm+iKoW0CZuFFgm3pbLIcnu4W/EnLF2H -Ry1lF1msvL/B9GNQF2vP4zcFJDo6famtyfXTQz85Sh2QHSdhL0h3pqGUKdDtRsf0 -zXXhlTKYqxq6rJrIIoRXQniBUPUX+bk6TceEX7b4FJU+c0HgEOP/CgN4uvdFlR73 -NTjSdt66BijWiqGu6DDGWxmaKJEx7nW9NAqL3GjVxWesW1CnrNFEo0FnlMqTvYar -PEVr33CrhKdUrLP7dt6Qe/mCJ6/6mevR8gOm+Mo31Tra1pbFqT8yZojOr/eABj/U -bEHrjVYkSwhCvwKCAQEAySpw/sZO6Kx3vGaNlmCq8RpMcHWd1w4W5dEg1VQfKaRx -7PpWh5tAAlzvW25/xEmlS3VAuEnJDGM+hyh9FxHVmmcgVYQkeriBCS8ApjGr29Jx -SZ7iSHeN7PEEBls8OapR6UK5vZYlAnI4L8xS4gUv93E7RQ3GWWPfbMF2kI1vLR86 -fqkgbssyTBL0iwe4vzGbuwJ7NjqQwK5oNXKoJT7SE+jDbI0pjbJEvQ43/lPyMreH -nBqbEhkBZymy41TpecrEdDe24SghLq4SO+BpQvbwEKons+jLz+/19jRXIP1fmXlH -VkR0OGvcGD7g12bb3xM3TtufeF7bcGF+83dYeLT2UwKCAQEAs4YJO85aKMzjvU0W -oWJ/jopd1e0oGkNbjZJ53SBr6Hyv6qy84Gof3foQd5BAwQ3SML05uNegLkHMBC4H -wmiJCq6/OuuksrmaANEnD+9Pnlv57xT+rqK035TKwMoE9RHOqsYsbL44wHzyONQ2 -kJIy5yykD7RF9VV6d+Ywnd54NR05q+IHY2GXFzSMBTRalB6rZhTlhdXybS9hOt92 -fwWY8Fxrw3STcpWk8PInV3uIfmjf0GpXNUNgoMhu2w85vR86QLLiSCSm266sms0A -5ILPyUz4Edl/2hMPBwRgDgE5rr7cBmPahoJ0nAyaqPiVipcWwgzzG1CDtvfWA4w8 -5LpqbwKCAQEAha4FftkLkQUjYHiJ+HduwV/nkggnBsVfJAOQHROUzdhwuLk3DVB2 -/dsCWLEaiLcj9/wIMS8fQnMlFy4pyk3Ys416aDmzADZh0VeBx+9UNHUpQXIrD1sb -Xmxfb1XrtKphWnAz/C+tkm2StvjBz18BHB8L8vyPZdG/pIb/olnKmqKY/Zioa9fu -Ka2jAkz0UWHHCkRA2q2aieCccYArCu0vL3nLe/Rmu7nOgg/T19ezKE7b+DmZ+THS -w9pq/TTtHjlHya9IgWFog5u7lDyx1oVAzOI2FhFKd3kP6zem+s5FXDjC1ioRTXkn -vpjyU1IQJLKhW28JDzWB/7FaarJRgY1H7wKCAQEAtJp1vAw2IomD02EfDiTDi90M -I5EIaVf4z5Kw9YkYKX3D/gXBr3KKba4QQhVg5oO5S9RrpRGBnbKuE6sJNqoxCvxP -ro22Y0KpesYdaFuVv8x8AB3LnYSGgNrkl68hNgC/8z69ZJRRdhpcY3GofxMbfVhV -MMtUF6l/oEAOKNT+LCHWlBwGrGtswsBXo7Y1GRUBOfMYUzQoqGyV9QvrdPAHjzvE -VR2/A/pQTbDW9DumWbiU/QVAhXlgY5/VZ/DadWHzLcY7Kpfzcp2O0AmdH4qwSL2Y -ZDLtSMNuRAUmkX1HL4c06qCCOHxKT1ZZNrBbvsWI+X7z1BvU37yO2x5UY4vlVg== ------END RSA PRIVATE KEY----- diff --git a/centreon-gorgone/keys/poller/pubkey.crt b/centreon-gorgone/keys/poller/pubkey.crt deleted file mode 100644 index 7fb3f963e9..0000000000 --- a/centreon-gorgone/keys/poller/pubkey.crt +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuQ0EjIm2FXh6Z/JtjBkJ -1PHFdZcw1QBss0KQ1/NIYfg0dAl1X1SSDYGVTVvqr2Z5AiE5rwpDMZjUjxh2WLTz -VpVbLAWIzsmc54RtaEYbB2QCi/p+uvOr7JGzf5PVRIgA+McnghSYmcqZsyWVi6sR -2LhTLA4ndlNH32tJDKQ6lnXM43EAvd9BiKDEzp4CzDehg8HWSaC36wv8OPCQ9EbO -FmIDWU4kL6xE3ThyHbRPGfEKFykE5PmPCuYKWmPGVkbB2OipBmwOuJ6C/MgIYhQB -LH61e7aXnytoLw5NG/xb4IXyOOvVU8gtmo4bjxeEmGBzIoiOXxTeb643rJpPLkjv -ub0PRlYvgHzIuBt3Zj3pBhfmlm7V1mNwba0PAxJ6AU4sXskBxYEeWq6gNWOpGIxi -4+fAF2MQ35OTjEBJp/rv5zY2weCSKYby3xO6TrGRCZZyxmrYErcUFIqnfZNkfe7H -UUEx6dCKA/wfmGucaHI+I2z/+iJNbi3n59Rj6rQvf0PsETmiahjIGhDt0y+/F7dz -CsKfMVsA07vO+uFWpF6uYmjoB5ZhzBjn7BiIdpCc7tnJE4L2ctc4YQRNi5xqu0O2 -VtfqGwtb3fy6dEPge/Femp7/NGgjbbGloLXiHCnujXpPHoaib9T0ryIGAMrRPPYr -gGv+od1qZfDlw3UpnrodLe0CAwEAAQ== ------END PUBLIC KEY----- diff --git a/centreon-gorgone/packaging/centreon-gorgone-centreon-config.yaml b/centreon-gorgone/packaging/centreon-gorgone-centreon-config.yaml deleted file mode 100644 index c57d0cc9c8..0000000000 --- a/centreon-gorgone/packaging/centreon-gorgone-centreon-config.yaml +++ /dev/null @@ -1,69 +0,0 @@ -name: "centreon-gorgone-centreon-config" -arch: "${ARCH}" -platform: "linux" -version_schema: "none" -version: "${VERSION}" -release: "${RELEASE}${DIST}" -section: "default" -priority: "optional" -maintainer: "Centreon " -description: | - Configure Centreon Gorgone for use with Centreon Web - Commit: @COMMIT_HASH@ -vendor: "Centreon" -homepage: "https://www.centreon.com" -license: "Apache-2.0" - -contents: - - src: "./configuration/centreon.yaml" - dst: "/etc/centreon-gorgone/config.d/30-centreon.yaml" - type: config|noreplace - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0640 - - - src: "./configuration/centreon-api.yaml" - dst: "/etc/centreon-gorgone/config.d/centreon-api.yaml" - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0660 - - - src: "./configuration/centreon-audit.yaml" - dst: "/etc/centreon-gorgone/config.d/50-centreon-audit.yaml" - type: config|noreplace - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0640 - - - dst: "/var/cache/centreon-gorgone/autodiscovery" - type: dir - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0770 - -scripts: - postinstall: ./scripts/centreon-gorgone-centreon-config-postinstall.sh - -overrides: - rpm: - depends: - - centreon-gorgone = ${VERSION}-${RELEASE}${DIST} - deb: - depends: - - centreon-gorgone (= ${VERSION}-${RELEASE}${DIST}) - replaces: - - centreon-gorgone (<< 24.05.0) - -deb: - breaks: - - centreon-gorgone (<< 24.05.0) - -rpm: - summary: Configure Centreon Gorgone for use with Centreon Web - signature: - key_file: ${RPM_SIGNING_KEY_FILE} - key_id: ${RPM_SIGNING_KEY_ID} diff --git a/centreon-gorgone/packaging/centreon-gorgone-selinux.yaml b/centreon-gorgone/packaging/centreon-gorgone-selinux.yaml deleted file mode 100644 index 98d1975e1e..0000000000 --- a/centreon-gorgone/packaging/centreon-gorgone-selinux.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: "centreon-gorgone-selinux" -arch: "${ARCH}" -platform: "linux" -version_schema: "none" -version: "${VERSION}" -release: "${RELEASE}${DIST}" -section: "default" -priority: "optional" -maintainer: "Centreon " -description: | - Selinux for centreon-gorgone - Commit: @COMMIT_HASH@ -vendor: "Centreon" -homepage: "https://www.centreon.com" -license: "Apache-2.0" - -depends: - - policycoreutils - - centreon-common-selinux -replaces: - - centreon-gorgone-selinux-debuginfo -conflicts: - - centreon-gorgone-selinux-debuginfo -provides: - - centreon-gorgone-selinux-debuginfo - -contents: - - src: "../selinux/centreon-gorgoned.pp" - dst: "/usr/share/selinux/packages/centreon/centreon-gorgoned.pp" - file_info: - mode: 0655 - -scripts: - postinstall: ./scripts/centreon-gorgone-selinux-postinstall.sh - preremove: ./scripts/centreon-gorgone-selinux-preremove.sh - -rpm: - summary: Selinux for centreon-gorgone - signature: - key_file: ${RPM_SIGNING_KEY_FILE} - key_id: ${RPM_SIGNING_KEY_ID} diff --git a/centreon-gorgone/packaging/centreon-gorgone.yaml b/centreon-gorgone/packaging/centreon-gorgone.yaml deleted file mode 100644 index c24f1d8ffe..0000000000 --- a/centreon-gorgone/packaging/centreon-gorgone.yaml +++ /dev/null @@ -1,228 +0,0 @@ -name: "centreon-gorgone" -arch: "${ARCH}" -platform: "linux" -version_schema: "none" -version: "${VERSION}" -release: "${RELEASE}${DIST}" -section: "default" -priority: "optional" -maintainer: "Centreon " -description: | - Centreon gorgone daemon - Commit: @COMMIT_HASH@ -vendor: "Centreon" -homepage: "https://www.centreon.com" -license: "Apache-2.0" - -contents: - - dst: "/etc/centreon-gorgone" - type: dir - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0755 - - - dst: "/etc/centreon-gorgone/config.d" - type: dir - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0770 - - - dst: "/etc/centreon-gorgone/config.d/cron.d" - type: dir - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0770 - - - dst: "/etc/centreon-gorgone/config.d/whitelist.conf.d" - type: dir - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0770 - - - src: "./configuration/config.yaml" - dst: "/etc/centreon-gorgone/config.yaml" - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0640 - - - src: "./configuration/action.yaml" - dst: "/etc/centreon-gorgone/config.d/39-action.yaml" - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0640 - - - src: "./configuration/whitelist.conf.d/centreon.yaml" - dst: "/etc/centreon-gorgone/config.d/whitelist.conf.d/centreon.yaml" - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0640 - - - dst: "/var/lib/centreon-gorgone" - type: dir - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0775 - - - dst: "/var/log/centreon-gorgone" - type: dir - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0775 - - - dst: "/var/cache/centreon-gorgone" - type: dir - file_info: - owner: centreon-gorgone - group: centreon-gorgone - mode: 0775 - - - src: "./sudoers.d/centreon-gorgone" - dst: "/etc/sudoers.d/centreon-gorgone" - file_info: - mode: 0600 - - - src: "../config/systemd/gorgoned.rpm.service" - dst: "/etc/systemd/system/gorgoned.service" - file_info: - mode: 0644 - packager: rpm - - src: "../config/systemd/gorgoned.deb.service" - dst: "/lib/systemd/system/gorgoned.service" - file_info: - mode: 0644 - packager: deb - - - src: "../config/systemd/gorgoned-sysconfig" - dst: "/etc/sysconfig/gorgoned" - type: config|noreplace - packager: rpm - - src: "../config/systemd/gorgoned-sysconfig" - dst: "/etc/default/gorgoned" - type: config|noreplace - packager: deb - - - src: "../config/logrotate/gorgoned" - dst: "/etc/logrotate.d/gorgoned" - type: config|noreplace - - - src: "../gorgoned" - dst: "/usr/bin/gorgoned" - file_info: - mode: 0755 - - - src: "../gorgone" - dst: "${PERL_VENDORLIB}/gorgone" - expand: true - - - src: "../contrib/gorgone_config_init.pl" - dst: "/usr/local/bin/" - file_info: - mode: 0755 - - - src: "../contrib/gorgone_audit.pl" - dst: "/usr/local/bin/" - file_info: - mode: 0755 - - - src: "../contrib/gorgone_install_plugins.pl" - dst: "/usr/local/bin/" - file_info: - mode: 0750 - - - src: "../contrib/gorgone_key_thumbprint.pl" - dst: "/usr/local/bin/" - file_info: - mode: 0750 - - - src: "../contrib/gorgone_key_generation.pl" - dst: "/usr/local/bin/" - file_info: - mode: 0750 - -scripts: - preinstall: ./scripts/centreon-gorgone-preinstall.sh - postinstall: ./scripts/centreon-gorgone-postinstall.sh - preremove: ./scripts/centreon-gorgone-preremove.sh - -overrides: - rpm: - depends: - - centreon-common - - bzip2 - - perl-Libssh-Session >= 0.8 - - perl-CryptX - - perl-Mojolicious - - perl(Archive::Tar) - - perl(Schedule::Cron) - - perl(ZMQ::FFI) - - perl(EV) - - perl(JSON::XS) - - perl(JSON::PP) - - perl(XML::Simple) - - perl(XML::LibXML::Simple) - - perl(Net::SMTP) - - perl(YAML::XS) - - perl(DBD::SQLite) - - perl(DBD::mysql) - - perl(DBI) - - perl(UUID) - - perl(HTTP::Daemon) - - perl(HTTP::Status) - - perl(MIME::Base64) - - perl(Digest::MD5::File) - - perl(Net::Curl::Easy) - - perl(HTTP::Daemon::SSL) - - perl(NetAddr::IP) - - perl(Hash::Merge) - - perl(Clone) - - perl(Sys::Syslog) - - perl(DateTime) - - perl(Try::Tiny) - - tar - - perl(JSON) # gorgone_key_thumbprint.pl needs the json module, even when json::xs is already installed - deb: - depends: # those dependencies are taken from centreon-gorgone/packaging/debian/control - - centreon-common - - libdatetime-perl - - libtime-parsedate-perl - - libtry-tiny-perl - - libxml-simple-perl - - libxml-libxml-simple-perl - - libdigest-md5-file-perl - - libjson-pp-perl - - libjson-xs-perl - - libyaml-libyaml-perl - - libdbi-perl - - libdbd-sqlite3-perl - - libdbd-mysql-perl - - libhttp-daemon-perl - - libhttp-daemon-ssl-perl - - libnetaddr-ip-perl - - libschedule-cron-perl - - libhash-merge-perl - - libcryptx-perl - - libmojolicious-perl - - libauthen-simple-perl - - libauthen-simple-net-perl - - libnet-curl-perl - - libssh-session-perl - - libssh-4 - - libev-perl - - libzmq-ffi-perl - - libclone-choose-perl - - libjson-perl # gorgone_key_thumbprint.pl needs the json module, even when json::xs is already installed - -rpm: - summary: Centreon gorgone daemon - signature: - key_file: ${RPM_SIGNING_KEY_FILE} - key_id: ${RPM_SIGNING_KEY_ID} diff --git a/centreon-gorgone/packaging/configuration/action.yaml b/centreon-gorgone/packaging/configuration/action.yaml deleted file mode 100644 index 8dcebf2cd2..0000000000 --- a/centreon-gorgone/packaging/configuration/action.yaml +++ /dev/null @@ -1,8 +0,0 @@ -gorgone: - modules: - - name: action - package: "gorgone::modules::core::action::hooks" - enable: true - command_timeout: 30 - whitelist_cmds: true - allowed_cmds: !include /etc/centreon-gorgone/config.d/whitelist.conf.d/*.yaml diff --git a/centreon-gorgone/packaging/configuration/centreon-api.yaml b/centreon-gorgone/packaging/configuration/centreon-api.yaml deleted file mode 100644 index e0c47e50e1..0000000000 --- a/centreon-gorgone/packaging/configuration/centreon-api.yaml +++ /dev/null @@ -1,9 +0,0 @@ -gorgone: - tpapi: - - name: centreonv2 - base_url: "http://127.0.0.1/centreon/api/latest/" - username: "@GORGONE_USER@" - password: "@GORGONE_PASSWORD@" - - name: clapi - username: "@GORGONE_USER@" - password: "@GORGONE_PASSWORD@" diff --git a/centreon-gorgone/packaging/configuration/centreon-audit.yaml b/centreon-gorgone/packaging/configuration/centreon-audit.yaml deleted file mode 100644 index ae0f8c96c6..0000000000 --- a/centreon-gorgone/packaging/configuration/centreon-audit.yaml +++ /dev/null @@ -1,5 +0,0 @@ -gorgone: - modules: - - name: audit - package: "gorgone::modules::centreon::audit::hooks" - enable: true diff --git a/centreon-gorgone/packaging/configuration/centreon.yaml b/centreon-gorgone/packaging/configuration/centreon.yaml deleted file mode 100644 index a66311890a..0000000000 --- a/centreon-gorgone/packaging/configuration/centreon.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: centreon.yaml -description: Configure Centreon Gorgone to work with Centreon Web. -centreon: !include /etc/centreon/config.d/*.yaml diff --git a/centreon-gorgone/packaging/configuration/config.yaml b/centreon-gorgone/packaging/configuration/config.yaml deleted file mode 100644 index d5fb3439db..0000000000 --- a/centreon-gorgone/packaging/configuration/config.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: config.yaml -description: Configuration brought by Centreon Gorgone package. SHOULD NOT BE EDITED! USE CONFIG.D DIRECTORY! -configuration: !include /etc/centreon-gorgone/config.d/*.yaml diff --git a/centreon-gorgone/packaging/configuration/whitelist.conf.d/centreon.yaml b/centreon-gorgone/packaging/configuration/whitelist.conf.d/centreon.yaml deleted file mode 100644 index 5a7e2cca4e..0000000000 --- a/centreon-gorgone/packaging/configuration/whitelist.conf.d/centreon.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Configuration brought by Centreon Gorgone package. -# SHOULD NOT BE EDITED! CREATE YOUR OWN FILE IN WHITELIST.CONF.D DIRECTORY! -- ^sudo\s+(/bin/|/usr/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ -- ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ -- ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/+centengine\.cfg\s*$ -- ^cat\s+/var/lib/centreon-engine/+[a-zA-Z0-9\-]+-stats\.json\s*$ -- ^/usr/lib/centreon/plugins/.*$ -- ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ -- ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ -- ^centreon -- ^mkdir -- ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host -- ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ -- ^/usr/bin/php (-q )?/usr/share/centreon/cron/[\w,\s.-]+ >> /var/log/centreon-gorgone/[\w,\s.-]+\s+2>&1$ -- ^/usr/bin/php -q /usr/share/centreon/www/modules/centreon-bi-server/tools/purgeArchivesFiles\.php >> /var/log/centreon-gorgone/centreon-bi-archive-retention\.log 2>&1$ -- ^/usr/share/centreon/cron/eventReportBuilder --config=/etc/centreon/conf\.pm >> /var/log/centreon-gorgone/eventReportBuilder\.log 2>&1$ -- ^/usr/share/centreon/cron/dashboardBuilder --config=/etc/centreon/conf\.pm >> /var/log/centreon-gorgone/dashboardBuilder\.log 2>&1$ -- ^/usr/share/centreon/www/modules/centreon-dsm/+cron/centreon_dsm_purge\.pl --config=\"/etc/centreon/conf.pm\" --severity=\S+ >> /var/log/centreon-gorgone/centreon_dsm_purge\.log 2>&1\s*$ -- ^/usr/share/centreon-bi-backup/centreon-bi-backup-web\.sh >> /var/log/centreon-gorgone/centreon-bi-backup-web\.log 2>&1$ -- ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/+cron/centreon_autodisco.pl --config='/etc/centreon/conf.pm' --config-extra='/etc/centreon/centreon_autodisco.pm' --severity=\S+ >> /var/log/centreon-gorgone/centreon_service_discovery.log 2>&1$ diff --git a/centreon-gorgone/packaging/packages/perl-Clone-Choose.spec b/centreon-gorgone/packaging/packages/perl-Clone-Choose.spec deleted file mode 100644 index 5390763404..0000000000 --- a/centreon-gorgone/packaging/packages/perl-Clone-Choose.spec +++ /dev/null @@ -1,51 +0,0 @@ -%define cpan_name Clone-Choose - -Name: perl-Clone-Choose -Version: 0.010 -Release: 1%{?dist} -Summary: Choose appropriate clone utility -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/Clone::Choose -Source0: https://cpan.metacpan.org/authors/id/H/HE/HERMES/%{cpan_name}-%{version}.tar.gz -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: make - -Provides: perl(Clone::Choose) -AutoReqProv: no - -%description -Clone::Choose checks several different modules which provides a clone() function and selects an appropriate one. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorlib} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-Clone.spec b/centreon-gorgone/packaging/packages/perl-Clone.spec deleted file mode 100644 index 22fabb47db..0000000000 --- a/centreon-gorgone/packaging/packages/perl-Clone.spec +++ /dev/null @@ -1,51 +0,0 @@ -%define cpan_name Clone - -Name: perl-Clone -Version: 0.45 -Release: 1%{?dist} -Summary: recursively copy Perl datatypes -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/Clone -Source0: https://cpan.metacpan.org/authors/id/A/AT/ATOOMIC/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: gcc -BuildRequires: make - -Provides: perl(Clone) -AutoReqProv: no - -%description -This module provides a clone() method which makes recursive copies of nested hash, array, scalar and reference types, including tied variables and objects. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorarch} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-CryptX.spec b/centreon-gorgone/packaging/packages/perl-CryptX.spec deleted file mode 100644 index 6fd4f8c1a7..0000000000 --- a/centreon-gorgone/packaging/packages/perl-CryptX.spec +++ /dev/null @@ -1,46 +0,0 @@ -%define cpan_name CryptX - -Name: perl-CryptX -Version: 0.068 -Release: 1%{?dist} -Summary: Cryptographic toolkit (self-contained, no external libraries needed) -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/CryptX -Source0: https://cpan.metacpan.org/authors/id/M/MI/MIK/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: make -BuildRequires: gcc - -%description -Cryptography in CryptX is based on https://github.com/libtom/libtomcrypt - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%{perl_vendorarch} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-Digest-MD5-File.spec b/centreon-gorgone/packaging/packages/perl-Digest-MD5-File.spec deleted file mode 100644 index 9fc2af4166..0000000000 --- a/centreon-gorgone/packaging/packages/perl-Digest-MD5-File.spec +++ /dev/null @@ -1,53 +0,0 @@ -%define cpan_name Digest-MD5-File - -Name: Digest-MD5-File -Version: 0.08 -Release: 1%{?dist} -Summary: Perl extension for getting MD5 sums for files and urls. -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/Digest::MD5::File -Source0: https://cpan.metacpan.org/authors/id/D/DM/DMUEY/%{cpan_name}-%{version}.tar.gz -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: make - -Provides: perl(Digest::MD5::File) -Requires: perl(Digest::MD5) -Requires: perl(LWP::UserAgent) -AutoReqProv: no - -%description -Get MD5 sums for files of a given path or content of a given url. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorlib} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-FFI-CheckLib.spec b/centreon-gorgone/packaging/packages/perl-FFI-CheckLib.spec deleted file mode 100644 index 025166f200..0000000000 --- a/centreon-gorgone/packaging/packages/perl-FFI-CheckLib.spec +++ /dev/null @@ -1,54 +0,0 @@ -%define cpan_name FFI-CheckLib - -Name: perl-FFI-CheckLib -Version: 0.31 -Release: 1%{?dist} -Summary: Check that a library is available for FFI -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/FFI::CheckLib -Source0: https://cpan.metacpan.org/authors/id/P/PL/PLICEASE/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -Provides: perl(FFI::CheckLib) - -BuildRequires: make -BuildRequires: perl(ExtUtils::MakeMaker) - -Requires: perl(File::Which) -Requires: perl(List::Util) - -%description -This module checks whether a particular dynamic library is available for FFI to use. It is modeled heavily on Devel::CheckLib, but will find dynamic libraries even when development packages are not installed. It also provides a find_lib function that will return the full path to the found dynamic library, which can be feed directly into FFI::Platypus or another FFI system. - -%global debug_package %{nil} - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorlib}/ -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-FFI-Platypus.spec b/centreon-gorgone/packaging/packages/perl-FFI-Platypus.spec deleted file mode 100644 index 7cc88d10e7..0000000000 --- a/centreon-gorgone/packaging/packages/perl-FFI-Platypus.spec +++ /dev/null @@ -1,58 +0,0 @@ -%define cpan_name FFI-Platypus - -Name: perl-FFI-Platypus -Version: 2.05 -Release: 1%{?dist} -Summary: Write Perl bindings to non-Perl libraries with FFI. No XS required. -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/FFI::Platypus -Source0: https://cpan.metacpan.org/authors/id/P/PL/PLICEASE/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: make -BuildRequires: gcc -BuildRequires: libffi-devel -BuildRequires: perl(ExtUtils::MakeMaker) - -Provides: perl(FFI::Platypus) - -Requires: libffi -Requires: perl(JSON::PP) -Requires: perl(FFI::CheckLib) -Requires: perl(Capture::Tiny) - -%description -Platypus is a library for creating interfaces to machine code libraries written in languages like C, C++, Go, Fortran, Rust, Pascal. Essentially anything that gets compiled into machine code. This implementation uses libffi to accomplish this task. libffi is battle tested by a number of other scripting and virtual machine languages, such as Python and Ruby to serve a similar role. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -export ODBCHOME=/usr/ -export PERL_MM_USE_DEFAULT="1" -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorarch}/ -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-HTTP-Daemon.spec b/centreon-gorgone/packaging/packages/perl-HTTP-Daemon.spec deleted file mode 100644 index d4ae42080c..0000000000 --- a/centreon-gorgone/packaging/packages/perl-HTTP-Daemon.spec +++ /dev/null @@ -1,57 +0,0 @@ -%define cpan_name HTTP-Daemon - -Name: perl-HTTP-Daemon -Version: 6.06 -Release: 1%{?dist} -Summary: A simple http server class -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/HTTP::Daemon -Source0: https://cpan.metacpan.org/authors/id/O/OA/OALDERS/%{cpan_name}-%{version}.tar.gz -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: perl(Module::Build::Tiny) -BuildRequires: make - -Provides: perl(HTTP::Daemon) -Requires: perl(HTTP::Date) -Requires: perl(HTTP::Message) -Requires: perl(HTTP::Response) -Requires: perl(HTTP::Status) -Requires: perl(LWP::MediaTypes) -AutoReqProv: no - -%description -Instances of the HTTP::Daemon class are HTTP/1.1 servers that listen on a socket for incoming requests. The HTTP::Daemon is a subclass of IO::Socket::IP, so you can perform socket operations directly on it too. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorlib} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-Hash-Merge.spec b/centreon-gorgone/packaging/packages/perl-Hash-Merge.spec deleted file mode 100644 index c2088f31b9..0000000000 --- a/centreon-gorgone/packaging/packages/perl-Hash-Merge.spec +++ /dev/null @@ -1,53 +0,0 @@ -%define cpan_name Hash-Merge - -Name: perl-Hash-Merge -Version: 0.300 -Release: 1%{?dist} -Summary: Merges arbitrarily deep hashes into a single hash -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/Hash::Merge -Source0: https://cpan.metacpan.org/authors/id/R/RE/REHSACK/%{cpan_name}-%{version}.tar.gz -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: make - -Provides: perl(Hash::Merge) -Requires: perl(Scalar::Util) -Requires: perl(Clone::Choose) -AutoReqProv: no - -%description -Hash::Merge merges two arbitrarily deep hashes into a single hash. That is, at any level, it will add non-conflicting key-value pairs from one hash to the other, and follows a set of specific rules when there are key value conflicts (as outlined below). The hash is followed recursively, so that deeply nested hashes that are at the same level will be merged when the parent hashes are merged. Please note that self-referencing hashes, or recursive references, are not handled well by this method. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorlib} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-JSON-XS.spec b/centreon-gorgone/packaging/packages/perl-JSON-XS.spec deleted file mode 100644 index 7b781dd4c6..0000000000 --- a/centreon-gorgone/packaging/packages/perl-JSON-XS.spec +++ /dev/null @@ -1,55 +0,0 @@ -%define cpan_name JSON-XS - -Name: perl-JSON-XS -Version: 4.02 -Release: 1%{?dist} -Summary: JSON serialising/deserialising, done correctly and fast -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/JSON::XS -Source0: https://cpan.metacpan.org/authors/id/M/ML/MLEHMANN/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(Canary::Stability) -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: make - -Provides: perl(JSON::XS) -Requires: perl(common::sense) -Requires: perl(Types::Serialiser) -AutoReqProv: no - -%description -This module converts Perl data structures to JSON and vice versa. Its primary goal is to be correct and its secondary goal is to be fast. To reach the latter goal it was written in C. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -export PERL_CANARY_STABILITY_NOPROMPT=1 -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{_usr}/bin/* -%{perl_vendorarch} -%{_mandir} - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-Net-Curl.spec b/centreon-gorgone/packaging/packages/perl-Net-Curl.spec deleted file mode 100644 index f6b0d5aa46..0000000000 --- a/centreon-gorgone/packaging/packages/perl-Net-Curl.spec +++ /dev/null @@ -1,60 +0,0 @@ -%define cpan_name Net-Curl - -Name: perl-Net-Curl -Version: 0.44 -Release: 1%{?dist} -Summary: Perl interface for libcurl -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/Net::Curl -Source0: https://cpan.metacpan.org/authors/id/S/SY/SYP/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -Provides: perl(Net::Curl) -Provides: perl(Net::Curl::Compat) -Provides: perl(Net::Curl::Easy) -Provides: perl(Net::Curl::Form) -Provides: perl(Net::Curl::Share) -Provides: perl(Net::Curl::Multi) - -BuildRequires: make -BuildRequires: gcc -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: libcurl-devel - -Requires: perl -Requires: libcurl -AutoReqProv: no - -%description -Net::Curl provides a Perl interface to libcurl created with object-oriented implementations in mind. This documentation contains Perl-specific details and quirks. For more information consult libcurl man pages and documentation at http://curl.haxx.se. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -#%doc Changes -%{perl_vendorarch}/ -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-Types-Serialiser.spec b/centreon-gorgone/packaging/packages/perl-Types-Serialiser.spec deleted file mode 100644 index ce879f79ca..0000000000 --- a/centreon-gorgone/packaging/packages/perl-Types-Serialiser.spec +++ /dev/null @@ -1,52 +0,0 @@ -%define cpan_name Types-Serialiser - -Name: perl-Types-Serialiser -Version: 1.0 -Release: 1%{?dist} -Summary: simple data types for common serialisation formats -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/Types::Serialiser -Source0: https://cpan.metacpan.org/authors/id/M/ML/MLEHMANN/%{cpan_name}-%{version}.tar.gz -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: make - -Provides: perl(Types::Serialiser) -Requires: perl(common::sense) -AutoReqProv: no - -%description -This module provides some extra datatypes that are used by common serialisation formats such as JSON or CBOR. The idea is to have a repository of simple/small constants and containers that can be shared by different implementations so they become interoperable between each other. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorlib} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-UUID.spec b/centreon-gorgone/packaging/packages/perl-UUID.spec deleted file mode 100644 index a7e71bc0a0..0000000000 --- a/centreon-gorgone/packaging/packages/perl-UUID.spec +++ /dev/null @@ -1,53 +0,0 @@ -%define cpan_name UUID - -Name: perl-UUID -Version: 0.28 -Release: 1%{?dist} -Summary: DCE compatible Universally Unique Identifier library for Perl -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/UUID -Source0: https://cpan.metacpan.org/authors/id/J/JR/JRM/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(Devel::CheckLib) -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: libuuid-devel -BuildRequires: make - -Provides: perl(UUID) -Requires: libuuid -AutoReqProv: no - -%description -The UUID library is used to generate unique identifiers for objects that may be accessible beyond the local system. For instance, they could be used to generate unique HTTP cookies across multiple web servers without communication between the servers, and without fear of a name clash. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorarch} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-YAML-LibYAML.spec b/centreon-gorgone/packaging/packages/perl-YAML-LibYAML.spec deleted file mode 100644 index 42e01e7793..0000000000 --- a/centreon-gorgone/packaging/packages/perl-YAML-LibYAML.spec +++ /dev/null @@ -1,47 +0,0 @@ -%define cpan_name YAML-LibYAML - -Name: perl-YAML-LibYAML -Version: 0.80 -Release: 1%{?dist} -Summary: Perl YAML Serialization using XS and libyaml -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/release/YAML-LibYAML -Source0: https://cpan.metacpan.org/authors/id/T/TI/TINITA/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: make -BuildRequires: gcc - -%description -Kirill Simonov's libyaml is arguably the best YAML implementation. The C library is written precisely to the YAML 1.1 specification. It was originally bound to Python and was later bound to Ruby. -This module is a Perl XS binding to libyaml which offers Perl the best YAML support to date. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%{perl_vendorarch} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-ZMQ-FFI.spec b/centreon-gorgone/packaging/packages/perl-ZMQ-FFI.spec deleted file mode 100644 index ca4ef00bc7..0000000000 --- a/centreon-gorgone/packaging/packages/perl-ZMQ-FFI.spec +++ /dev/null @@ -1,62 +0,0 @@ -%define cpan_name ZMQ-FFI - -Name: perl-ZMQ-FFI -Version: 1.18 -Release: 1%{?dist} -Summary: version agnostic Perl bindings for zeromq using ffi -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/ZMQ::FFI -Source0: https://cpan.metacpan.org/authors/id/G/GH/GHENRY/%{cpan_name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -Provides: perl(ZMQ::FFI) - -BuildRequires: make -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: zeromq-devel - -Requires: zeromq -Requires: perl(FFI::CheckLib) -Requires: perl(FFI::Platypus) -Requires: perl(Moo) -Requires: perl(Moo::Role) -Requires: perl(Scalar::Util) -Requires: perl(Try::Tiny) -Requires: perl(namespace::clean) -Requires: perl(Import::Into) - -%description -ZMQ::FFI exposes a high level, transparent, OO interface to zeromq independent of the underlying libzmq version. Where semantics differ, it will dispatch to the appropriate backend for you. As it uses ffi, there is no dependency on XS or compilation. - -%global debug_package %{nil} - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%doc Changes -%{perl_vendorlib}/ -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/packages/perl-common-sense.spec b/centreon-gorgone/packaging/packages/perl-common-sense.spec deleted file mode 100644 index 017c6c755b..0000000000 --- a/centreon-gorgone/packaging/packages/perl-common-sense.spec +++ /dev/null @@ -1,50 +0,0 @@ -%define cpan_name common-sense - -Name: perl-common-sense -Version: 3.75 -Release: 1%{?dist} -Summary: save a tree AND a kitten, use common::sense! -Group: Development/Libraries -License: GPL or Artistic -URL: https://metacpan.org/pod/common::sense -Source0: https://cpan.metacpan.org/authors/id/M/ML/MLEHMANN/%{cpan_name}-%{version}.tar.gz -BuildArch: noarch -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: perl(ExtUtils::MakeMaker) -BuildRequires: make - -Provides: perl(common::sense) -AutoReqProv: no - -%description -This module implements some sane defaults for Perl programs, as defined by two typical (or not so typical - use your common sense) specimens of Perl coders. In fact, after working out details on which warnings and strict modes to enable and make fatal, we found that we (and our code written so far, and others) fully agree on every option, even though we never used warnings before, so it seems this module indeed reflects a "common" sense among some long-time Perl coders. - -%prep -%setup -q -n %{cpan_name}-%{version} - -%build -%{__perl} Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" -make %{?_smp_mflags} - -%install -rm -rf %{buildroot} -make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT -find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type f -name '*.bs' -a -size 0 -exec rm -f {} ';' -find $RPM_BUILD_ROOT -type d -depth -exec rmdir {} 2>/dev/null ';' -%{_fixperms} $RPM_BUILD_ROOT/* - -%check -#make test - -%clean -rm -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%{perl_vendorlib} -%{_mandir}/man3/*.3* - -%changelog - diff --git a/centreon-gorgone/packaging/scripts/centreon-gorgone-centreon-config-postinstall.sh b/centreon-gorgone/packaging/scripts/centreon-gorgone-centreon-config-postinstall.sh deleted file mode 100644 index f4bd78d02c..0000000000 --- a/centreon-gorgone/packaging/scripts/centreon-gorgone-centreon-config-postinstall.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -installConfigurationFile() { - if [ ! -f /etc/centreon-gorgone/config.d/31-centreon-api.yaml ] || grep -q "@GORGONE_USER@" "/etc/centreon-gorgone/config.d/31-centreon-api.yaml"; then - mv /etc/centreon-gorgone/config.d/centreon-api.yaml /etc/centreon-gorgone/config.d/31-centreon-api.yaml - else - mv /etc/centreon-gorgone/config.d/centreon-api.yaml /etc/centreon-gorgone/config.d/centreon-api.yaml.new - fi -} - -fixConfigurationFileRights() { - # force update of configuration file rights since they are not updated automatically by nfpm - chmod 0640 /etc/centreon-gorgone/config.d/30-centreon.yaml - chmod 0640 /etc/centreon-gorgone/config.d/31-centreon-api.yaml - chmod 0640 /etc/centreon-gorgone/config.d/50-centreon-audit.yaml - chmod 0770 /etc/centreon-gorgone/config.d - chmod 0770 /etc/centreon-gorgone/config.d/cron.d -} - -manageUserGroups() { - if getent passwd centreon > /dev/null 2>&1; then - usermod -a -G centreon-gorgone centreon 2> /dev/null - fi - - if getent passwd centreon-engine > /dev/null 2>&1; then - usermod -a -G centreon-gorgone centreon-engine 2> /dev/null - fi - - if getent passwd centreon-broker > /dev/null 2>&1; then - usermod -a -G centreon-gorgone centreon-broker 2> /dev/null - fi - - if getent passwd centreon-gorgone > /dev/null 2>&1; then - usermod -a -G centreon centreon-gorgone 2> /dev/null - fi -} - -addGorgoneSshKeys() { - if [ ! -d /var/lib/centreon-gorgone/.ssh ] && [ -d /var/spool/centreon/.ssh ]; then - cp -r /var/spool/centreon/.ssh /var/lib/centreon-gorgone/.ssh - chown -R centreon-gorgone:centreon-gorgone /var/lib/centreon-gorgone/.ssh - chmod 600 /var/lib/centreon-gorgone/.ssh/id_rsa - fi -} - -action="$1" -if [ "$1" = "configure" ] && [ -z "$2" ]; then - # Alpine linux does not pass args, and deb passes $1=configure - action="install" -elif [ "$1" = "configure" ] && [ -n "$2" ]; then - # deb passes $1=configure $2= - action="upgrade" -fi - -case "$action" in - "1" | "install") - manageUserGroups - installConfigurationFile - addGorgoneSshKeys - ;; - "2" | "upgrade") - manageUserGroups - installConfigurationFile - fixConfigurationFileRights - addGorgoneSshKeys - ;; - *) - # $1 == version being installed - manageUserGroups - installConfigurationFile - addGorgoneSshKeys - ;; -esac diff --git a/centreon-gorgone/packaging/scripts/centreon-gorgone-postinstall.sh b/centreon-gorgone/packaging/scripts/centreon-gorgone-postinstall.sh deleted file mode 100644 index 0ff1468729..0000000000 --- a/centreon-gorgone/packaging/scripts/centreon-gorgone-postinstall.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -startGorgoned() { - systemctl daemon-reload ||: - systemctl unmask gorgoned.service ||: - systemctl preset gorgoned.service ||: - systemctl enable gorgoned.service ||: - systemctl restart gorgoned.service ||: -} - -action="$1" -if [ "$1" = "configure" ] && [ -z "$2" ]; then - # Alpine linux does not pass args, and deb passes $1=configure - action="install" -elif [ "$1" = "configure" ] && [ -n "$2" ]; then - # deb passes $1=configure $2= - action="upgrade" -fi - -case "$action" in - "1" | "install") - startGorgoned - ;; - "2" | "upgrade") - startGorgoned - ;; - *) - # $1 == version being installed - startGorgoned - ;; -esac diff --git a/centreon-gorgone/packaging/scripts/centreon-gorgone-preinstall.sh b/centreon-gorgone/packaging/scripts/centreon-gorgone-preinstall.sh deleted file mode 100644 index f4d22b0a16..0000000000 --- a/centreon-gorgone/packaging/scripts/centreon-gorgone-preinstall.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -if ! getent group centreon-gorgone > /dev/null 2>&1; then - groupadd -r centreon-gorgone -fi - -# Check if the centreon-gorgone user exists, and create it if not -if ! getent passwd centreon-gorgone > /dev/null 2>&1; then - useradd -g centreon-gorgone -m -d /var/lib/centreon-gorgone -r centreon-gorgone 2> /dev/null -fi diff --git a/centreon-gorgone/packaging/scripts/centreon-gorgone-preremove.sh b/centreon-gorgone/packaging/scripts/centreon-gorgone-preremove.sh deleted file mode 100644 index 3498c040c1..0000000000 --- a/centreon-gorgone/packaging/scripts/centreon-gorgone-preremove.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -systemctl stop gorgoned.service ||: diff --git a/centreon-gorgone/packaging/scripts/centreon-gorgone-selinux-postinstall.sh b/centreon-gorgone/packaging/scripts/centreon-gorgone-selinux-postinstall.sh deleted file mode 100644 index c7a5de1a19..0000000000 --- a/centreon-gorgone/packaging/scripts/centreon-gorgone-selinux-postinstall.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -install() { - semodule -i /usr/share/selinux/packages/centreon/centreon-gorgoned.pp > /dev/null 2>&1 || : -} - -upgrade() { - semodule -i /usr/share/selinux/packages/centreon/centreon-gorgoned.pp > /dev/null 2>&1 || : -} - -action="$1" -if [ "$1" = "configure" ] && [ -z "$2" ]; then - action="install" -elif [ "$1" = "configure" ] && [ -n "$2" ]; then - action="upgrade" -fi - -case "$action" in - "1" | "install") - install - ;; - "2" | "upgrade") - upgrade - ;; -esac diff --git a/centreon-gorgone/packaging/scripts/centreon-gorgone-selinux-preremove.sh b/centreon-gorgone/packaging/scripts/centreon-gorgone-selinux-preremove.sh deleted file mode 100644 index d3d21a909c..0000000000 --- a/centreon-gorgone/packaging/scripts/centreon-gorgone-selinux-preremove.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -if [ "$1" -lt "1" ]; then - semodule -r centreon-gorgoned > /dev/null 2>&1 || : -fi diff --git a/centreon-gorgone/packaging/sudoers.d/centreon-gorgone b/centreon-gorgone/packaging/sudoers.d/centreon-gorgone deleted file mode 100644 index ead5adc64d..0000000000 --- a/centreon-gorgone/packaging/sudoers.d/centreon-gorgone +++ /dev/null @@ -1,6 +0,0 @@ -## BEGIN: GORGONE SUDO - -User_Alias GORGONE=centreon-gorgone -Defaults:GORGONE !requiretty - -GORGONE ALL = NOPASSWD: /usr/local/bin/gorgone_install_plugins.pl diff --git a/centreon-gorgone/schema/gorgone_database.sql b/centreon-gorgone/schema/gorgone_database.sql deleted file mode 100644 index 7487a8b831..0000000000 --- a/centreon-gorgone/schema/gorgone_database.sql +++ /dev/null @@ -1,62 +0,0 @@ -PRAGMA encoding = "UTF-8"; - -CREATE TABLE `gorgone_information` ( - `key` varchar(1024) DEFAULT NULL, - `value` varchar(1024) DEFAULT NULL -); - -CREATE TABLE IF NOT EXISTS `gorgone_identity` ( - `id` INTEGER PRIMARY KEY, - `ctime` int(11) DEFAULT NULL, - `mtime` int(11) DEFAULT NULL, - `identity` varchar(2048) DEFAULT NULL, - `key` varchar(1024) DEFAULT NULL, - `oldkey` varchar(1024) DEFAULT NULL, - `iv` varchar(1024) DEFAULT NULL, - `oldiv` varchar(1024) DEFAULT NULL, - `parent` int(11) DEFAULT '0' -); - -CREATE INDEX IF NOT EXISTS idx_gorgone_identity ON gorgone_identity (identity); -CREATE INDEX IF NOT EXISTS idx_gorgone_parent ON gorgone_identity (parent); - -CREATE TABLE IF NOT EXISTS `gorgone_history` ( - `id` INTEGER PRIMARY KEY, - `token` varchar(2048) DEFAULT NULL, - `code` int(11) DEFAULT NULL, - `etime` int(11) DEFAULT NULL, - `ctime` FLOAT DEFAULT NULL, - `instant` int(11) DEFAULT '0', - `data` TEXT DEFAULT NULL -); - -CREATE INDEX IF NOT EXISTS idx_gorgone_history_id ON gorgone_history (id); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_token ON gorgone_history (token); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_etime ON gorgone_history (etime); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_code ON gorgone_history (code); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_ctime ON gorgone_history (ctime); -CREATE INDEX IF NOT EXISTS idx_gorgone_history_instant ON gorgone_history (instant); - -CREATE TABLE IF NOT EXISTS `gorgone_synchistory` ( - `id` int(11) NOT NULL, - `ctime` FLOAT DEFAULT NULL, - `last_id` int(11) DEFAULT NULL -); - -CREATE UNIQUE INDEX IF NOT EXISTS idx_gorgone_synchistory_id ON gorgone_synchistory (id); - -CREATE TABLE IF NOT EXISTS `gorgone_target_fingerprint` ( - `id` INTEGER PRIMARY KEY, - `target` varchar(2048) DEFAULT NULL, - `fingerprint` varchar(4096) DEFAULT NULL -); - -CREATE INDEX IF NOT EXISTS idx_gorgone_target_fingerprint_target ON gorgone_target_fingerprint (target); - -CREATE TABLE IF NOT EXISTS `gorgone_centreon_judge_spare` ( - `cluster_name` varchar(2048) NOT NULL, - `status` int(11) NOT NULL, - `data` TEXT DEFAULT NULL -); - -CREATE UNIQUE INDEX IF NOT EXISTS idx_gorgone_centreon_judge_spare_cluster_name ON gorgone_centreon_judge_spare (cluster_name); diff --git a/centreon-gorgone/selinux/centreon-gorgoned.fc b/centreon-gorgone/selinux/centreon-gorgoned.fc deleted file mode 100644 index 5e782b3c86..0000000000 --- a/centreon-gorgone/selinux/centreon-gorgoned.fc +++ /dev/null @@ -1,3 +0,0 @@ -/usr/bin/gorgoned -- gen_context(system_u:object_r:centreon_gorgoned_exec_t,s0) -/etc/centreon-gorgone(/.*)? gen_context(system_u:object_r:centreon_etc_t,s0) -/var/lib/centreon-gorgone(/.*)? gen_context(system_u:object_r:centreon_gorgoned_t,s0) diff --git a/centreon-gorgone/selinux/centreon-gorgoned.if b/centreon-gorgone/selinux/centreon-gorgoned.if deleted file mode 100644 index ba267cf471..0000000000 --- a/centreon-gorgone/selinux/centreon-gorgoned.if +++ /dev/null @@ -1 +0,0 @@ -## Centreon Gorgoned Network monitoring server. diff --git a/centreon-gorgone/selinux/centreon-gorgoned.te b/centreon-gorgone/selinux/centreon-gorgoned.te deleted file mode 100644 index 38cc272697..0000000000 --- a/centreon-gorgone/selinux/centreon-gorgoned.te +++ /dev/null @@ -1,119 +0,0 @@ -policy_module(centreon-gorgoned, @VERSION@) - -######################################## -# -# Declarations -# -require { - type unconfined_t; - type unconfined_service_t; - type useradd_t; - type fs_t; - type kernel_t; - type setroubleshootd_t; - type rpm_script_t; - type setfiles_t; - type unconfined_domain_type; -} - -type centreon_gorgoned_t; -type centreon_gorgoned_exec_t; -init_daemon_domain(centreon_gorgoned_t, centreon_gorgoned_exec_t) - -######################################## -# -# Centreon local policy -# - -allow centreon_gorgoned_t self:process { setpgid signal_perms }; -allow centreon_gorgoned_t self:tcp_socket { accept listen }; -allow centreon_gorgoned_t self:file { read open write getattr read_file_perms relabelto }; -allow centreon_gorgoned_t fs_t:filesystem associate; -allow rpm_script_t centreon_gorgoned_t:dir { getattr search }; - -#============= setroubleshootd_t ============== -allow setroubleshootd_t centreon_gorgoned_t:dir { getattr search }; -allow setroubleshootd_t centreon_gorgoned_t:file getattr; - -#============= unconfined_t ============== -allow unconfined_t centreon_gorgoned_t:dir { getattr setattr relabelfrom relabelto }; -allow unconfined_t centreon_gorgoned_t:file { getattr setattr relabelto rename }; - -#============= unconfined_service_t ============== -allow unconfined_service_t centreon_gorgoned_t:file { create read open write rename getattr setattr ioctl lock unlink }; -allow unconfined_service_t centreon_gorgoned_t:dir { getattr setattr search create write add_name remove_name }; - -#============= useradd_t ============== -allow useradd_t centreon_gorgoned_t:dir { getattr search setattr create write add_name remove_name }; -allow useradd_t centreon_gorgoned_t:file { open write read unlink create setattr getattr ioctl lock }; - -#============= setfiles_t ============== -allow setfiles_t centreon_gorgoned_t:dir relabelto; -allow setfiles_t centreon_gorgoned_t:file relabelto; - -#============= kernel_t ============== -allow kernel_t centreon_gorgoned_t:dir { getattr search setattr create write add_name remove_name }; -allow kernel_t centreon_gorgoned_t:file { open write read unlink create setattr getattr ioctl lock }; - -#============= cluster =============== -allow daemon initrc_transition_domain:fifo_file { ioctl read write getattr lock append }; -allow domain unconfined_domain_type:association recvfrom; -allow domain domain:key { search link }; -allow domain unconfined_domain_type:tcp_socket recvfrom; -allow centreon_gorgoned_t domain:lnk_file { read getattr }; -allow daemon initrc_domain:fd use; -allow centreon_gorgoned_t domain:file { ioctl read getattr lock open }; -allow daemon initrc_domain:process sigchld; -allow domain unconfined_domain_type:peer recv; -allow centreon_gorgoned_t domain:dir { ioctl read getattr lock search open }; -allow daemon initrc_transition_domain:fd use; -allow daemon initrc_domain:fifo_file { ioctl read write getattr lock append }; - -mysql_stream_connect(centreon_gorgoned_t) -mysql_tcp_connect(centreon_gorgoned_t) - -kernel_read_kernel_sysctls(centreon_gorgoned_t) -kernel_read_net_sysctls(centreon_gorgoned_t) -kernel_read_network_state(centreon_gorgoned_t) -kernel_read_system_state(centreon_gorgoned_t) -kernel_request_load_module(centreon_gorgoned_t) - -corecmd_exec_bin(centreon_gorgoned_t) -corecmd_exec_shell(centreon_gorgoned_t) - -corenet_port(centreon_gorgoned_t) -corenet_all_recvfrom_unlabeled(centreon_gorgoned_t) -corenet_all_recvfrom_netlabel(centreon_gorgoned_t) -corenet_tcp_sendrecv_generic_if(centreon_gorgoned_t) -corenet_udp_sendrecv_generic_if(centreon_gorgoned_t) -corenet_tcp_sendrecv_generic_node(centreon_gorgoned_t) -corenet_udp_sendrecv_generic_node(centreon_gorgoned_t) -corenet_tcp_bind_generic_node(centreon_gorgoned_t) -corenet_udp_bind_generic_node(centreon_gorgoned_t) -corenet_sendrecv_all_client_packets(centreon_gorgoned_t) -corenet_tcp_connect_all_ports(centreon_gorgoned_t) -corenet_tcp_sendrecv_all_ports(centreon_gorgoned_t) - -corenet_sendrecv_inetd_child_server_packets(centreon_gorgoned_t) -corenet_tcp_bind_inetd_child_port(centreon_gorgoned_t) -corenet_tcp_sendrecv_inetd_child_port(centreon_gorgoned_t) - -dev_read_sysfs(centreon_gorgoned_t) -dev_read_urand(centreon_gorgoned_t) - -domain_use_interactive_fds(centreon_gorgoned_t) -domain_read_all_domains_state(centreon_gorgoned_t) - -files_read_etc_runtime_files(centreon_gorgoned_t) -files_read_usr_files(centreon_gorgoned_t) - -fs_getattr_all_fs(centreon_gorgoned_t) -fs_search_auto_mountpoints(centreon_gorgoned_t) - -auth_use_nsswitch(centreon_gorgoned_t) - -logging_send_syslog_msg(centreon_gorgoned_t) - -miscfiles_read_localization(centreon_gorgoned_t) - -userdom_dontaudit_use_unpriv_user_fds(centreon_gorgoned_t) \ No newline at end of file diff --git a/centreon-gorgone/tests/robot/config/includer.yaml b/centreon-gorgone/tests/robot/config/includer.yaml deleted file mode 100644 index f1a5cad34b..0000000000 --- a/centreon-gorgone/tests/robot/config/includer.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: config.yaml -description: Configuration of centreon-gorgone. Use config.d directory to change configuration -configuration: !include /etc/centreon-gorgone/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/config.d/*.yaml diff --git a/centreon-gorgone/tests/robot/config/push_central_config.yaml b/centreon-gorgone/tests/robot/config/push_central_config.yaml deleted file mode 100644 index d866027ade..0000000000 --- a/centreon-gorgone/tests/robot/config/push_central_config.yaml +++ /dev/null @@ -1,43 +0,0 @@ -gorgone: - gorgonecore: - internal_com_type: ipc - internal_com_path: /etc/centreon-gorgone/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/routing.ipc - external_com_type: tcp - - gorgone_db_type: SQLite - gorgone_db_name: dbname=/etc/centreon-gorgone/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/history.sdb - id: 1 - privkey: "/var/lib/centreon-gorgone/.keys/rsakey.priv.pem" - pubkey: "/var/lib/centreon-gorgone/.keys/rsakey.pub.pem" - modules: - - name: proxy - package: "gorgone::modules::core::proxy::hooks" - enable: true - - - name: nodes - package: "gorgone::modules::centreon::nodes::hooks" - enable: true - - - name: httpserver - package: "gorgone::modules::core::httpserver::hooks" - enable: true - address: "0.0.0.0" - port: "8085" - ssl: false - auth: - enabled: false - allowed_hosts: - enabled: true - subnets: - - 127.0.0.1/32 - -centreon: - database: - db_configuration: - dsn: "mysql:host=@DBHOST@:port=3306;dbname=@DBNAME@" - username: "@DBUSER@" - password: "@DBPASSWORD@" - db_realtime: - dsn: "mysql:host=@DBHOST@:port=3306;dbname=centreon_storage" - username: "@DBUSER@" - password: "@DBPASSWORD@" diff --git a/centreon-gorgone/tests/robot/config/push_db_1_poller.sql b/centreon-gorgone/tests/robot/config/push_db_1_poller.sql deleted file mode 100644 index e8e3edf699..0000000000 --- a/centreon-gorgone/tests/robot/config/push_db_1_poller.sql +++ /dev/null @@ -1,68 +0,0 @@ -INSERT IGNORE INTO `nagios_server` - VALUES - ( - 1, 'Central', '1', 1, 1711560733, '127.0.0.1', - '1', '0', 'service centengine start', - 'service centengine stop', 'service centengine restart', - 'service centengine reload', '/usr/sbin/centengine', - '/usr/sbin/centenginestats', '/var/log/centreon-engine/service-perfdata', - 'service cbd reload', '/etc/centreon-broker', - '/usr/share/centreon/lib/centreon-broker', - '/usr/lib64/centreon-connector', - 22, '1', 5556, 'centreontrapd', '/etc/snmp/centreon_traps/', - NULL, NULL, NULL, NULL, '1', '0' - ), - ( - 2, 'pushpoller', '0', 0, NULL, '127.0.0.1', - '1', '0', 'service centengine start', - 'service centengine stop', 'service centengine restart', - 'service centengine reload', '/usr/sbin/centengine', - '/usr/sbin/centenginestats', '/var/log/centreon-engine/service-perfdata', - 'service cbd reload', '/etc/centreon-broker', - '/usr/share/centreon/lib/centreon-broker', - '/usr/lib64/centreon-connector', - 22, '1', 5556, 'centreontrapd', '/etc/snmp/centreon_traps/', - NULL, NULL, '/var/log/centreon-broker/', - NULL, '1', '0' - ); -INSERT IGNORE INTO `cfg_nagios` - VALUES - ( - 1, 'Centreon Engine Central', NULL, - '/var/log/centreon-engine/centengine.log', - '/etc/centreon-engine', '/var/log/centreon-engine/status.dat', - 60, '1', '1', '1', '1', '1', '1', '1', - 4096, '1s', '/var/lib/centreon-engine/rw/centengine.cmd', - '1', '/var/log/centreon-engine/retention.dat', - 60, '1', '1', '0', '1', '1', '1', '1', - NULL, '1', '1', NULL, NULL, NULL, 's', - 's', 's', 0, 15, 15, 5, '0', NULL, NULL, - '0', '25.0', '50.0', '25.0', '50.0', - '0', 60, 12, 30, 30, '1', '1', '0', NULL, - NULL, '0', NULL, 'euro', 30, '~!$%^&*\"|\'<>?,()=', - '`~$^&\"|\'<>', '0', '0', 'admin@localhost', - 'admin@localhost', 'Centreon Engine configuration file for a central instance', - '1', '-1', 1, '1', '1', 15, 15, NULL, - '0', 15, '/var/log/centreon-engine/centengine.debug', - 0, '0', '1', 1000000000, 'centengine.cfg', - '1', '0', '', 'log_v2_enabled' - ), - ( - 15, 'pushpoller', NULL, '/var/log/centreon-engine/centengine.log', - '/etc/centreon-engine/', '/var/log/centreon-engine/status.dat', - 60, '1', '1', '1', '1', '1', '1', '1', - 4096, '1s', '/var/lib/centreon-engine/rw/centengine.cmd', - '1', '/var/log/centreon-engine/retention.dat', - 60, '1', '0', '0', '1', '1', '1', '1', - '1', '1', '1', NULL, NULL, '0.5', 's', - 's', 's', 0, 15, 15, 5, '0', 30, 180, '0', - '25.0', '50.0', '25.0', '50.0', '0', - 60, 30, 30, 30, '1', '1', '0', NULL, NULL, - '0', NULL, 'euro', 30, '~!$%^&*\"|\'<>?,()=', - '`~$^&\"|\'<>', '0', '0', 'admin@localhost', - 'admin@localhost', 'Centreon Engine config file for a polling instance', - '1', '-1', 2, '1', '1', 15, 15, NULL, - '0', 15, '/var/log/centreon-engine/centengine.debug', - 0, '0', '1', 1000000000, 'centengine.cfg', - '1', '0', '', 'log_v2_enabled' - ); diff --git a/centreon-gorgone/tests/robot/config/push_db_1_poller_delete.sql b/centreon-gorgone/tests/robot/config/push_db_1_poller_delete.sql deleted file mode 100644 index 69f3b03943..0000000000 --- a/centreon-gorgone/tests/robot/config/push_db_1_poller_delete.sql +++ /dev/null @@ -1,2 +0,0 @@ -delete from cfg_nagios; -delete from nagios_server; \ No newline at end of file diff --git a/centreon-gorgone/tests/robot/config/push_poller_config.yaml b/centreon-gorgone/tests/robot/config/push_poller_config.yaml deleted file mode 100644 index a3487f22db..0000000000 --- a/centreon-gorgone/tests/robot/config/push_poller_config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: gorgoned-pushpoller -description: Configuration for poller pushpoller -gorgone: - gorgonecore: - internal_com_type: ipc - internal_com_path: /etc/centreon-gorgone/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/routing.ipc - gorgone_db_type: SQLite - gorgone_db_name: dbname=/etc/centreon-gorgone/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/history.sdb - id: 2 - external_com_type: tcp - external_com_path: "*:5556" - authorized_clients: - - key:@KEYTHUMBPRINT@ - - privkey: "/var/lib/centreon-gorgone/.keys/rsakey.priv.pem" - pubkey: "/var/lib/centreon-gorgone/.keys/rsakey.pub.pem" - - modules: - - name: action - package: gorgone::modules::core::action::hooks - enable: true diff --git a/centreon-gorgone/tests/robot/resources/import.resource b/centreon-gorgone/tests/robot/resources/import.resource deleted file mode 100644 index 82132fb874..0000000000 --- a/centreon-gorgone/tests/robot/resources/import.resource +++ /dev/null @@ -1,8 +0,0 @@ -*** Settings *** -Documentation This is the documentation for the import resource file. -Library Examples -Library OperatingSystem -Library String -Library Collections -Resource resources.resource -Library DatabaseLibrary diff --git a/centreon-gorgone/tests/robot/resources/resources.resource b/centreon-gorgone/tests/robot/resources/resources.resource deleted file mode 100644 index 91ae77e077..0000000000 --- a/centreon-gorgone/tests/robot/resources/resources.resource +++ /dev/null @@ -1,129 +0,0 @@ -*** Settings *** -Documentation Centreon Gorgone library for Robot Framework - -Library Process -Library RequestsLibrary - -*** Variables *** -${gorgone_binary} /usr/bin/gorgoned -${ROOT_CONFIG} ${CURDIR}${/}..${/}config${/} -${pull_central_config} ${ROOT_CONFIG}pull_central_config.yaml -${pull_poller_config} ${ROOT_CONFIG}pull_poller_config.yaml -${push_central_config} ${ROOT_CONFIG}push_central_config.yaml -${push_poller_config} ${ROOT_CONFIG}push_poller_config.yaml -${DBHOST} 127.0.0.1 -${DBPORT} 3306 -${DBNAME} centreon_gorgone_test -${DBUSER} centreon -${DBPASSWORD} password - -*** Keywords *** -Start Gorgone - [Arguments] ${CONFIG_FILE} ${SEVERITY} ${ALIAS} - ${process} Start Process - ... /usr/bin/perl - ... ${gorgone_binary} - ... --config - ... ${CONFIG_FILE} - ... --logfile - ... /var/log/centreon-gorgone/${ALIAS}/gorgoned.log - ... --severity - ... ${SEVERITY} - ... alias=${ALIAS} - -Stop Gorgone And Remove Gorgone Config - [Documentation] This keyword stops the gorgone process and removes the configuration in the database. Configuration files are not modified as we want them in case something failed to analyse the problem. - [Arguments] @{process_alias} ${sql_file}= - Gorgone Execute Sql ${sql_file} - # remove configuration in db if needed. - - FOR ${process} IN @{process_alias} - ${result} Terminate Process ${process} - BuiltIn.Run Keyword And Continue On Failure Should Be True ${result.rc} == -15 or ${result.rc} == 0 Engine badly stopped alias = ${process_alias} - code returned ${result.rc}. - END - -Gorgone Execute Sql - [Arguments] ${sql_file} - ${length} Get Length ${sql_file} - IF ${length} > 0 - Connect To Database pymysql ${DBNAME} ${DBUSER} ${DBPASSWORD} ${DBHOST} ${DBPORT} - Log To Console Executing sql file ${sql_file} - Execute SQL Script ${sql_file} - END - -Setup Gorgone Config - [Arguments] ${gorgone_name} @{file_list} ${sql_file}= - Gorgone Execute Sql ${sql_file} - Create Directory /var/log/centreon-gorgone/${gorgone_name}/ - Copy File ${CURDIR}${/}..${/}config${/}includer.yaml /etc/centreon-gorgone/${gorgone_name}/includer.yaml - - FOR ${file} IN @{file_list} - Copy File ${file} /etc/centreon-gorgone/${gorgone_name}/config.d/ - END - ${key_thumbprint} Run perl /usr/local/bin/gorgone_key_thumbprint.pl --key-path=/var/lib/centreon-gorgone/.keys/rsakey.priv.pem | cut -d: -f4 - - ${result} Run sed -i -e 's/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/${gorgone_name}/g' /etc/centreon-gorgone/${gorgone_name}/includer.yaml - - ${CMD} Catenate - ... sed -i -e 's/@KEYTHUMBPRINT@/${key_thumbprint}/g' - ... -e 's/@DBNAME@/${DBNAME}/g' - ... -e 's/@DBHOST@/${DBHOST}/g' - ... -e 's/@DBPASSWORD@/${DBPASSWORD}/g' - ... -e 's/@DBUSER@/${DBUSER}/g' - ... -e 's/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/${gorgone_name}/g' - ... /etc/centreon-gorgone/${gorgone_name}/config.d/*.yaml - - ${result2} Run ${CMD} - -Check Poller Is Connected - [Arguments] ${port}= ${expected_nb}= - Log To Console checking TCP connection is established... - FOR ${i} IN RANGE 40 - Sleep 4 - ${nb_socket_connexion} Run ss -tnp | grep ':${port}' | grep ESTAB | wc -l - IF ${expected_nb} == ${nb_socket_connexion} - BREAK - END - END - Log To Console TCP connection establishing after ${i} attempt - Should Be True ${i} < 39 Gorgone did not establish tcp connection in 160 seconds. - Log To Console TCP connection established after ${i} attempt (4 seconds each) - -Check Poller Communicate - [Documentation] Ask the central Gorgone rest api if it have communicated with the poller using a given ID. - [Arguments] ${poller_id} - ${response} Set Variable ${EMPTY} - Log To Console checking Gorgone see poller in rest api response... - FOR ${i} IN RANGE 10 - Sleep 5 - ${response}= GET http://127.0.0.1:8085/api/internal/constatus - Log ${response.json()} - IF ${response.json()}[data][${poller_id}][ping_failed] > 0 or ${response.json()}[data][${poller_id}][ping_ok] > 0 - BREAK - END - END - Log To Console json response : ${response.json()} - Should Be True ${i} < 9 timeout waiting for poller status in gorgone rest api (/api/internal/constatus) : ${response.json()} - Should Be True 0 == ${response.json()}[data][${poller_id}][ping_failed] there was failed ping between the central and the poller ${poller_id} - Should Be True 0 < ${response.json()}[data][${poller_id}][ping_ok] there was no successful ping between the central and the poller ${poller_id} - -Setup Two Gorgone Instances - [Arguments] ${communication_mode}=push_zmq ${central_name}=gorgone_central ${poller_name}=gorgone_poller_2 - - ${result} Run perl /usr/local/bin/gorgone_key_generation.pl - # generate key if there is none. - # gorgone can generate it's own key, but as we need the thumbprint in the configuration we need to generate them before launching gorgone. - # this script only create key if the files don't exists, and silently finish if the files already exists. - IF '${communication_mode}' == 'push_zmq' - Setup Gorgone Config ${central_name} ${push_central_config} sql_file=${ROOT_CONFIG}push_db_1_poller.sql - Setup Gorgone Config ${poller_name} ${push_poller_config} - - Start Gorgone /etc/centreon-gorgone/gorgone_central/includer.yaml debug ${central_name} - Start Gorgone /etc/centreon-gorgone/gorgone_poller_2/includer.yaml debug ${poller_name} - - Check Poller Is Connected port=5556 expected_nb=2 - Check Poller Communicate 2 - ELSE - Fail pull and pullwss mode are not yet implemented. - END - diff --git a/centreon-gorgone/tests/robot/tests/core/httpserver.robot b/centreon-gorgone/tests/robot/tests/core/httpserver.robot deleted file mode 100644 index 53d2e61d16..0000000000 --- a/centreon-gorgone/tests/robot/tests/core/httpserver.robot +++ /dev/null @@ -1,52 +0,0 @@ -*** Settings *** -Documentation check gorgone api response -Suite Setup Setup Gorgone -Suite Teardown Stop Gorgone And Remove Gorgone Config httpserver_api_statuscode -Resource ${CURDIR}${/}..${/}..${/}resources${/}import.resource -Test Timeout 220s - -*** Variables *** - - -*** Test Cases *** -check http api get status code ${tc} - ${expected_code}= Convert To Integer ${http_status_code} - ${api_response}= GET http://127.0.0.1:8085${endpoint} expected_status=anything - - Log To Console \nendpoint code is : ${api_response.status_code} output is : ${api_response.text} - - Should Be Equal ${api_response.status_code} ${expected_code} - ${expected_json}= evaluate json.loads('''${expected_response}''') json - Dictionaries Should Be Equal ${api_response.json()} ${expected_json} - - Examples: tc http_status_code endpoint expected_response -- - ... forbidden 403 /bad/endpoint {"error":"http_error_403","message":"forbidden"} - ... constatus Ok 200 /api/internal/constatus {"data":{},"action":"constatus","message":"ok"} - ... method not found 404 /api/internal/wrongendpoint {"error":"method_unknown","message":"Method not implemented"} - -check http api post api ${tc} - ${expected_code}= Convert To Integer ${http_status_code} - ${api_response}= POST http://127.0.0.1:8085${endpoint} expected_status=anything data=${body} - - Log To Console \nendpoint code is : ${api_response.status_code} output is : ${api_response.text} - - Should Be Equal ${api_response.status_code} ${expected_code} - IF len("""${expected_response}""") > 0 - ${expected}= evaluate json.loads('''${expected_response}''') json - Dictionaries Should Be Equal ${api_response.json()} ${expected} - END - - Examples: tc http_status_code endpoint body expected_response -- - ... body is not json 400 /api/centreon/nodes/sync { {"error":"decode_error","message":"POST content must be JSON-formated"} - ... body is valid json 200 /api/centreon/nodes/sync {} ${EMPTY} # api send back a random token. - - -*** Keywords *** - -Setup Gorgone - Setup Gorgone Config httpserver_api_statuscode ${push_central_config} - Start Gorgone /etc/centreon-gorgone/httpserver_api_statuscode/includer.yaml debug httpserver_api_statuscode - - Log To Console \nGorgone Started. We have to wait for it to be ready to respond. - Sleep 10 - Log To Console Gorgone should be ready. \n \ No newline at end of file diff --git a/centreon-gorgone/tests/robot/tests/core/push.robot b/centreon-gorgone/tests/robot/tests/core/push.robot deleted file mode 100644 index 7ddb758c90..0000000000 --- a/centreon-gorgone/tests/robot/tests/core/push.robot +++ /dev/null @@ -1,16 +0,0 @@ -*** Settings *** -Documentation Start and stop gorgone - -Resource ${CURDIR}${/}..${/}..${/}resources${/}import.resource -Test Timeout 220s - -*** Variables *** -@{process_list} gorgone_central gorgone_poller_2 - -*** Test Cases *** -connect 1 poller to a central - [Teardown] Stop Gorgone And Remove Gorgone Config @{process_list} sql_file=${ROOT_CONFIG}push_db_1_poller_delete.sql - - Log To Console \nStarting the gorgone setup - Setup Two Gorgone Instances push_zmq - Log To Console End of tests. diff --git a/centreon-gorgone/tests/robot/tests/start_stop/config.yaml b/centreon-gorgone/tests/robot/tests/start_stop/config.yaml deleted file mode 100644 index c35b99ed70..0000000000 --- a/centreon-gorgone/tests/robot/tests/start_stop/config.yaml +++ /dev/null @@ -1,34 +0,0 @@ -gorgone: - gorgonecore: - internal_com_type: ipc - internal_com_path: /etc/centreon-gorgone/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/routing.ipc - external_com_type: tcp - - gorgone_db_type: SQLite - gorgone_db_name: dbname=/etc/centreon-gorgone/@UNIQ_ID_FROM_ROBOT_TESTING_CONFIG_FILE@/history.sdb - id: 1 - privkey: "/var/lib/centreon-gorgone/.keys/rsakey.priv.pem" - pubkey: "/var/lib/centreon-gorgone/.keys/rsakey.pub.pem" - modules: - - name: httpserver - package: "gorgone::modules::core::httpserver::hooks" - enable: true - address: "0.0.0.0" - port: "8085" - ssl: false - auth: - enabled: false - allowed_hosts: - enabled: true - subnets: - - 127.0.0.1/32 -centreon: - database: - db_configuration: - dsn: "mysql:host=@DBHOST@:port=3306;dbname=@DBNAME@" - username: "@DBUSER@" - password: "@DBPASSWORD@" - db_realtime: - dsn: "mysql:host=@DBHOST@:port=3306;dbname=centreon_storage" - username: "@DBUSER@" - password: "@DBPASSWORD@" diff --git a/centreon-gorgone/tests/robot/tests/start_stop/start_stop.robot b/centreon-gorgone/tests/robot/tests/start_stop/start_stop.robot deleted file mode 100644 index 08ddb9b6f0..0000000000 --- a/centreon-gorgone/tests/robot/tests/start_stop/start_stop.robot +++ /dev/null @@ -1,19 +0,0 @@ -*** Settings *** -Documentation Start and stop gorgone - -Resource ${CURDIR}${/}..${/}..${/}resources${/}import.resource -Test Timeout 120s - -*** Test Cases *** -Start and stop gorgone - # fichier de conf : pull_central + autodiscovery - # start gorgone 2 - FOR ${i} IN RANGE 5 - Setup Gorgone Config gorgone_start_stop${i} ${CURDIR}${/}config.yaml - Log To Console Starting Gorgone... - Start Gorgone /etc/centreon-gorgone/gorgone_start_stop${i}/includer.yaml debug gorgone_start_stop${i} - Sleep 5s - Log To Console Stopping Gorgone... - Stop Gorgone And Remove Gorgone Config gorgone_start_stop${i} - sleep 2s - END \ No newline at end of file diff --git a/centreon-gorgone/veracode.json b/centreon-gorgone/veracode.json deleted file mode 100644 index 329f76f89b..0000000000 --- a/centreon-gorgone/veracode.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "ignorethirdparty": "false" -} \ No newline at end of file diff --git a/centreon-ha/.env b/centreon-ha/.env index c294ad713b..3a705d94dc 100644 --- a/centreon-ha/.env +++ b/centreon-ha/.env @@ -1 +1 @@ -VERSION=24.05.0 +VERSION=24.07.0 diff --git a/centreon-ha/CHANGELOG.md b/centreon-ha/CHANGELOG.md index 975710c830..0c93b1a7b7 100644 --- a/centreon-ha/CHANGELOG.md +++ b/centreon-ha/CHANGELOG.md @@ -13,3 +13,7 @@ ## [24.04.0] - _2023-10-31_ ## [24.05.0] - _2024-04-12_ + +## [24.07.0] - _2024-06-28_ + +## [24.09.0] - _2024-08-27_ diff --git a/centreon-ha/packaging/centreon-ha.spectemplate b/centreon-ha/packaging/centreon-ha.spectemplate index 40f8837efd..7325bd577f 100644 --- a/centreon-ha/packaging/centreon-ha.spectemplate +++ b/centreon-ha/packaging/centreon-ha.spectemplate @@ -2,7 +2,7 @@ %define debug_package %{nil} %define version %{PACKAGE_VERSION} %define release %{PACKAGE_RELEASE}%{?dist} -%define thismajor 24.05.0 +%define thismajor 24.09.0 %define nextmajor 24.10.0 Name: %{name} @@ -140,4 +140,4 @@ This add-on is built to manage a failover solution for Centreon. %clean -rm -rf %buildroot \ No newline at end of file +rm -rf %buildroot diff --git a/centreon-open-tickets/.php-cs-fixer.dist.php b/centreon-open-tickets/.php-cs-fixer.dist.php new file mode 100644 index 0000000000..24cdb3ffd6 --- /dev/null +++ b/centreon-open-tickets/.php-cs-fixer.dist.php @@ -0,0 +1,41 @@ +in([ + __DIR__ . '/src/CentreonOpenTickets', + ]); + +/** + * These rules have various risky rune like 'declare_strict_types' which may be dangerous on legacy code. + * 👉️ We use the other php-cs-fixer config file for this legacy code. + * + * @see .php-cs-fixer.unstrict.php + */ +return (new Config()) + ->setFinder($finder) + ->setRiskyAllowed(true) + ->setRules(PhpCsFixerRuleSet::getRules()); diff --git a/centreon-open-tickets/.php-cs-fixer.unstrict.php b/centreon-open-tickets/.php-cs-fixer.unstrict.php new file mode 100644 index 0000000000..5537b17843 --- /dev/null +++ b/centreon-open-tickets/.php-cs-fixer.unstrict.php @@ -0,0 +1,41 @@ +in([ + __DIR__ . '/src/CentreonOpenTickets', + ]); + +/** + * These rules have various risky rune like 'declare_strict_types' which may be dangerous on legacy code. + * 👉️ We use the other php-cs-fixer config file for this legacy code. + * + * @see .php-cs-fixer.dist.php + */ +return (new Config()) + ->setFinder($finder) + ->setRiskyAllowed(false) // 👈 risky NOT allowed + ->setRules(PhpCsFixerRuleSet::getRulesSafe()); diff --git a/centreon-open-tickets/composer.json b/centreon-open-tickets/composer.json index 6f5dbee60b..2eeac54e4b 100644 --- a/centreon-open-tickets/composer.json +++ b/centreon-open-tickets/composer.json @@ -1,32 +1,53 @@ { - "name": "centreon/centreon-open-tickets", - "description": "Module dedicated to open case on various Ticket systems", - "version": "23.04.0", - "type": "project", - "license": "GPL-2.0-only", - "scripts": { - "codestyle": "phpcs --extensions=php --standard=./ruleset.xml ./", - "codestyle:ci": "@codestyle --report=checkstyle --report-file=./build/checkstyle.xml --no-cache" - }, - "repositories": [{ - "type": "path", - "url": "../centreon" - }], - "require": { - "centreon/centreon": "dev-develop" - }, - "require-dev": { - "phpunit/phpunit": "^8.5", - "squizlabs/php_codesniffer": "^3.6", - "phpstan/phpstan": "^1.10" - }, - "config": { - "secure-http": false, - "platform": { - "php": "8.1" + "name": "centreon/centreon-open-tickets", + "description": "Module dedicated to open case on various Ticket systems", + "version": "24.10.0", + "type": "project", + "license": "GPL-2.0-only", + "keywords": [ + "centreon", + "centreon-open-tickets" + ], + "scripts": { + "test": "pest", + "test:ci": "@test --log-junit ./build/phpunit.xml --coverage-clover ./build/coverage.xml --no-interaction --do-not-cache-result", + "codestyle": "phpcs --standard=./ruleset.xml ./", + "codestyle:ci": "@codestyle --report=checkstyle --report-file=./build/checkstyle.xml --no-cache", + "phpstan": "phpstan analyse -c phpstan.neon --level 6 --memory-limit=512M", + "phpstan:ci": "@phpstan --error-format=checkstyle --no-interaction --no-progress" }, - "allow-plugins": { - "symfony/flex": false + "repositories": [{ + "type": "path", + "url": "../centreon" + }], + "require": { + "centreon/centreon": "dev-develop", + "ext-openssl": "*", + "ext-json": "*" + }, + "require-dev": { + "beberlei/assert": "^3.3", + "centreon/centreon-test-lib": "dev-master", + "phpstan/phpstan": "^1.3.0", + "phpstan/phpstan-beberlei-assert": "^1.0.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/console": "6.4.*", + "pestphp/pest": "^1.21" + }, + "autoload": { + "psr-4": { + "CentreonOpenTickets\\": "src/CentreonOpenTickets", + "Tests\\": "tests/php/" + } + }, + "config": { + "secure-http": false, + "platform": { + "php": "8.1" + }, + "allow-plugins": { + "symfony/flex": false, + "pestphp/pest-plugin": true + } } - } } diff --git a/centreon-open-tickets/composer.lock b/centreon-open-tickets/composer.lock index 8a0099a033..5a8032d03a 100644 --- a/centreon-open-tickets/composer.lock +++ b/centreon-open-tickets/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6f7ad207db507f50cc75955999fb966b", + "content-hash": "c719e154ec5a24337bb40def020c4cef", "packages": [ { "name": "beberlei/assert", @@ -79,7 +79,7 @@ "dist": { "type": "path", "url": "../centreon", - "reference": "4a1d48aa72462c83322a69980e6ddc4a803dd31c" + "reference": "97e0b42f57a88f485576aba2c2cada827e6fcc8e" }, "require": { "beberlei/assert": "^3.3", @@ -94,8 +94,9 @@ "ext-phar": "*", "ext-zip": "*", "friendsofsymfony/rest-bundle": "^3.0", - "jms/serializer-bundle": "^4.0", + "jms/serializer-bundle": "^5.4", "justinrainbow/json-schema": "^5.2", + "monolog/monolog": "^3.3", "nelmio/cors-bundle": "^2.1", "onelogin/php-saml": "^4.1", "openpsa/quickform": "3.3.*", @@ -106,36 +107,36 @@ "sensio/framework-extra-bundle": "^6.2", "smarty-gettext/smarty-gettext": "^1.6", "smarty/smarty": "^v4.3", - "symfony/config": "5.4.*", - "symfony/console": "5.4.*", - "symfony/dependency-injection": "5.4.*", - "symfony/dotenv": "5.4.*", - "symfony/error-handler": "5.4.*", - "symfony/event-dispatcher": "5.4.*", - "symfony/event-dispatcher-contracts": "2.5.*", - "symfony/expression-language": "5.4.*", - "symfony/filesystem": "5.4.*", - "symfony/finder": "5.4.*", - "symfony/flex": "^1.17", - "symfony/framework-bundle": "5.4.*", - "symfony/http-client": "5.4.*", - "symfony/http-foundation": "5.4.*", - "symfony/http-kernel": "5.4.*", - "symfony/lock": "5.4.*", - "symfony/maker-bundle": "^1.11", - "symfony/mime": "^6.1", - "symfony/monolog-bundle": "^3.7", - "symfony/options-resolver": "5.4.*", - "symfony/property-access": "5.4.*", - "symfony/property-info": "5.4.*", - "symfony/routing": "5.4.*", - "symfony/security-bundle": "5.4.*", - "symfony/serializer": "5.4.*", - "symfony/string": "5.4.*", - "symfony/translation": "5.4.*", - "symfony/uid": "^6.2", - "symfony/validator": "5.4.*", - "symfony/yaml": "5.4.*" + "symfony/config": "6.4.*", + "symfony/console": "6.4.*", + "symfony/dependency-injection": "6.4.*", + "symfony/dotenv": "6.4.*", + "symfony/error-handler": "6.4.*", + "symfony/event-dispatcher": "6.4.*", + "symfony/event-dispatcher-contracts": "3.4.*", + "symfony/expression-language": "6.4.*", + "symfony/filesystem": "6.4.*", + "symfony/finder": "6.4.*", + "symfony/flex": "2.4.*", + "symfony/framework-bundle": "6.4.*", + "symfony/http-client": "6.4.*", + "symfony/http-foundation": "6.4.*", + "symfony/http-kernel": "6.4.*", + "symfony/lock": "6.4.*", + "symfony/maker-bundle": "^1.56", + "symfony/mime": "6.4.*", + "symfony/monolog-bundle": "^3.10", + "symfony/options-resolver": "6.4.*", + "symfony/property-access": "6.4.*", + "symfony/property-info": "6.4.*", + "symfony/routing": "6.4.*", + "symfony/security-bundle": "6.4.*", + "symfony/serializer": "6.4.*", + "symfony/string": "6.4.*", + "symfony/translation": "6.4.*", + "symfony/uid": "6.4.*", + "symfony/validator": "6.4.*", + "symfony/yaml": "6.4.*" }, "conflict": { "symfony/symfony": "*" @@ -150,22 +151,23 @@ }, "require-dev": { "behat/behat": "^3.10", - "behat/mink-selenium2-driver": "^1.5", + "behat/mink-selenium2-driver": "1.6.*", "centreon/centreon-test-lib": "dev-master", "friends-of-behat/mink": "^1.9", "friends-of-behat/mink-extension": "^2.5", "friendsofphp/php-cs-fixer": "^3.10", - "pestphp/pest": "^1.21", + "pestphp/pest": "^1.9", "php-vfs/php-vfs": "^1.4", "phpstan/phpstan": "^1.3.0", "phpstan/phpstan-beberlei-assert": "^1.0.0", + "rector/rector": "^1.0", "robertfausk/mink-panther-driver": "^1.1", "squizlabs/php_codesniffer": "3.6.2", - "symfony/phpunit-bridge": "6.0.*", - "symfony/stopwatch": "^5.4", - "symfony/twig-bundle": "^5.4", - "symfony/var-dumper": "5.4.*", - "symfony/web-profiler-bundle": "^5.4", + "symfony/phpunit-bridge": "6.4.*", + "symfony/stopwatch": "6.4.*", + "symfony/twig-bundle": "6.4.*", + "symfony/var-dumper": "6.4.*", + "symfony/web-profiler-bundle": "6.4.*", "twig/twig": "^3.3", "webmozart/assert": "^1.8", "zircote/swagger-php": "^4.0" @@ -174,7 +176,7 @@ "extra": { "symfony": { "allow-contrib": true, - "require": "5.4.*" + "require": "6.4.*" } }, "autoload": { @@ -380,16 +382,16 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "shasum": "" }, "require": { @@ -421,22 +423,22 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.2" + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" }, - "time": "2023-09-27T20:04:15+00:00" + "time": "2024-01-30T19:34:25+00:00" }, { "name": "doctrine/inflector", - "version": "2.0.8", + "version": "2.0.10", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff" + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff", - "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", "shasum": "" }, "require": { @@ -498,7 +500,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.8" + "source": "https://github.com/doctrine/inflector/tree/2.0.10" }, "funding": [ { @@ -514,34 +516,34 @@ "type": "tidelift" } ], - "time": "2023-06-16T13:40:37+00:00" + "time": "2024-02-18T20:23:39+00:00" }, { "name": "doctrine/instantiator", - "version": "1.5.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^11", + "doctrine/coding-standard": "^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.30 || ^5.4" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { @@ -568,7 +570,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { @@ -584,20 +586,20 @@ "type": "tidelift" } ], - "time": "2022-12-30T00:15:36+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "doctrine/lexer", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + "reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6", + "reference": "861c870e8b75f7c8f69c146c7f89cc1c0f1b49b6", "shasum": "" }, "require": { @@ -605,11 +607,11 @@ "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^10", + "doctrine/coding-standard": "^9 || ^12", "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" + "vimeo/psalm": "^4.11 || ^5.21" }, "type": "library", "autoload": { @@ -646,7 +648,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/2.1.0" + "source": "https://github.com/doctrine/lexer/tree/2.1.1" }, "funding": [ { @@ -662,7 +664,7 @@ "type": "tidelift" } ], - "time": "2022-12-14T08:49:07+00:00" + "time": "2024-02-05T11:35:39+00:00" }, { "name": "dragonmantank/cron-expression", @@ -772,28 +774,29 @@ }, { "name": "friendsofsymfony/rest-bundle", - "version": "3.6.0", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSRestBundle.git", - "reference": "e01be8113d4451adb3cbb29d7d2cc96bbc698179" + "reference": "db7d9a17da2bcae1bb8e2d7ff320ef3915903373" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/e01be8113d4451adb3cbb29d7d2cc96bbc698179", - "reference": "e01be8113d4451adb3cbb29d7d2cc96bbc698179", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/db7d9a17da2bcae1bb8e2d7ff320ef3915903373", + "reference": "db7d9a17da2bcae1bb8e2d7ff320ef3915903373", "shasum": "" }, "require": { - "php": "^7.2|^8.0", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/framework-bundle": "^4.4.1|^5.0|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/routing": "^5.4|^6.0", - "symfony/security-core": "^5.4|^6.0", + "php": "^7.4|^8.0", + "symfony/config": "^5.4|^6.4|^7.0", + "symfony/dependency-injection": "^5.4|^6.4|^7.0", + "symfony/deprecation-contracts": "^2.1|^3.0", + "symfony/event-dispatcher": "^5.4|^6.4|^7.0", + "symfony/framework-bundle": "^5.4|^6.4|^7.0", + "symfony/http-foundation": "^5.4|^6.4|^7.0", + "symfony/http-kernel": "^5.4|^6.4|^7.0", + "symfony/routing": "^5.4|^6.4|^7.0", + "symfony/security-core": "^5.4|^6.4|^7.0", "willdurand/jsonp-callback-validator": "^1.0|^2.0", "willdurand/negotiation": "^2.0|^3.0" }, @@ -804,32 +807,32 @@ "sensio/framework-extra-bundle": "<6.1" }, "require-dev": { - "doctrine/annotations": "^1.13.2|^2.0 ", - "friendsofphp/php-cs-fixer": "^3.0", + "doctrine/annotations": "^1.13.2|^2.0", + "friendsofphp/php-cs-fixer": "^3.43", "jms/serializer": "^1.13|^2.0|^3.0", "jms/serializer-bundle": "^2.4.3|^3.0.1|^4.0|^5.0", "psr/http-message": "^1.0", "psr/log": "^1.0|^2.0|^3.0", "sensio/framework-extra-bundle": "^6.1", - "symfony/asset": "^5.4|^6.0", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/css-selector": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", - "symfony/phpunit-bridge": "^5.4|^6.0", - "symfony/security-bundle": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0", - "symfony/twig-bundle": "^5.4|^6.0", - "symfony/validator": "^5.4|^6.0", - "symfony/web-profiler-bundle": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" + "symfony/asset": "^5.4|^6.4|^7.0", + "symfony/browser-kit": "^5.4|^6.4|^7.0", + "symfony/css-selector": "^5.4|^6.4|^7.0", + "symfony/expression-language": "^5.4|^6.4|^7.0", + "symfony/form": "^5.4|^6.4|^7.0", + "symfony/mime": "^5.4|^6.4|^7.0", + "symfony/phpunit-bridge": "^7.0.1", + "symfony/security-bundle": "^5.4|^6.4|^7.0", + "symfony/serializer": "^5.4|^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.4|^7.0", + "symfony/validator": "^5.4|^6.4|^7.0", + "symfony/web-profiler-bundle": "^5.4|^6.4|^7.0", + "symfony/yaml": "^5.4|^6.4|^7.0" }, "suggest": { - "jms/serializer-bundle": "Add support for advanced serialization capabilities, recommended, requires ^2.0|^3.0", - "sensio/framework-extra-bundle": "Add support for the request body converter and the view response listener, requires ^3.0", - "symfony/serializer": "Add support for basic serialization capabilities and xml decoding, requires ^2.7|^3.0", - "symfony/validator": "Add support for validation capabilities in the ParamFetcher, requires ^2.7|^3.0" + "jms/serializer-bundle": "Add support for advanced serialization capabilities, recommended", + "sensio/framework-extra-bundle": "Add support for the request body converter and the view response listener, not supported with Symfony >=7.0", + "symfony/serializer": "Add support for basic serialization capabilities and xml decoding", + "symfony/validator": "Add support for validation capabilities in the ParamFetcher" }, "type": "symfony-bundle", "extra": { @@ -871,9 +874,9 @@ ], "support": { "issues": "https://github.com/FriendsOfSymfony/FOSRestBundle/issues", - "source": "https://github.com/FriendsOfSymfony/FOSRestBundle/tree/3.6.0" + "source": "https://github.com/FriendsOfSymfony/FOSRestBundle/tree/3.7.1" }, - "time": "2023-09-27T11:41:02+00:00" + "time": "2024-04-12T22:57:10+00:00" }, { "name": "jms/metadata", @@ -941,27 +944,27 @@ }, { "name": "jms/serializer", - "version": "3.29.1", + "version": "3.30.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "111451f43abb448ce297361a8ab96a9591e848cd" + "reference": "bf1105358123d7c02ee6cad08ea33ab535a09d5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/111451f43abb448ce297361a8ab96a9591e848cd", - "reference": "111451f43abb448ce297361a8ab96a9591e848cd", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/bf1105358123d7c02ee6cad08ea33ab535a09d5e", + "reference": "bf1105358123d7c02ee6cad08ea33ab535a09d5e", "shasum": "" }, "require": { - "doctrine/annotations": "^1.14 || ^2.0", "doctrine/instantiator": "^1.3.1 || ^2.0", "doctrine/lexer": "^2.0 || ^3.0", "jms/metadata": "^2.6", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpstan/phpdoc-parser": "^1.20" }, "require-dev": { + "doctrine/annotations": "^1.14 || ^2.0", "doctrine/coding-standard": "^12.0", "doctrine/orm": "^2.14 || ^3.0", "doctrine/persistence": "^2.5.2 || ^3.0", @@ -971,16 +974,17 @@ "ocramius/proxy-manager": "^1.0 || ^2.0", "phpbench/phpbench": "^1.0", "phpstan/phpstan": "^1.0.2", - "phpunit/phpunit": "^8.5.21 || ^9.0 || ^10.0", + "phpunit/phpunit": "^9.0 || ^10.0", "psr/container": "^1.0 || ^2.0", - "symfony/dependency-injection": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/expression-language": "^3.2 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/filesystem": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "symfony/form": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/translation": "^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/uid": "^5.1 || ^6.0 || ^7.0", - "symfony/validator": "^3.1.9 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0", + "rector/rector": "^0.19.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/expression-language": "^5.4 || ^6.0 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", + "symfony/form": "^5.4 || ^6.0 || ^7.0", + "symfony/translation": "^5.4 || ^6.0 || ^7.0", + "symfony/uid": "^5.4 || ^6.0 || ^7.0", + "symfony/validator": "^5.4 || ^6.0 || ^7.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0", "twig/twig": "^1.34 || ^2.4 || ^3.0" }, "suggest": { @@ -1025,7 +1029,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.29.1" + "source": "https://github.com/schmittjoh/serializer/tree/3.30.0" }, "funding": [ { @@ -1033,52 +1037,52 @@ "type": "github" } ], - "time": "2023-12-14T15:25:09+00:00" + "time": "2024-02-24T14:12:14+00:00" }, { "name": "jms/serializer-bundle", - "version": "4.2.0", + "version": "5.4.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/JMSSerializerBundle.git", - "reference": "d402554c66442ba494af7a37e3e43fc0f24e2689" + "reference": "6fa2dd0083e00fe21c5da171556d7ecabc14b437" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/d402554c66442ba494af7a37e3e43fc0f24e2689", - "reference": "d402554c66442ba494af7a37e3e43fc0f24e2689", + "url": "https://api.github.com/repos/schmittjoh/JMSSerializerBundle/zipball/6fa2dd0083e00fe21c5da171556d7ecabc14b437", + "reference": "6fa2dd0083e00fe21c5da171556d7ecabc14b437", "shasum": "" }, "require": { - "jms/metadata": "^2.5", - "jms/serializer": "^3.18", - "php": "^7.2 || ^8.0", - "symfony/dependency-injection": "^3.4 || ^4.0 || ^5.0 || ^6.0", - "symfony/framework-bundle": "^3.0 || ^4.0 || ^5.0 || ^6.0" + "jms/metadata": "^2.6", + "jms/serializer": "^3.28", + "php": "^7.4 || ^8.0", + "symfony/config": "^5.4 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { "doctrine/coding-standard": "^8.1", - "doctrine/orm": "^2.4", + "doctrine/orm": "^2.14", "phpunit/phpunit": "^8.0 || ^9.0", - "symfony/expression-language": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/finder": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/form": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/templating": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/twig-bundle": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/uid": "^5.1 || ^6.0", - "symfony/validator": "^3.0 || ^4.0 || ^5.0 || ^6.0", - "symfony/yaml": "^3.0 || ^4.0 || ^5.0 || ^6.0" + "symfony/expression-language": "^5.4 || ^6.0 || ^7.0", + "symfony/finder": "^5.4 || ^6.0 || ^7.0", + "symfony/form": "^5.4 || ^6.0 || ^7.0", + "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0", + "symfony/templating": "^5.4 || ^6.0", + "symfony/twig-bundle": "^5.4 || ^6.0 || ^7.0", + "symfony/uid": "^5.4 || ^6.0 || ^7.0", + "symfony/validator": "^5.4 || ^6.0 || ^7.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "suggest": { - "jms/di-extra-bundle": "Required to get lazy loading (de)serialization visitors, ^1.3", - "symfony/expression-language": "Required for opcache preloading, ^3.0 || ^4.0 || ^5.0", - "symfony/finder": "Required for cache warmup, supported versions ^3.0|^4.0" + "symfony/expression-language": "Required for opcache preloading ^5.4 || ^6.0 || ^7.0", + "symfony/finder": "Required for cache warmup, supported versions ^5.4 || ^6.0 || ^7.0" }, "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -1113,7 +1117,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/JMSSerializerBundle/issues", - "source": "https://github.com/schmittjoh/JMSSerializerBundle/tree/4.2.0" + "source": "https://github.com/schmittjoh/JMSSerializerBundle/tree/5.4.0" }, "funding": [ { @@ -1121,19 +1125,19 @@ "type": "github" } ], - "time": "2022-09-13T19:27:18+00:00" + "time": "2023-12-12T15:33:15+00:00" }, { "name": "justinrainbow/json-schema", "version": "v5.2.13", "source": { "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", + "url": "https://github.com/jsonrainbow/json-schema.git", "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", "shasum": "" }, @@ -1188,49 +1192,48 @@ "schema" ], "support": { - "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/v5.2.13" + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/v5.2.13" }, "time": "2023-09-26T02:20:38+00:00" }, { "name": "monolog/monolog", - "version": "2.9.2", + "version": "3.7.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f" + "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/437cb3628f4cf6042cc10ae97fc2b8472e48ca1f", - "reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f4393b648b78a5408747de94fca38beb5f7e9ef8", + "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8", "shasum": "" }, "require": { - "php": ">=7.2", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + "psr/log-implementation": "3.0.0" }, "require-dev": { - "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "aws/aws-sdk-php": "^3.0", "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7 || ^8", "ext-json": "*", - "graylog2/gelf-php": "^1.4.2 || ^2@dev", - "guzzlehttp/guzzle": "^7.4", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpspec/prophecy": "^1.15", - "phpstan/phpstan": "^0.12.91", - "phpunit/phpunit": "^8.5.14", - "predis/predis": "^1.1 || ^2.0", - "rollbar/rollbar": "^1.3 || ^2 || ^3", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.4", + "phpunit/phpunit": "^10.5.17", + "predis/predis": "^1.1 || ^2", "ruflin/elastica": "^7", - "swiftmailer/swiftmailer": "^5.3|^6.0", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" }, @@ -1253,7 +1256,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.x-dev" + "dev-main": "3.x-dev" } }, "autoload": { @@ -1281,7 +1284,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.9.2" + "source": "https://github.com/Seldaek/monolog/tree/3.7.0" }, "funding": [ { @@ -1293,20 +1296,20 @@ "type": "tidelift" } ], - "time": "2023-10-27T15:25:26+00:00" + "time": "2024-06-28T09:40:51+00:00" }, { "name": "nelmio/cors-bundle", - "version": "2.4.0", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/nelmio/NelmioCorsBundle.git", - "reference": "78fcdb91f76b080a1008133def9c7f613833933d" + "reference": "3a526fe025cd20e04a6a11370cf5ab28dbb5a544" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/78fcdb91f76b080a1008133def9c7f613833933d", - "reference": "78fcdb91f76b080a1008133def9c7f613833933d", + "url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/3a526fe025cd20e04a6a11370cf5ab28dbb5a544", + "reference": "3a526fe025cd20e04a6a11370cf5ab28dbb5a544", "shasum": "" }, "require": { @@ -1353,31 +1356,33 @@ ], "support": { "issues": "https://github.com/nelmio/NelmioCorsBundle/issues", - "source": "https://github.com/nelmio/NelmioCorsBundle/tree/2.4.0" + "source": "https://github.com/nelmio/NelmioCorsBundle/tree/2.5.0" }, - "time": "2023-11-30T16:41:19+00:00" + "time": "2024-06-24T21:25:28+00:00" }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v5.1.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -1385,7 +1390,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1409,27 +1414,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2024-07-01T20:03:41+00:00" }, { "name": "onelogin/php-saml", - "version": "4.1.0", + "version": "4.2.0", "source": { "type": "git", - "url": "https://github.com/onelogin/php-saml.git", - "reference": "b22a57ebd13e838b90df5d3346090bc37056409d" + "url": "https://github.com/SAML-Toolkits/php-saml.git", + "reference": "d3b5172f137db2f412239432d77253ceaaa1e939" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/onelogin/php-saml/zipball/b22a57ebd13e838b90df5d3346090bc37056409d", - "reference": "b22a57ebd13e838b90df5d3346090bc37056409d", + "url": "https://api.github.com/repos/SAML-Toolkits/php-saml/zipball/d3b5172f137db2f412239432d77253ceaaa1e939", + "reference": "d3b5172f137db2f412239432d77253ceaaa1e939", "shasum": "" }, "require": { "php": ">=7.3", - "robrichards/xmlseclibs": ">=3.1.1" + "robrichards/xmlseclibs": "^3.1" }, "require-dev": { "pdepend/pdepend": "^2.8.0", @@ -1455,19 +1460,27 @@ "license": [ "MIT" ], - "description": "OneLogin PHP SAML Toolkit", - "homepage": "https://developers.onelogin.com/saml/php", + "description": "PHP SAML Toolkit", + "homepage": "https://github.com/SAML-Toolkits/php-saml", "keywords": [ + "Federation", "SAML2", - "onelogin", + "SSO", + "identity", "saml" ], "support": { - "email": "sixto.garcia@onelogin.com", - "issues": "https://github.com/onelogin/php-saml/issues", - "source": "https://github.com/onelogin/php-saml/" + "email": "sixto.martin.garcia@gmail.com", + "issues": "https://github.com/onelogin/SAML-Toolkits/issues", + "source": "https://github.com/onelogin/SAML-Toolkits/" }, - "time": "2022-07-15T20:44:36+00:00" + "funding": [ + { + "url": "https://github.com/SAML-Toolkits", + "type": "github" + } + ], + "time": "2024-05-30T15:10:40+00:00" }, { "name": "openpsa/quickform", @@ -1572,16 +1585,16 @@ }, { "name": "pear/pear-core-minimal", - "version": "v1.10.14", + "version": "v1.10.15", "source": { "type": "git", "url": "https://github.com/pear/pear-core-minimal.git", - "reference": "a86fc145edb5caedbf96527214ce3cadc9de4a32" + "reference": "ce0adade8b97561656ace07cdaac4751c271ea8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/a86fc145edb5caedbf96527214ce3cadc9de4a32", - "reference": "a86fc145edb5caedbf96527214ce3cadc9de4a32", + "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/ce0adade8b97561656ace07cdaac4751c271ea8c", + "reference": "ce0adade8b97561656ace07cdaac4751c271ea8c", "shasum": "" }, "require": { @@ -1594,9 +1607,9 @@ }, "type": "library", "autoload": { - "psr-0": { - "": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "include-path": [ @@ -1617,7 +1630,7 @@ "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR", "source": "https://github.com/pear/pear-core-minimal" }, - "time": "2023-11-26T16:15:38+00:00" + "time": "2024-03-16T18:41:45+00:00" }, { "name": "pear/pear_exception", @@ -1733,28 +1746,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "5.4.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.1", "ext-filter": "*", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.13" }, "type": "library", "extra": { @@ -1778,33 +1798,33 @@ }, { "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "opensource@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2024-05-21T05:55:05+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.3", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419" + "reference": "153ae662783729388a584b4361f2545e4d841e3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", - "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", + "reference": "153ae662783729388a584b4361f2545e4d841e3c", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", - "php": "^7.4 || ^8.0", + "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", "phpstan/phpdoc-parser": "^1.13" }, @@ -1842,22 +1862,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.3" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" }, - "time": "2023-08-12T11:01:26+00:00" + "time": "2024-02-23T11:10:43+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.25.0", + "version": "1.29.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240" + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240", - "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", "shasum": "" }, "require": { @@ -1889,9 +1909,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" }, - "time": "2024-01-04T17:06:16+00:00" + "time": "2024-05-31T08:52:43+00:00" }, { "name": "pimple/pimple", @@ -1995,6 +2015,54 @@ }, "time": "2021-02-03T23:26:27+00:00" }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, { "name": "psr/container", "version": "1.1.1", @@ -2095,16 +2163,16 @@ }, { "name": "psr/log", - "version": "2.0.0", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376" + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376", - "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", "shasum": "" }, "require": { @@ -2113,7 +2181,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { @@ -2139,9 +2207,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/2.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.0" }, - "time": "2021-07-14T16:41:46+00:00" + "time": "2021-07-14T16:46:02+00:00" }, { "name": "robrichards/xmlseclibs", @@ -2321,16 +2389,16 @@ }, { "name": "smarty/smarty", - "version": "v4.3.4", + "version": "v4.5.3", "source": { "type": "git", "url": "https://github.com/smarty-php/smarty.git", - "reference": "3931d8f54b8f7a4ffab538582d34d4397ba8daa5" + "reference": "9fc96a13dbaf546c3d7bcf95466726578cd4e0fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/smarty-php/smarty/zipball/3931d8f54b8f7a4ffab538582d34d4397ba8daa5", - "reference": "3931d8f54b8f7a4ffab538582d34d4397ba8daa5", + "url": "https://api.github.com/repos/smarty-php/smarty/zipball/9fc96a13dbaf546c3d7bcf95466726578cd4e0fa", + "reference": "9fc96a13dbaf546c3d7bcf95466726578cd4e0fa", "shasum": "" }, "require": { @@ -2381,22 +2449,22 @@ "support": { "forum": "https://github.com/smarty-php/smarty/discussions", "issues": "https://github.com/smarty-php/smarty/issues", - "source": "https://github.com/smarty-php/smarty/tree/v4.3.4" + "source": "https://github.com/smarty-php/smarty/tree/v4.5.3" }, - "time": "2023-09-14T10:59:08+00:00" + "time": "2024-05-28T21:46:01+00:00" }, { "name": "symfony/cache", - "version": "v6.4.2", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "14a75869bbb41cb35bc5d9d322473928c6f3f978" + "reference": "287142df5579ce223c485b3872df3efae8390984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/14a75869bbb41cb35bc5d9d322473928c6f3f978", - "reference": "14a75869bbb41cb35bc5d9d322473928c6f3f978", + "url": "https://api.github.com/repos/symfony/cache/zipball/287142df5579ce223c485b3872df3efae8390984", + "reference": "287142df5579ce223c485b3872df3efae8390984", "shasum": "" }, "require": { @@ -2463,7 +2531,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.2" + "source": "https://github.com/symfony/cache/tree/v6.4.8" }, "funding": [ { @@ -2479,20 +2547,20 @@ "type": "tidelift" } ], - "time": "2023-12-29T15:34:34+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/cache-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "1d74b127da04ffa87aa940abe15446fa89653778" + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/1d74b127da04ffa87aa940abe15446fa89653778", - "reference": "1d74b127da04ffa87aa940abe15446fa89653778", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/df6a1a44c890faded49a5fca33c2d5c5fd3c2197", + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197", "shasum": "" }, "require": { @@ -2502,7 +2570,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -2539,7 +2607,81 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/cache-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/clock", + "version": "v6.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/7a4840efd17135cbd547e41ec49fb910ed4f8b98", + "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v6.4.8" }, "funding": [ { @@ -2555,42 +2697,38 @@ "type": "tidelift" } ], - "time": "2023-09-25T12:52:38+00:00" + "time": "2024-05-31T14:51:39+00:00" }, { "name": "symfony/config", - "version": "v5.4.31", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9" + "reference": "12e7e52515ce37191b193cf3365903c4f3951e35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", + "url": "https://api.github.com/repos/symfony/config/zipball/12e7e52515ce37191b193cf3365903c4f3951e35", + "reference": "12e7e52515ce37191b193cf3365903c4f3951e35", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<4.4" + "symfony/finder": "<5.4", + "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/messenger": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -2618,7 +2756,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.31" + "source": "https://github.com/symfony/config/tree/v6.4.8" }, "funding": [ { @@ -2634,56 +2772,51 @@ "type": "tidelift" } ], - "time": "2023-11-09T08:22:43+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/console", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "4b4d8cd118484aa604ec519062113dd87abde18c" + "reference": "6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/4b4d8cd118484aa604ec519062113dd87abde18c", - "reference": "4b4d8cd118484aa604ec519062113dd87abde18c", + "url": "https://api.github.com/repos/symfony/console/zipball/6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9", + "reference": "6edb5363ec0c78ad4d48c5128ebf4d083d89d3a9", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.1|^6.0" + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -2717,7 +2850,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.34" + "source": "https://github.com/symfony/console/tree/v6.4.9" }, "funding": [ { @@ -2733,52 +2866,44 @@ "type": "tidelift" } ], - "time": "2023-12-08T13:33:03+00:00" + "time": "2024-06-28T09:49:33+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c" + "reference": "a4df9dfe5da2d177af6643610c7bee2cb76a9f5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/75d568165a65fa7d8124869ec7c3a90424352e6c", - "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a4df9dfe5da2d177af6643610c7bee2cb76a9f5e", + "reference": "a4df9dfe5da2d177af6643610c7bee2cb76a9f5e", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1.1", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22", - "symfony/service-contracts": "^1.1.6|^2" + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.2.10|^7.0" }, "conflict": { "ext-psr": "<1.1|>=2", - "symfony/config": "<5.3", - "symfony/finder": "<4.4", - "symfony/proxy-manager-bridge": "<4.4", - "symfony/yaml": "<4.4.26" + "symfony/config": "<6.1", + "symfony/finder": "<5.4", + "symfony/proxy-manager-bridge": "<6.3", + "symfony/yaml": "<5.4" }, "provide": { - "psr/container-implementation": "1.0", - "symfony/service-implementation": "1.0|2.0" + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "symfony/config": "^5.3|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4.26|^5.0|^6.0" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" + "symfony/config": "^6.1|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -2806,7 +2931,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.34" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.9" }, "funding": [ { @@ -2822,20 +2947,20 @@ "type": "tidelift" } ], - "time": "2023-12-28T09:31:38+00:00" + "time": "2024-06-19T10:45:28+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { @@ -2844,7 +2969,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -2873,7 +2998,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -2889,29 +3014,32 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/dotenv", - "version": "v5.4.34", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "07d75571cc7efc88f1aae96eddc5f671826c7327" + "reference": "55aefa0029adff89ecffdb560820e945c7983f06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/07d75571cc7efc88f1aae96eddc5f671826c7327", - "reference": "07d75571cc7efc88f1aae96eddc5f671826c7327", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/55aefa0029adff89ecffdb560820e945c7983f06", + "reference": "55aefa0029adff89ecffdb560820e945c7983f06", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.1" + }, + "conflict": { + "symfony/console": "<5.4", + "symfony/process": "<5.4" }, "require-dev": { - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0" + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -2944,7 +3072,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v5.4.34" + "source": "https://github.com/symfony/dotenv/tree/v6.4.8" }, "funding": [ { @@ -2960,31 +3088,35 @@ "type": "tidelift" } ], - "time": "2023-12-28T12:17:46+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/error-handler", - "version": "v5.4.29", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "328c6fcfd2f90b64c16efaf0ea67a311d672f078" + "reference": "c9b7cc075b3ab484239855622ca05cb0b99c13ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/328c6fcfd2f90b64c16efaf0ea67a311d672f078", - "reference": "328c6fcfd2f90b64c16efaf0ea67a311d672f078", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/c9b7cc075b3ab484239855622ca05cb0b99c13ec", + "reference": "c9b7cc075b3ab484239855622ca05cb0b99c13ec", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^4.4|^5.0|^6.0" + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" }, "require-dev": { - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/http-kernel": "^4.4|^5.0|^6.0", - "symfony/serializer": "^4.4|^5.0|^6.0" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^5.4|^6.0|^7.0" }, "bin": [ "Resources/bin/patch-type-declarations" @@ -3015,7 +3147,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.29" + "source": "https://github.com/symfony/error-handler/tree/v6.4.9" }, "funding": [ { @@ -3031,48 +3163,43 @@ "type": "tidelift" } ], - "time": "2023-09-06T21:54:06+00:00" + "time": "2024-06-21T16:04:15+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.4.34", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "e3bca343efeb613f843c254e7718ef17c9bdf7a3" + "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/e3bca343efeb613f843c254e7718ef17c9bdf7a3", - "reference": "e3bca343efeb613f843c254e7718ef17c9bdf7a3", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8d7507f02b06e06815e56bb39aa0128e3806208b", + "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/event-dispatcher-contracts": "^2|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/service-contracts": "<2.5" }, "provide": { "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0" + "symfony/event-dispatcher-implementation": "2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/stopwatch": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -3100,7 +3227,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.34" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.8" }, "funding": [ { @@ -3116,33 +3243,30 @@ "type": "tidelift" } ], - "time": "2023-12-27T21:12:56+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.2", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + "reference": "4e64b49bf370ade88e567de29465762e316e4224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/4e64b49bf370ade88e567de29465762e316e4224", + "reference": "4e64b49bf370ade88e567de29465762e316e4224", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "psr/event-dispatcher": "^1" }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -3179,7 +3303,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.2" }, "funding": [ { @@ -3195,26 +3319,27 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2024-01-23T14:51:35+00:00" }, { "name": "symfony/expression-language", - "version": "v5.4.21", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "501589522b844b8eecf012c133f0404f0eef77ac" + "reference": "0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/501589522b844b8eecf012c133f0404f0eef77ac", - "reference": "501589522b844b8eecf012c133f0404f0eef77ac", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a", + "reference": "0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3" + "php": ">=8.1", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -3242,7 +3367,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v5.4.21" + "source": "https://github.com/symfony/expression-language/tree/v6.4.8" }, "funding": [ { @@ -3258,27 +3383,29 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.25", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" + "reference": "b51ef8059159330b74a4d52f68e671033c0fe463" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b51ef8059159330b74a4d52f68e671033c0fe463", + "reference": "b51ef8059159330b74a4d52f68e671033c0fe463", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^5.4|^6.4|^7.0" }, "type": "library", "autoload": { @@ -3306,7 +3433,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.25" + "source": "https://github.com/symfony/filesystem/tree/v6.4.9" }, "funding": [ { @@ -3322,26 +3449,27 @@ "type": "tidelift" } ], - "time": "2023-05-31T13:04:02+00:00" + "time": "2024-06-28T09:49:33+00:00" }, { "name": "symfony/finder", - "version": "v5.4.27", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d" + "reference": "3ef977a43883215d560a2cecb82ec8e62131471c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ff4bce3c33451e7ec778070e45bd23f74214cd5d", - "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d", + "url": "https://api.github.com/repos/symfony/finder/zipball/3ef977a43883215d560a2cecb82ec8e62131471c", + "reference": "3ef977a43883215d560a2cecb82ec8e62131471c", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0|^7.0" }, "type": "library", "autoload": { @@ -3369,7 +3497,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.27" + "source": "https://github.com/symfony/finder/tree/v6.4.8" }, "funding": [ { @@ -3385,32 +3513,32 @@ "type": "tidelift" } ], - "time": "2023-07-31T08:02:31+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/flex", - "version": "v1.21.4", + "version": "v2.4.5", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "7b40eec950ded5de7054f807c209d3c612efe517" + "reference": "b0a405f40614c9f584b489d54f91091817b0e26e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/7b40eec950ded5de7054f807c209d3c612efe517", - "reference": "7b40eec950ded5de7054f807c209d3c612efe517", + "url": "https://api.github.com/repos/symfony/flex/zipball/b0a405f40614c9f584b489d54f91091817b0e26e", + "reference": "b0a405f40614c9f584b489d54f91091817b0e26e", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0|^2.0", - "php": ">=7.1" + "composer-plugin-api": "^2.1", + "php": ">=8.0" }, "require-dev": { - "composer/composer": "^1.0.2|^2.0", - "symfony/dotenv": "^4.4|^5.0|^6.0", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/phpunit-bridge": "^4.4.12|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0" + "composer/composer": "^2.1", + "symfony/dotenv": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0", + "symfony/phpunit-bridge": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0" }, "type": "composer-plugin", "extra": { @@ -3434,7 +3562,7 @@ "description": "Composer plugin for Symfony", "support": { "issues": "https://github.com/symfony/flex/issues", - "source": "https://github.com/symfony/flex/tree/v1.21.4" + "source": "https://github.com/symfony/flex/tree/v2.4.5" }, "funding": [ { @@ -3450,113 +3578,111 @@ "type": "tidelift" } ], - "time": "2024-01-02T11:08:17+00:00" + "time": "2024-03-02T08:16:47+00:00" }, { "name": "symfony/framework-bundle", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "ee446bb6a89ec758ffc1614f54c003124c7d7a88" + "reference": "c1d1cb0e508e11639283e1e6f8918eef0fa524bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/ee446bb6a89ec758ffc1614f54c003124c7d7a88", - "reference": "ee446bb6a89ec758ffc1614f54c003124c7d7a88", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c1d1cb0e508e11639283e1e6f8918eef0fa524bd", + "reference": "c1d1cb0e508e11639283e1e6f8918eef0fa524bd", "shasum": "" }, "require": { + "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=7.2.5", - "symfony/cache": "^5.2|^6.0", - "symfony/config": "^5.3|^6.0", - "symfony/dependency-injection": "^5.4.5|^6.0.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/error-handler": "^4.4.1|^5.0.1|^6.0", - "symfony/event-dispatcher": "^5.1|^6.0", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^5.4.24|^6.2.11", - "symfony/http-kernel": "^5.4|^6.0", + "php": ">=8.1", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^6.1|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.1|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22", - "symfony/routing": "^5.3|^6.0" + "symfony/routing": "^6.4|^7.0" }, "conflict": { "doctrine/annotations": "<1.13.1", - "doctrine/cache": "<1.11", "doctrine/persistence": "<1.3", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/asset": "<5.3", - "symfony/console": "<5.2.5|>=7.0", - "symfony/dom-crawler": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/form": "<5.2", - "symfony/http-client": "<4.4", - "symfony/lock": "<4.4", - "symfony/mailer": "<5.2", - "symfony/messenger": "<5.4", - "symfony/mime": "<4.4", - "symfony/property-access": "<5.3", - "symfony/property-info": "<4.4", - "symfony/security-csrf": "<5.3", - "symfony/serializer": "<5.2", - "symfony/service-contracts": ">=3.0", - "symfony/stopwatch": "<4.4", - "symfony/translation": "<5.3", - "symfony/twig-bridge": "<4.4", - "symfony/twig-bundle": "<4.4", - "symfony/validator": "<5.3.11", - "symfony/web-profiler-bundle": "<4.4", - "symfony/workflow": "<5.2" + "symfony/asset": "<5.4", + "symfony/asset-mapper": "<6.4", + "symfony/clock": "<6.3", + "symfony/console": "<5.4|>=7.0", + "symfony/dom-crawler": "<6.4", + "symfony/dotenv": "<5.4", + "symfony/form": "<5.4", + "symfony/http-client": "<6.3", + "symfony/lock": "<5.4", + "symfony/mailer": "<5.4", + "symfony/messenger": "<6.3", + "symfony/mime": "<6.4", + "symfony/property-access": "<5.4", + "symfony/property-info": "<5.4", + "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", + "symfony/security-core": "<5.4", + "symfony/security-csrf": "<5.4", + "symfony/serializer": "<6.4", + "symfony/stopwatch": "<5.4", + "symfony/translation": "<6.4", + "symfony/twig-bridge": "<5.4", + "symfony/twig-bundle": "<5.4", + "symfony/validator": "<6.4", + "symfony/web-profiler-bundle": "<6.4", + "symfony/workflow": "<6.4" }, "require-dev": { "doctrine/annotations": "^1.13.1|^2", - "doctrine/cache": "^1.11|^2.0", "doctrine/persistence": "^1.3|^2|^3", + "dragonmantank/cron-expression": "^3.1", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^5.3|^6.0", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/console": "^5.4.9|^6.0.9", - "symfony/css-selector": "^4.4|^5.0|^6.0", - "symfony/dom-crawler": "^4.4.30|^5.3.7|^6.0", - "symfony/dotenv": "^5.1|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/form": "^5.2|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/mailer": "^5.2|^6.0", - "symfony/messenger": "^5.4|^6.0", - "symfony/mime": "^4.4|^5.0|^6.0", - "symfony/notifier": "^5.4|^6.0", + "seld/jsonlint": "^1.10", + "symfony/asset": "^5.4|^6.0|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/clock": "^6.2|^7.0", + "symfony/console": "^5.4.9|^6.0.9|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/dotenv": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/html-sanitizer": "^6.1|^7.0", + "symfony/http-client": "^6.3|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/mailer": "^5.4|^6.0|^7.0", + "symfony/messenger": "^6.3|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/notifier": "^5.4|^6.0|^7.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/property-info": "^4.4|^5.0|^6.0", - "symfony/rate-limiter": "^5.2|^6.0", - "symfony/security-bundle": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0", - "symfony/stopwatch": "^4.4|^5.0|^6.0", - "symfony/string": "^5.0|^6.0", - "symfony/translation": "^5.3|^6.0", - "symfony/twig-bundle": "^4.4|^5.0|^6.0", - "symfony/validator": "^5.3.11|^6.0", - "symfony/web-link": "^4.4|^5.0|^6.0", - "symfony/workflow": "^5.2|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0", - "twig/twig": "^2.10|^3.0" - }, - "suggest": { - "ext-apcu": "For best performance of the system caches", - "symfony/console": "For using the console commands", - "symfony/form": "For using forms", - "symfony/property-info": "For using the property_info service", - "symfony/serializer": "For using the serializer service", - "symfony/validator": "For using validation", - "symfony/web-link": "For using web links, features such as preloading, prefetching or prerendering", - "symfony/yaml": "For using the debug:config and lint:yaml commands" + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0", + "symfony/scheduler": "^6.4.4|^7.0.4", + "symfony/security-bundle": "^5.4|^6.0|^7.0", + "symfony/semaphore": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/string": "^5.4|^6.0|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/web-link": "^5.4|^6.0|^7.0", + "symfony/workflow": "^6.4|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0", + "twig/twig": "^2.10|^3.0.4" }, "type": "symfony-bundle", "autoload": { @@ -3584,7 +3710,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v5.4.34" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.9" }, "funding": [ { @@ -3600,51 +3726,53 @@ "type": "tidelift" } ], - "time": "2023-12-29T14:52:40+00:00" + "time": "2024-06-26T08:32:27+00:00" }, { "name": "symfony/http-client", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "8fe833b758bc5b325e9d96a913376d6d57a90fb0" + "reference": "6e9db0025db565bcf8f1d46ed734b549e51e6045" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/8fe833b758bc5b325e9d96a913376d6d57a90fb0", - "reference": "8fe833b758bc5b325e9d96a913376d6d57a90fb0", + "url": "https://api.github.com/repos/symfony/http-client/zipball/6e9db0025db565bcf8f1d46ed734b549e51e6045", + "reference": "6e9db0025db565bcf8f1d46ed734b549e51e6045", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/http-client-contracts": "^2.4", - "symfony/polyfill-php73": "^1.11", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.0|^2|^3" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "^3.4.1", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.3" }, "provide": { "php-http/async-client-implementation": "*", "php-http/client-implementation": "*", "psr/http-client-implementation": "1.0", - "symfony/http-client-implementation": "2.4" + "symfony/http-client-implementation": "3.0" }, "require-dev": { "amphp/amp": "^2.5", "amphp/http-client": "^4.2.1", "amphp/http-tunnel": "^1.0", "amphp/socket": "^1.1", - "guzzlehttp/promises": "^1.4", + "guzzlehttp/promises": "^1.4|^2.0", "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", - "php-http/message-factory": "^1.0", "psr/http-client": "^1.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/http-kernel": "^4.4.13|^5.1.5|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/stopwatch": "^4.4|^5.0|^6.0" + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -3675,7 +3803,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v5.4.34" + "source": "https://github.com/symfony/http-client/tree/v6.4.9" }, "funding": [ { @@ -3691,32 +3819,29 @@ "type": "tidelift" } ], - "time": "2023-12-02T08:41:43+00:00" + "time": "2024-06-28T07:59:05+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v2.5.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + "reference": "20414d96f391677bf80078aa55baece78b82647d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", - "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", + "reference": "20414d96f391677bf80078aa55baece78b82647d", "shasum": "" }, "require": { - "php": ">=7.2.5" - }, - "suggest": { - "symfony/http-client-implementation": "" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3726,7 +3851,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3753,7 +3881,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" }, "funding": [ { @@ -3769,39 +3897,40 @@ "type": "tidelift" } ], - "time": "2022-04-12T15:48:08+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.34", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "4da1713e88cf9c44bd4bf65f54772681222fcbec" + "reference": "27de8cc95e11db7a50b027e71caaab9024545947" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/4da1713e88cf9c44bd4bf65f54772681222fcbec", - "reference": "4da1713e88cf9c44bd4bf65f54772681222fcbec", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/27de8cc95e11db7a50b027e71caaab9024545947", + "reference": "27de8cc95e11db7a50b027e71caaab9024545947", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-php83": "^1.27" }, - "require-dev": { - "predis/predis": "~1.0", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", - "symfony/mime": "^4.4|^5.0|^6.0", - "symfony/rate-limiter": "^5.2|^6.0" + "conflict": { + "symfony/cache": "<6.3" }, - "suggest": { - "symfony/mime": "To use the file extension guesser" + "require-dev": { + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.3|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -3829,7 +3958,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.34" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.8" }, "funding": [ { @@ -3845,76 +3974,78 @@ "type": "tidelift" } ], - "time": "2023-12-27T11:45:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "f2b00c66d1c7ef12f3fc625af2a0bc5d5857db7b" + "reference": "cc4a9bec6e1bdd2405f40277a68a6ed1bb393005" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f2b00c66d1c7ef12f3fc625af2a0bc5d5857db7b", - "reference": "f2b00c66d1c7ef12f3fc625af2a0bc5d5857db7b", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/cc4a9bec6e1bdd2405f40277a68a6ed1bb393005", + "reference": "cc4a9bec6e1bdd2405f40277a68a6ed1bb393005", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/log": "^1|^2", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^5.0|^6.0", - "symfony/http-foundation": "^5.4.21|^6.2.7", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { "symfony/browser-kit": "<5.4", - "symfony/cache": "<5.0", - "symfony/config": "<5.0", - "symfony/console": "<4.4", - "symfony/dependency-injection": "<5.3", - "symfony/doctrine-bridge": "<5.0", - "symfony/form": "<5.0", - "symfony/http-client": "<5.0", - "symfony/mailer": "<5.0", - "symfony/messenger": "<5.0", - "symfony/translation": "<5.0", - "symfony/twig-bridge": "<5.0", - "symfony/validator": "<5.0", + "symfony/cache": "<5.4", + "symfony/config": "<6.1", + "symfony/console": "<5.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<5.4", + "symfony/form": "<5.4", + "symfony/http-client": "<5.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<5.4", + "symfony/messenger": "<5.4", + "symfony/translation": "<5.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<5.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.3", "twig/twig": "<2.13" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/config": "^5.0|^6.0", - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/css-selector": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^5.3|^6.0", - "symfony/dom-crawler": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/http-client-contracts": "^1.1|^2|^3", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/routing": "^4.4|^5.0|^6.0", - "symfony/stopwatch": "^4.4|^5.0|^6.0", - "symfony/translation": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2|^3", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/clock": "^6.2|^7.0", + "symfony/config": "^6.1|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4.5|^6.0.5|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4.4|^7.0.4", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.4|^7.0", + "symfony/var-exporter": "^6.2|^7.0", "twig/twig": "^2.13|^3.0.4" }, - "suggest": { - "symfony/browser-kit": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "" - }, "type": "library", "autoload": { "psr-4": { @@ -3941,7 +4072,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.34" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.9" }, "funding": [ { @@ -3957,34 +4088,34 @@ "type": "tidelift" } ], - "time": "2023-12-30T13:02:02+00:00" + "time": "2024-06-28T11:48:06+00:00" }, { "name": "symfony/lock", - "version": "v5.4.34", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/lock.git", - "reference": "26ff165e2b501ff7ead2f30a02f7e0eb0975866e" + "reference": "1387f50285c23607467c1f05b258bde65f1ab276" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/lock/zipball/26ff165e2b501ff7ead2f30a02f7e0eb0975866e", - "reference": "26ff165e2b501ff7ead2f30a02f7e0eb0975866e", + "url": "https://api.github.com/repos/symfony/lock/zipball/1387f50285c23607467c1f05b258bde65f1ab276", + "reference": "1387f50285c23607467c1f05b258bde65f1ab276", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { - "doctrine/dbal": "<2.13" + "doctrine/dbal": "<2.13", + "symfony/cache": "<6.2" }, "require-dev": { "doctrine/dbal": "^2.13|^3|^4", - "predis/predis": "~1.0" + "predis/predis": "^1.1|^2.0" }, "type": "library", "autoload": { @@ -4020,7 +4151,7 @@ "semaphore" ], "support": { - "source": "https://github.com/symfony/lock/tree/v5.4.34" + "source": "https://github.com/symfony/lock/tree/v6.4.8" }, "funding": [ { @@ -4036,56 +4167,54 @@ "type": "tidelift" } ], - "time": "2023-12-18T14:56:06+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/maker-bundle", - "version": "v1.50.0", + "version": "v1.60.0", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "a1733f849b999460c308e66f6392fb09b621fa86" + "reference": "c305a02a22974670f359d4274c9431e1a191f559" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/a1733f849b999460c308e66f6392fb09b621fa86", - "reference": "a1733f849b999460c308e66f6392fb09b621fa86", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/c305a02a22974670f359d4274c9431e1a191f559", + "reference": "c305a02a22974670f359d4274c9431e1a191f559", "shasum": "" }, "require": { "doctrine/inflector": "^2.0", - "nikic/php-parser": "^4.11", - "php": ">=8.0", - "symfony/config": "^5.4.7|^6.0", - "symfony/console": "^5.4.7|^6.0", - "symfony/dependency-injection": "^5.4.7|^6.0", + "nikic/php-parser": "^4.18|^5.0", + "php": ">=8.1", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", "symfony/deprecation-contracts": "^2.2|^3", - "symfony/filesystem": "^5.4.7|^6.0", - "symfony/finder": "^5.4.3|^6.0", - "symfony/framework-bundle": "^5.4.7|^6.0", - "symfony/http-kernel": "^5.4.7|^6.0", - "symfony/process": "^5.4.7|^6.0" + "symfony/filesystem": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0" }, "conflict": { - "doctrine/doctrine-bundle": "<2.4", - "doctrine/orm": "<2.10", - "symfony/doctrine-bridge": "<5.4" + "doctrine/doctrine-bundle": "<2.10", + "doctrine/orm": "<2.15" }, "require-dev": { "composer/semver": "^3.0", - "doctrine/doctrine-bundle": "^2.4", - "doctrine/orm": "^2.10.0", - "symfony/http-client": "^5.4.7|^6.0", - "symfony/phpunit-bridge": "^5.4.17|^6.0", - "symfony/polyfill-php80": "^1.16.0", - "symfony/security-core": "^5.4.7|^6.0", - "symfony/yaml": "^5.4.3|^6.0", - "twig/twig": "^2.0|^3.0" + "doctrine/doctrine-bundle": "^2.5.0", + "doctrine/orm": "^2.15|^3", + "symfony/http-client": "^6.4|^7.0", + "symfony/phpunit-bridge": "^6.4.1|^7.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/twig": "^3.0|^4.x-dev" }, "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-main": "1.0-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -4114,7 +4243,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.50.0" + "source": "https://github.com/symfony/maker-bundle/tree/v1.60.0" }, "funding": [ { @@ -4130,24 +4259,25 @@ "type": "tidelift" } ], - "time": "2023-07-10T18:21:57+00:00" + "time": "2024-06-10T06:03:18+00:00" }, { "name": "symfony/mime", - "version": "v6.1.11", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "2bff58573e81a1df51bf99ad01725428beda1cbc" + "reference": "7d048964877324debdcb4e0549becfa064a20d43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/2bff58573e81a1df51bf99ad01725428beda1cbc", - "reference": "2bff58573e81a1df51bf99ad01725428beda1cbc", + "url": "https://api.github.com/repos/symfony/mime/zipball/7d048964877324debdcb4e0549becfa064a20d43", + "reference": "7d048964877324debdcb4e0549becfa064a20d43", "shasum": "" }, "require": { "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, @@ -4155,15 +4285,18 @@ "egulias/email-validator": "~3.0.0", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/mailer": "<5.4" + "symfony/mailer": "<5.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/property-info": "^5.4|^6.0", - "symfony/serializer": "^5.2|^6.0" + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.4|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" }, "type": "library", "autoload": { @@ -4195,7 +4328,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.1.11" + "source": "https://github.com/symfony/mime/tree/v6.4.9" }, "funding": [ { @@ -4211,47 +4344,42 @@ "type": "tidelift" } ], - "time": "2023-01-10T18:53:01+00:00" + "time": "2024-06-28T09:49:33+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v5.4.31", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "3e295d9b0a873476356cb6cff0ce39b3f528b387" + "reference": "0fbee64913b1c595e7650a1919ba3edba8d49ea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/3e295d9b0a873476356cb6cff0ce39b3f528b387", - "reference": "3e295d9b0a873476356cb6cff0ce39b3f528b387", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/0fbee64913b1c595e7650a1919ba3edba8d49ea7", + "reference": "0fbee64913b1c595e7650a1919ba3edba8d49ea7", "shasum": "" }, "require": { - "monolog/monolog": "^1.25.1|^2", - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/http-kernel": "^5.3|^6.0", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2|^3" + "monolog/monolog": "^1.25.1|^2|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/console": "<4.4", - "symfony/http-foundation": "<5.3" + "symfony/console": "<5.4", + "symfony/http-foundation": "<5.4", + "symfony/security-core": "<5.4" }, "require-dev": { - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/mailer": "^4.4|^5.0|^6.0", - "symfony/messenger": "^4.4|^5.0|^6.0", - "symfony/mime": "^4.4|^5.0|^6.0", - "symfony/security-core": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", - "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", - "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/mailer": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/security-core": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "symfony-bridge", "autoload": { @@ -4279,7 +4407,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v5.4.31" + "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.8" }, "funding": [ { @@ -4295,7 +4423,7 @@ "type": "tidelift" } ], - "time": "2023-10-31T07:58:33+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/monolog-bundle", @@ -4380,23 +4508,21 @@ }, { "name": "symfony/options-resolver", - "version": "v5.4.21", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9" + "reference": "22ab9e9101ab18de37839074f8a1197f55590c1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", - "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/22ab9e9101ab18de37839074f8a1197f55590c1b", + "reference": "22ab9e9101ab18de37839074f8a1197f55590c1b", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -4429,7 +4555,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.4.21" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.8" }, "funding": [ { @@ -4445,20 +4571,20 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.4.0", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "e001f752338a49d644ee0523fd7891aabaccb7e2" + "reference": "90ebbe946e5d64a5fad9ac9427e335045cf2bd31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/e001f752338a49d644ee0523fd7891aabaccb7e2", - "reference": "e001f752338a49d644ee0523fd7891aabaccb7e2", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/90ebbe946e5d64a5fad9ac9427e335045cf2bd31", + "reference": "90ebbe946e5d64a5fad9ac9427e335045cf2bd31", "shasum": "" }, "require": { @@ -4501,7 +4627,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.0" + "source": "https://github.com/symfony/password-hasher/tree/v6.4.8" }, "funding": [ { @@ -4517,20 +4643,20 @@ "type": "tidelift" } ], - "time": "2023-11-06T11:00:25+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.28.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "875e90aeea2777b6f135677f618529449334a612" + "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", - "reference": "875e90aeea2777b6f135677f618529449334a612", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", + "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", "shasum": "" }, "require": { @@ -4541,9 +4667,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4582,7 +4705,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" }, "funding": [ { @@ -4598,20 +4721,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.28.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" + "reference": "a6e83bdeb3c84391d1dfe16f42e40727ce524a5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", - "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a6e83bdeb3c84391d1dfe16f42e40727ce524a5c", + "reference": "a6e83bdeb3c84391d1dfe16f42e40727ce524a5c", "shasum": "" }, "require": { @@ -4624,9 +4747,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4669,7 +4789,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.30.0" }, "funding": [ { @@ -4685,20 +4805,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:30:37+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.28.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", "shasum": "" }, "require": { @@ -4709,9 +4829,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4753,7 +4870,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" }, "funding": [ { @@ -4769,20 +4886,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", "shasum": "" }, "require": { @@ -4796,9 +4913,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4836,7 +4950,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" }, "funding": [ { @@ -4852,20 +4966,20 @@ "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2024-06-19T12:30:46+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.28.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" + "reference": "10112722600777e02d2745716b70c5db4ca70442" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", - "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/10112722600777e02d2745716b70c5db4ca70442", + "reference": "10112722600777e02d2745716b70c5db4ca70442", "shasum": "" }, "require": { @@ -4873,9 +4987,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4912,169 +5023,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.30.0" }, "funding": [ { @@ -5090,20 +5039,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-06-19T12:30:46+00:00" }, { - "name": "symfony/polyfill-php81", - "version": "v1.28.0", + "name": "symfony/polyfill-php83", + "version": "v1.30.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9", + "reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9", "shasum": "" }, "require": { @@ -5111,9 +5060,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5124,7 +5070,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" + "Symfony\\Polyfill\\Php83\\": "" }, "classmap": [ "Resources/stubs" @@ -5144,7 +5090,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -5153,7 +5099,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.30.0" }, "funding": [ { @@ -5169,20 +5115,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-06-19T12:35:24+00:00" }, { "name": "symfony/polyfill-uuid", - "version": "v1.28.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", - "reference": "9c44518a5aff8da565c8a55dbe85d2769e6f630e" + "reference": "2ba1f33797470debcda07fe9dce20a0003df18e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/9c44518a5aff8da565c8a55dbe85d2769e6f630e", - "reference": "9c44518a5aff8da565c8a55dbe85d2769e6f630e", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/2ba1f33797470debcda07fe9dce20a0003df18e9", + "reference": "2ba1f33797470debcda07fe9dce20a0003df18e9", "shasum": "" }, "require": { @@ -5196,9 +5142,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5235,7 +5178,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.30.0" }, "funding": [ { @@ -5251,20 +5194,20 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/process", - "version": "v6.4.2", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "c4b1ef0bc80533d87a2e969806172f1c2a980241" + "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c4b1ef0bc80533d87a2e969806172f1c2a980241", - "reference": "c4b1ef0bc80533d87a2e969806172f1c2a980241", + "url": "https://api.github.com/repos/symfony/process/zipball/8d92dd79149f29e89ee0f480254db595f6a6a2c5", + "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5", "shasum": "" }, "require": { @@ -5296,7 +5239,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.2" + "source": "https://github.com/symfony/process/tree/v6.4.8" }, "funding": [ { @@ -5312,33 +5255,29 @@ "type": "tidelift" } ], - "time": "2023-12-22T16:42:54+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/property-access", - "version": "v5.4.26", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "0249e46f69e92049a488f39fcf531cb42c50caaa" + "reference": "e4d9b00983612f9c0013ca37c61affdba2dd975a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/0249e46f69e92049a488f39fcf531cb42c50caaa", - "reference": "0249e46f69e92049a488f39fcf531cb42c50caaa", + "url": "https://api.github.com/repos/symfony/property-access/zipball/e4d9b00983612f9c0013ca37c61affdba2dd975a", + "reference": "e4d9b00983612f9c0013ca37c61affdba2dd975a", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16", - "symfony/property-info": "^5.2|^6.0" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/property-info": "^5.4|^6.0|^7.0" }, "require-dev": { - "symfony/cache": "^4.4|^5.0|^6.0" - }, - "suggest": { - "psr/cache-implementation": "To cache access methods." + "symfony/cache": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -5377,7 +5316,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v5.4.26" + "source": "https://github.com/symfony/property-access/tree/v6.4.8" }, "funding": [ { @@ -5393,46 +5332,38 @@ "type": "tidelift" } ], - "time": "2023-07-13T15:20:41+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/property-info", - "version": "v5.4.24", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "d43b85b00699b4484964c297575b5c6f9dc5f6e1" + "reference": "1a0357ed93a6ab09482435a7818defaa85cad69b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/d43b85b00699b4484964c297575b5c6f9dc5f6e1", - "reference": "d43b85b00699b4484964c297575b5c6f9dc5f6e1", + "url": "https://api.github.com/repos/symfony/property-info/zipball/1a0357ed93a6ab09482435a7818defaa85cad69b", + "reference": "1a0357ed93a6ab09482435a7818defaa85cad69b", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16", - "symfony/string": "^5.1|^6.0" + "php": ">=8.1", + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", - "symfony/dependency-injection": "<4.4" + "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/dependency-injection": "<5.4", + "symfony/serializer": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.10.4|^2", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "phpdocumentor/reflection-docblock": "^5.2", "phpstan/phpdoc-parser": "^1.0", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/serializer": "^4.4|^5.0|^6.0" - }, - "suggest": { - "phpdocumentor/reflection-docblock": "To use the PHPDoc", - "psr/cache-implementation": "To cache results", - "symfony/doctrine-bridge": "To use Doctrine metadata", - "symfony/serializer": "To use Serializer metadata" + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -5468,7 +5399,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v5.4.24" + "source": "https://github.com/symfony/property-info/tree/v6.4.9" }, "funding": [ { @@ -5484,47 +5415,40 @@ "type": "tidelift" } ], - "time": "2023-05-15T20:11:03+00:00" + "time": "2024-06-21T16:04:15+00:00" }, { "name": "symfony/routing", - "version": "v5.4.34", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "f1d08ed59d7718845bb70acd7480fa7da8966ec0" + "reference": "8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/f1d08ed59d7718845bb70acd7480fa7da8966ec0", - "reference": "f1d08ed59d7718845bb70acd7480fa7da8966ec0", + "url": "https://api.github.com/repos/symfony/routing/zipball/8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58", + "reference": "8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "doctrine/annotations": "<1.12", - "symfony/config": "<5.3", - "symfony/dependency-injection": "<4.4", - "symfony/yaml": "<4.4" + "symfony/config": "<6.2", + "symfony/dependency-injection": "<5.4", + "symfony/yaml": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.12|^2", "psr/log": "^1|^2|^3", - "symfony/config": "^5.3|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/config": "For using the all-in-one router or any loader", - "symfony/expression-language": "For using expression matching", - "symfony/http-foundation": "For using a Symfony Request object", - "symfony/yaml": "For using the YAML loader" + "symfony/config": "^6.2|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -5558,7 +5482,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.34" + "source": "https://github.com/symfony/routing/tree/v6.4.8" }, "funding": [ { @@ -5574,66 +5498,75 @@ "type": "tidelift" } ], - "time": "2023-12-27T12:51:02+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-bundle", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "6477c31e36dfa25b07befea20bc8326f4ba11d75" + "reference": "adc34df2fe487a13d4410a237202422294c917b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/6477c31e36dfa25b07befea20bc8326f4ba11d75", - "reference": "6477c31e36dfa25b07befea20bc8326f4ba11d75", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/adc34df2fe487a13d4410a237202422294c917b2", + "reference": "adc34df2fe487a13d4410a237202422294c917b2", "shasum": "" }, "require": { + "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=7.2.5", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^5.3|^6.0", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/event-dispatcher": "^5.1|^6.0", - "symfony/http-foundation": "^5.3|^6.0", - "symfony/http-kernel": "^5.3|^6.0", - "symfony/password-hasher": "^5.3|^6.0", - "symfony/polyfill-php80": "^1.16", - "symfony/security-core": "^5.4|^6.0", - "symfony/security-csrf": "^4.4|^5.0|^6.0", - "symfony/security-guard": "^5.3", - "symfony/security-http": "^5.4.30|^6.3.6", - "symfony/service-contracts": "^1.10|^2|^3" + "php": ">=8.1", + "symfony/clock": "^6.3|^7.0", + "symfony/config": "^6.1|^7.0", + "symfony/dependency-injection": "^6.2|^7.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.2|^7.0", + "symfony/http-kernel": "^6.2", + "symfony/password-hasher": "^5.4|^6.0|^7.0", + "symfony/security-core": "^6.2|^7.0", + "symfony/security-csrf": "^5.4|^6.0|^7.0", + "symfony/security-http": "^6.3.6|^7.0", + "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/browser-kit": "<4.4", - "symfony/console": "<4.4", - "symfony/framework-bundle": "<4.4", - "symfony/ldap": "<5.1", - "symfony/twig-bundle": "<4.4" + "symfony/browser-kit": "<5.4", + "symfony/console": "<5.4", + "symfony/framework-bundle": "<6.4", + "symfony/http-client": "<5.4", + "symfony/ldap": "<5.4", + "symfony/serializer": "<6.4", + "symfony/twig-bundle": "<5.4", + "symfony/validator": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.10.4|^2", - "symfony/asset": "^4.4|^5.0|^6.0", - "symfony/browser-kit": "^4.4|^5.0|^6.0", - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/css-selector": "^4.4|^5.0|^6.0", - "symfony/dom-crawler": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/form": "^4.4|^5.0|^6.0", - "symfony/framework-bundle": "^5.3|^6.0", - "symfony/ldap": "^5.3|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/rate-limiter": "^5.2|^6.0", - "symfony/serializer": "^4.4|^5.0|^6.0", - "symfony/translation": "^4.4|^5.0|^6.0", - "symfony/twig-bridge": "^4.4|^5.0|^6.0", - "symfony/twig-bundle": "^4.4|^5.0|^6.0", - "symfony/validator": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0", - "twig/twig": "^2.13|^3.0.4" + "symfony/asset": "^5.4|^6.0|^7.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/ldap": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", + "symfony/twig-bridge": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0", + "twig/twig": "^2.13|^3.0.4", + "web-token/jwt-checker": "^3.1", + "web-token/jwt-signature-algorithm-ecdsa": "^3.1", + "web-token/jwt-signature-algorithm-eddsa": "^3.1", + "web-token/jwt-signature-algorithm-hmac": "^3.1", + "web-token/jwt-signature-algorithm-none": "^3.1", + "web-token/jwt-signature-algorithm-rsa": "^3.1" }, "type": "symfony-bundle", "autoload": { @@ -5661,7 +5594,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v5.4.34" + "source": "https://github.com/symfony/security-bundle/tree/v6.4.9" }, "funding": [ { @@ -5677,56 +5610,49 @@ "type": "tidelift" } ], - "time": "2023-12-19T08:26:08+00:00" + "time": "2024-06-28T10:06:43+00:00" }, { "name": "symfony/security-core", - "version": "v5.4.30", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "3908c54da30dd68c2fe31915d82a1c81809d1928" + "reference": "2d58f4c3ff50b1b4eef0a333c2b1e3eef46807f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/3908c54da30dd68c2fe31915d82a1c81809d1928", - "reference": "3908c54da30dd68c2fe31915d82a1c81809d1928", + "url": "https://api.github.com/repos/symfony/security-core/zipball/2d58f4c3ff50b1b4eef0a333c2b1e3eef46807f4", + "reference": "2d58f4c3ff50b1b4eef0a333c2b1e3eef46807f4", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/event-dispatcher-contracts": "^1.1|^2|^3", - "symfony/password-hasher": "^5.3|^6.0", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1.6|^2|^3" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher-contracts": "^2.5|^3", + "symfony/password-hasher": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/event-dispatcher": "<4.4", - "symfony/http-foundation": "<5.3", - "symfony/ldap": "<4.4", - "symfony/security-guard": "<4.4", - "symfony/validator": "<5.2" + "symfony/event-dispatcher": "<5.4", + "symfony/http-foundation": "<5.4", + "symfony/ldap": "<5.4", + "symfony/security-guard": "<5.4", + "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", + "symfony/validator": "<5.4" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "psr/container": "^1.0|^2.0", + "psr/container": "^1.1|^2.0", "psr/log": "^1|^2|^3", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^5.3|^6.0", - "symfony/ldap": "^4.4|^5.0|^6.0", - "symfony/translation": "^4.4|^5.0|^6.0", - "symfony/validator": "^5.2|^6.0" - }, - "suggest": { - "psr/container-implementation": "To instantiate the Security class", - "symfony/event-dispatcher": "", - "symfony/expression-language": "For using the expression voter", - "symfony/http-foundation": "", - "symfony/ldap": "For using LDAP integration", - "symfony/validator": "For using the user password constraint" + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/ldap": "^5.4|^6.0|^7.0", + "symfony/string": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", + "symfony/validator": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -5754,7 +5680,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v5.4.30" + "source": "https://github.com/symfony/security-core/tree/v6.4.9" }, "funding": [ { @@ -5770,20 +5696,20 @@ "type": "tidelift" } ], - "time": "2023-10-27T07:38:28+00:00" + "time": "2024-06-28T07:59:05+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.4.0", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "b28413496ebfce2f98afbb990ad0ce0ba3586638" + "reference": "f46ab02b76311087873257071559edcaf6d7ab99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/b28413496ebfce2f98afbb990ad0ce0ba3586638", - "reference": "b28413496ebfce2f98afbb990ad0ce0ba3586638", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/f46ab02b76311087873257071559edcaf6d7ab99", + "reference": "f46ab02b76311087873257071559edcaf6d7ab99", "shasum": "" }, "require": { @@ -5822,7 +5748,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.0" + "source": "https://github.com/symfony/security-csrf/tree/v6.4.8" }, "funding": [ { @@ -5838,117 +5764,51 @@ "type": "tidelift" } ], - "time": "2023-08-25T16:27:31+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { - "name": "symfony/security-guard", - "version": "v5.4.27", + "name": "symfony/security-http", + "version": "v6.4.9", "source": { "type": "git", - "url": "https://github.com/symfony/security-guard.git", - "reference": "72c53142533462fc6fda4a429c2a21c2b944a8cc" + "url": "https://github.com/symfony/security-http.git", + "reference": "8e70f39626ada36c5492c3aff9369c85d2840948" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-guard/zipball/72c53142533462fc6fda4a429c2a21c2b944a8cc", - "reference": "72c53142533462fc6fda4a429c2a21c2b944a8cc", + "url": "https://api.github.com/repos/symfony/security-http/zipball/8e70f39626ada36c5492c3aff9369c85d2840948", + "reference": "8e70f39626ada36c5492c3aff9369c85d2840948", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.15", - "symfony/security-core": "^5.0", - "symfony/security-http": "^5.3" - }, - "require-dev": { - "psr/log": "^1|^2|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Security\\Guard\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Security Component - Guard", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/security-guard/tree/v5.4.27" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-07-28T14:44:35+00:00" - }, - { - "name": "symfony/security-http", - "version": "v5.4.31", - "source": { - "type": "git", - "url": "https://github.com/symfony/security-http.git", - "reference": "6d3cd5a4deee9697738db8d24258890ca4140ae9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/6d3cd5a4deee9697738db8d24258890ca4140ae9", - "reference": "6d3cd5a4deee9697738db8d24258890ca4140ae9", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/http-foundation": "^5.3|^6.0", - "symfony/http-kernel": "^5.3|^6.0", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-foundation": "^6.2|^7.0", + "symfony/http-kernel": "^6.3|^7.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16", - "symfony/property-access": "^4.4|^5.0|^6.0", - "symfony/security-core": "^5.4.19|~6.0.19|~6.1.11|^6.2.5", - "symfony/service-contracts": "^1.10|^2|^3" + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/event-dispatcher": "<4.3", - "symfony/security-bundle": "<5.3", - "symfony/security-csrf": "<4.4" + "symfony/clock": "<6.3", + "symfony/event-dispatcher": "<5.4.9|>=6,<6.0.9", + "symfony/http-client-contracts": "<3.0", + "symfony/security-bundle": "<5.4", + "symfony/security-csrf": "<5.4" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/rate-limiter": "^5.2|^6.0", - "symfony/routing": "^4.4|^5.0|^6.0", - "symfony/security-csrf": "^4.4|^5.0|^6.0", - "symfony/translation": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", - "symfony/security-csrf": "For using tokens to protect authentication/logout attempts" + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/clock": "^6.3|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-client-contracts": "^3.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/security-csrf": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", + "web-token/jwt-checker": "^3.1", + "web-token/jwt-signature-algorithm-ecdsa": "^3.1" }, "type": "library", "autoload": { @@ -5976,7 +5836,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v5.4.31" + "source": "https://github.com/symfony/security-http/tree/v6.4.9" }, "funding": [ { @@ -5992,66 +5852,61 @@ "type": "tidelift" } ], - "time": "2023-11-03T16:13:08+00:00" + "time": "2024-06-21T16:04:15+00:00" }, { "name": "symfony/serializer", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "b8353e4208e9161f34d22c4631c63404b26ba929" + "reference": "56ce31d19127e79647ac53387c7555bdcd5730ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/b8353e4208e9161f34d22c4631c63404b26ba929", - "reference": "b8353e4208e9161f34d22c4631c63404b26ba929", + "url": "https://api.github.com/repos/symfony/serializer/zipball/56ce31d19127e79647ac53387c7555bdcd5730ce", + "reference": "56ce31d19127e79647ac53387c7555bdcd5730ce", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/dependency-injection": "<4.4", + "symfony/dependency-injection": "<5.4", "symfony/property-access": "<5.4", "symfony/property-info": "<5.4.24|>=6,<6.2.11", - "symfony/uid": "<5.3", - "symfony/yaml": "<4.4" + "symfony/uid": "<5.4", + "symfony/validator": "<6.4", + "symfony/yaml": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/form": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/http-kernel": "^4.4|^5.0|^6.0", - "symfony/mime": "^4.4|^5.0|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/property-info": "^5.4.24|^6.2.11", - "symfony/uid": "^5.3|^6.0", - "symfony/validator": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0", - "symfony/var-exporter": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "psr/cache-implementation": "For using the metadata cache.", - "symfony/config": "For using the XML mapping loader.", - "symfony/mime": "For using a MIME type guesser within the DataUriNormalizer.", - "symfony/property-access": "For using the ObjectNormalizer.", - "symfony/property-info": "To deserialize relations.", - "symfony/var-exporter": "For using the metadata compiler.", - "symfony/yaml": "For using the default YAML mapping loader." + "seld/jsonlint": "^1.10", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4.26|^6.3|^7.0", + "symfony/property-info": "^5.4.24|^6.2.11|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -6079,7 +5934,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v5.4.34" + "source": "https://github.com/symfony/serializer/tree/v6.4.9" }, "funding": [ { @@ -6095,37 +5950,34 @@ "type": "tidelift" } ], - "time": "2023-12-27T08:53:17+00:00" + "time": "2024-06-28T07:59:05+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -6135,7 +5987,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6162,7 +6017,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" }, "funding": [ { @@ -6178,38 +6033,38 @@ "type": "tidelift" } ], - "time": "2022-05-30T19:17:29+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/string", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "e3f98bfc7885c957488f443df82d97814a3ce061" + "reference": "76792dbd99690a5ebef8050d9206c60c59e681d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e3f98bfc7885c957488f443df82d97814a3ce061", - "reference": "e3f98bfc7885c957488f443df82d97814a3ce061", + "url": "https://api.github.com/repos/symfony/string/zipball/76792dbd99690a5ebef8050d9206c60c59e681d7", + "reference": "76792dbd99690a5ebef8050d9206c60c59e681d7", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": ">=3.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -6248,7 +6103,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.34" + "source": "https://github.com/symfony/string/tree/v6.4.9" }, "funding": [ { @@ -6264,57 +6119,55 @@ "type": "tidelift" } ], - "time": "2023-12-09T13:20:28+00:00" + "time": "2024-06-28T09:25:38+00:00" }, { "name": "symfony/translation", - "version": "v5.4.31", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "ba72f72fceddf36f00bd495966b5873f2d17ad8f" + "reference": "a002933b13989fc4bd0b58e04bf7eec5210e438a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/ba72f72fceddf36f00bd495966b5873f2d17ad8f", - "reference": "ba72f72fceddf36f00bd495966b5873f2d17ad8f", + "url": "https://api.github.com/repos/symfony/translation/zipball/a002933b13989fc4bd0b58e04bf7eec5210e438a", + "reference": "a002933b13989fc4bd0b58e04bf7eec5210e438a", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16", - "symfony/translation-contracts": "^2.3" + "symfony/translation-contracts": "^2.5|^3.0" }, "conflict": { - "symfony/config": "<4.4", - "symfony/console": "<5.3", - "symfony/dependency-injection": "<5.0", - "symfony/http-kernel": "<5.0", - "symfony/twig-bundle": "<5.0", - "symfony/yaml": "<4.4" + "symfony/config": "<5.4", + "symfony/console": "<5.4", + "symfony/dependency-injection": "<5.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<5.4", + "symfony/yaml": "<5.4" }, "provide": { - "symfony/translation-implementation": "2.3" + "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { + "nikic/php-parser": "^4.18|^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/console": "^5.4|^6.0", - "symfony/dependency-injection": "^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/http-client-contracts": "^1.1|^2.0|^3.0", - "symfony/http-kernel": "^5.0|^6.0", - "symfony/intl": "^4.4|^5.0|^6.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/service-contracts": "^1.1.2|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "psr/log-implementation": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" + "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -6345,7 +6198,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.4.31" + "source": "https://github.com/symfony/translation/tree/v6.4.8" }, "funding": [ { @@ -6361,32 +6214,29 @@ "type": "tidelift" } ], - "time": "2023-11-03T16:16:43+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/translation-contracts", - "version": "v2.5.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe" + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe", - "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", "shasum": "" }, "require": { - "php": ">=7.2.5" - }, - "suggest": { - "symfony/translation-implementation": "" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -6396,7 +6246,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Translation\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6423,7 +6276,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" }, "funding": [ { @@ -6439,20 +6292,20 @@ "type": "tidelift" } ], - "time": "2022-06-27T16:58:25+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/uid", - "version": "v6.4.0", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "8092dd1b1a41372110d06374f99ee62f7f0b9a92" + "reference": "35904eca37a84bb764c560cbfcac9f0ac2bcdbdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/8092dd1b1a41372110d06374f99ee62f7f0b9a92", - "reference": "8092dd1b1a41372110d06374f99ee62f7f0b9a92", + "url": "https://api.github.com/repos/symfony/uid/zipball/35904eca37a84bb764c560cbfcac9f0ac2bcdbdf", + "reference": "35904eca37a84bb764c560cbfcac9f0ac2bcdbdf", "shasum": "" }, "require": { @@ -6497,7 +6350,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v6.4.0" + "source": "https://github.com/symfony/uid/tree/v6.4.8" }, "funding": [ { @@ -6513,75 +6366,59 @@ "type": "tidelift" } ], - "time": "2023-10-31T08:18:17+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/validator", - "version": "v5.4.34", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "0700751f19b5e8dcfadb6614662216a93f37e2dd" + "reference": "ee0a4d6a327a963aee094f730da238f7ea18cb01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/0700751f19b5e8dcfadb6614662216a93f37e2dd", - "reference": "0700751f19b5e8dcfadb6614662216a93f37e2dd", + "url": "https://api.github.com/repos/symfony/validator/zipball/ee0a4d6a327a963aee094f730da238f7ea18cb01", + "reference": "ee0a4d6a327a963aee094f730da238f7ea18cb01", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22", - "symfony/translation-contracts": "^1.1|^2|^3" + "symfony/polyfill-php83": "^1.27", + "symfony/translation-contracts": "^2.5|^3" }, "conflict": { "doctrine/annotations": "<1.13", - "doctrine/cache": "<1.11", "doctrine/lexer": "<1.1", - "symfony/dependency-injection": "<4.4", - "symfony/expression-language": "<5.1", - "symfony/http-kernel": "<4.4", - "symfony/intl": "<4.4", - "symfony/property-info": "<5.3", - "symfony/translation": "<4.4", - "symfony/yaml": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/expression-language": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/intl": "<5.4", + "symfony/property-info": "<5.4", + "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", + "symfony/yaml": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.13|^2", - "doctrine/cache": "^1.11|^2.0", "egulias/email-validator": "^2.1.10|^3|^4", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^5.1|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/http-kernel": "^4.4|^5.0|^6.0", - "symfony/intl": "^4.4|^5.0|^6.0", - "symfony/mime": "^4.4|^5.0|^6.0", - "symfony/property-access": "^4.4|^5.0|^6.0", - "symfony/property-info": "^5.3|^6.0", - "symfony/translation": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "egulias/email-validator": "Strict (RFC compliant) email validation", - "psr/cache-implementation": "For using the mapping cache.", - "symfony/config": "", - "symfony/expression-language": "For using the Expression validator and the ExpressionLanguageSyntax constraints", - "symfony/http-foundation": "", - "symfony/intl": "", - "symfony/property-access": "For accessing properties within comparison constraints", - "symfony/property-info": "To automatically add NotNull and Type constraints", - "symfony/translation": "For translating validation errors.", - "symfony/yaml": "" + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -6589,7 +6426,8 @@ "Symfony\\Component\\Validator\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/Resources/bin/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -6609,7 +6447,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v5.4.34" + "source": "https://github.com/symfony/validator/tree/v6.4.9" }, "funding": [ { @@ -6625,20 +6463,20 @@ "type": "tidelift" } ], - "time": "2023-12-29T15:57:36+00:00" + "time": "2024-06-22T07:42:41+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.2", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "68d6573ec98715ddcae5a0a85bee3c1c27a4c33f" + "reference": "c31566e4ca944271cc8d8ac6887cbf31b8c6a172" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/68d6573ec98715ddcae5a0a85bee3c1c27a4c33f", - "reference": "68d6573ec98715ddcae5a0a85bee3c1c27a4c33f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c31566e4ca944271cc8d8ac6887cbf31b8c6a172", + "reference": "c31566e4ca944271cc8d8ac6887cbf31b8c6a172", "shasum": "" }, "require": { @@ -6694,7 +6532,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.2" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.9" }, "funding": [ { @@ -6710,20 +6548,20 @@ "type": "tidelift" } ], - "time": "2023-12-28T19:16:56+00:00" + "time": "2024-06-27T13:23:14+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.2", + "version": "v6.4.9", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "5fe9a0021b8d35e67d914716ec8de50716a68e7e" + "reference": "f9a060622e0d93777b7f8687ec4860191e16802e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/5fe9a0021b8d35e67d914716ec8de50716a68e7e", - "reference": "5fe9a0021b8d35e67d914716ec8de50716a68e7e", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/f9a060622e0d93777b7f8687ec4860191e16802e", + "reference": "f9a060622e0d93777b7f8687ec4860191e16802e", "shasum": "" }, "require": { @@ -6731,6 +6569,8 @@ "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", @@ -6769,7 +6609,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.2" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.9" }, "funding": [ { @@ -6785,35 +6625,32 @@ "type": "tidelift" } ], - "time": "2023-12-27T08:18:35+00:00" + "time": "2024-06-24T15:53:56+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.31", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "f387675d7f5fc4231f7554baa70681f222f73563" + "reference": "52903de178d542850f6f341ba92995d3d63e60c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/f387675d7f5fc4231f7554baa70681f222f73563", - "reference": "f387675d7f5fc4231f7554baa70681f222f73563", + "url": "https://api.github.com/repos/symfony/yaml/zipball/52903de178d542850f6f341ba92995d3d63e60c9", + "reference": "52903de178d542850f6f341ba92995d3d63e60c9", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<5.3" + "symfony/console": "<5.4" }, "require-dev": { - "symfony/console": "^5.3|^6.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" + "symfony/console": "^5.4|^6.0|^7.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -6844,7 +6681,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.31" + "source": "https://github.com/symfony/yaml/tree/v6.4.8" }, "funding": [ { @@ -6860,7 +6697,7 @@ "type": "tidelift" } ], - "time": "2023-11-03T14:41:28+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "webmozart/assert", @@ -7022,499 +6859,3545 @@ ], "packages-dev": [ { - "name": "myclabs/deep-copy", - "version": "1.11.1", + "name": "behat/behat", + "version": "v3.14.0", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "url": "https://github.com/Behat/Behat.git", + "reference": "2a3832d9cb853a794af3a576f9e524ae460f3340" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/Behat/Behat/zipball/2a3832d9cb853a794af3a576f9e524ae460f3340", + "reference": "2a3832d9cb853a794af3a576f9e524ae460f3340", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "behat/gherkin": "^4.9.0", + "behat/transliterator": "^1.2", + "ext-mbstring": "*", + "php": "^7.2 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/config": "^4.4 || ^5.0 || ^6.0 || ^7.0", + "symfony/console": "^4.4 || ^5.0 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0 || ^7.0", + "symfony/event-dispatcher": "^4.4 || ^5.0 || ^6.0 || ^7.0", + "symfony/translation": "^4.4 || ^5.0 || ^6.0 || ^7.0", + "symfony/yaml": "^4.4 || ^5.0 || ^6.0 || ^7.0" }, "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + "herrera-io/box": "~1.6.1", + "phpspec/prophecy": "^1.15", + "phpunit/phpunit": "^8.5 || ^9.0", + "symfony/process": "^4.4 || ^5.0 || ^6.0 || ^7.0", + "vimeo/psalm": "^4.8" + }, + "suggest": { + "ext-dom": "Needed to output test results in JUnit format." }, + "bin": [ + "bin/behat" + ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], "psr-4": { - "DeepCopy\\": "src/DeepCopy/" + "Behat\\Hook\\": "src/Behat/Hook/", + "Behat\\Step\\": "src/Behat/Step/", + "Behat\\Behat\\": "src/Behat/Behat/", + "Behat\\Testwork\\": "src/Behat/Testwork/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Create deep copies (clones) of your objects", + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Scenario-oriented BDD framework for PHP", + "homepage": "http://behat.org/", "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" + "Agile", + "BDD", + "ScenarioBDD", + "Scrum", + "StoryBDD", + "User story", + "business", + "development", + "documentation", + "examples", + "symfony", + "testing" ], "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "issues": "https://github.com/Behat/Behat/issues", + "source": "https://github.com/Behat/Behat/tree/v3.14.0" }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2023-12-09T13:55:02+00:00" }, { - "name": "phar-io/manifest", - "version": "2.0.3", + "name": "behat/gherkin", + "version": "v4.9.0", "source": { "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "url": "https://github.com/Behat/Gherkin.git", + "reference": "0bc8d1e30e96183e4f36db9dc79caead300beff4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/0bc8d1e30e96183e4f36db9dc79caead300beff4", + "reference": "0bc8d1e30e96183e4f36db9dc79caead300beff4", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" + "php": "~7.2|~8.0" + }, + "require-dev": { + "cucumber/cucumber": "dev-gherkin-22.0.0", + "phpunit/phpunit": "~8|~9", + "symfony/yaml": "~3|~4|~5" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "4.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-0": { + "Behat\\Gherkin": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" } ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "description": "Gherkin DSL parser for PHP", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "issues": "https://github.com/Behat/Gherkin/issues", + "source": "https://github.com/Behat/Gherkin/tree/v4.9.0" }, - "time": "2021-07-20T11:28:43+00:00" + "time": "2021-10-12T13:05:09+00:00" }, { - "name": "phar-io/version", - "version": "3.2.1", + "name": "behat/transliterator", + "version": "v1.5.0", "source": { "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + "url": "https://github.com/Behat/Transliterator.git", + "reference": "baac5873bac3749887d28ab68e2f74db3a4408af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "url": "https://api.github.com/repos/Behat/Transliterator/zipball/baac5873bac3749887d28ab68e2f74db3a4408af", + "reference": "baac5873bac3749887d28ab68e2f74db3a4408af", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": ">=7.2" + }, + "require-dev": { + "chuyskywalker/rolling-curl": "^3.1", + "php-yaoi/php-yaoi": "^1.0", + "phpunit/phpunit": "^8.5.25 || ^9.5.19" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Behat\\Transliterator\\": "src/Behat/Transliterator" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "Artistic-1.0" ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } + "description": "String transliterator", + "keywords": [ + "i18n", + "slug", + "transliterator" ], - "description": "Library for handling version information and constraints", "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" + "issues": "https://github.com/Behat/Transliterator/issues", + "source": "https://github.com/Behat/Transliterator/tree/v1.5.0" }, - "time": "2022-02-21T01:04:05+00:00" + "time": "2022-03-30T09:27:43+00:00" }, { - "name": "phpstan/phpstan", - "version": "1.10.54", + "name": "cebe/php-openapi", + "version": "1.7.0", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "3e25f279dada0adc14ffd7bad09af2e2fc3523bb" + "url": "https://github.com/cebe/php-openapi.git", + "reference": "020d72b8e3a9a60bc229953e93eda25c49f46f45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3e25f279dada0adc14ffd7bad09af2e2fc3523bb", - "reference": "3e25f279dada0adc14ffd7bad09af2e2fc3523bb", + "url": "https://api.github.com/repos/cebe/php-openapi/zipball/020d72b8e3a9a60bc229953e93eda25c49f46f45", + "reference": "020d72b8e3a9a60bc229953e93eda25c49f46f45", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "ext-json": "*", + "justinrainbow/json-schema": "^5.2", + "php": ">=7.1.0", + "symfony/yaml": "^3.4 || ^4 || ^5 || ^6" }, "conflict": { - "phpstan/phpstan-shim": "*" + "symfony/yaml": "3.4.0 - 3.4.4 || 4.0.0 - 4.4.17 || 5.0.0 - 5.1.9 || 5.2.0" + }, + "require-dev": { + "apis-guru/openapi-directory": "1.0.0", + "cebe/indent": "*", + "mermade/openapi3-examples": "1.0.0", + "nexmo/api-specification": "1.0.0", + "oai/openapi-specification": "3.0.3", + "phpstan/phpstan": "^0.12.0", + "phpunit/phpunit": "^6.5 || ^7.5 || ^8.5 || ^9.4" }, "bin": [ - "phpstan", - "phpstan.phar" + "bin/php-openapi" ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, "autoload": { - "files": [ - "bootstrap.php" - ] + "psr-4": { + "cebe\\openapi\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "PHPStan - PHP Static Analysis Tool", + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "https://cebe.cc/", + "role": "Creator" + } + ], + "description": "Read and write OpenAPI yaml/json files and make the content accessable in PHP objects.", + "homepage": "https://github.com/cebe/php-openapi#readme", "keywords": [ - "dev", - "static analysis" + "openapi" ], "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" + "issues": "https://github.com/cebe/php-openapi/issues", + "source": "https://github.com/cebe/php-openapi" + }, + "time": "2022-04-20T14:46:44+00:00" + }, + { + "name": "centreon/centreon-test-lib", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/centreon/centreon-test-lib.git", + "reference": "d686936d55f7d2d20ee3ebcece13c12c6e6001db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/centreon/centreon-test-lib/zipball/d686936d55f7d2d20ee3ebcece13c12c6e6001db", + "reference": "d686936d55f7d2d20ee3ebcece13c12c6e6001db", + "shasum": "" + }, + "require": { + "behat/behat": "^3.0", + "friendsofphp/php-cs-fixer": "^3.10", + "guzzlehttp/guzzle": "^7.3", + "justinrainbow/json-schema": "^5.2", + "league/openapi-psr7-validator": "^0.17", + "nyholm/psr7": "^1.3", + "pestphp/pest": "^1.9", + "phpstan/phpstan": "~1.10.0", + "psr/http-client": "^1.0", + "symfony/console": "^6.4", + "symfony/http-client": "^6.4.0", + "symfony/property-access": "^6.4.0", + "webmozart/assert": "^1.9" + }, + "suggest": { + "behat/mink": "Browser controller/emulator abstraction for PHP", + "behat/mink-selenium2-driver": "Mink driver using Selenium", + "phpstan/phpstan": "PHP static analysis" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Centreon\\Command\\": "src/Command", + "Centreon\\PHPStan\\": "src/PHPStan", + "Centreon\\Test\\Mock\\": "src/mock", + "Centreon\\PhpCsFixer\\": "src/PhpCsFixer", + "Centreon\\Test\\Behat\\": "src/behat", + "Centreon\\Test\\Traits\\": "src/traits" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Library using for Behat test and PHPUnit test", + "keywords": [ + "Behat", + "centreon", + "phpunit", + "testing" + ], + "support": { + "issues": "https://github.com/centreon/centreon-test-lib/issues", + "source": "https://github.com/centreon/centreon-test-lib/tree/master" + }, + "time": "2024-06-03T09:51:01+00:00" + }, + { + "name": "clue/ndjson-react", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/clue/reactphp-ndjson.git", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "react/event-loop": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\React\\NDJson\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", + "homepage": "https://github.com/clue/reactphp-ndjson", + "keywords": [ + "NDJSON", + "json", + "jsonlines", + "newline", + "reactphp", + "streaming" + ], + "support": { + "issues": "https://github.com/clue/reactphp-ndjson/issues", + "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" }, "funding": [ { - "url": "https://github.com/ondrejmirtes", + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", "type": "github" + } + ], + "time": "2022-12-23T10:58:28+00:00" + }, + { + "name": "composer/pcre", + "version": "3.1.4", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "04229f163664973f68f38f6f73d917799168ef24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/04229f163664973f68f38f6f73d917799168ef24", + "reference": "04229f163664973f68f38f6f73d917799168ef24", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.1.4" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" }, { - "url": "https://github.com/phpstan", + "url": "https://github.com/composer", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "url": "https://tidelift.com/funding/github/packagist/composer/composer", "type": "tidelift" } ], - "time": "2024-01-05T15:50:47+00:00" + "time": "2024-05-27T13:40:54+00:00" }, { - "name": "phpunit/php-code-coverage", - "version": "7.0.15", + "name": "composer/semver", + "version": "3.4.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "819f92bba8b001d4363065928088de22f25a3a48" + "url": "https://github.com/composer/semver.git", + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/819f92bba8b001d4363065928088de22f25a3a48", - "reference": "819f92bba8b001d4363065928088de22f25a3a48", + "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": ">=7.2", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.1.3 || ^4.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^4.2.2", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1.3" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^8.2.2" - }, - "suggest": { - "ext-xdebug": "^2.7.2" + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.0-dev" + "dev-main": "3.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Composer\\Semver\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2023-08-31T09:50:34+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-05-06T16:37:16+00:00" + }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^1.9.2", + "phpstan/phpstan-deprecation-rules": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.2.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2024-02-07T09:43:46+00:00" + }, + { + "name": "filp/whoops", + "version": "2.15.4", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/a139776fa3f5985a50b509f2a02ff0f709d2a546", + "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.15.4" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2023-11-03T12:00:00+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.59.3", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "30ba9ecc2b0e5205e578fe29973c15653d9bfd29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/30ba9ecc2b0e5205e578fe29973c15653d9bfd29", + "reference": "30ba9ecc2b0e5205e578fe29973c15653d9bfd29", + "shasum": "" + }, + "require": { + "clue/ndjson-react": "^1.0", + "composer/semver": "^3.4", + "composer/xdebug-handler": "^3.0.3", + "ext-filter": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "fidry/cpu-core-counter": "^1.0", + "php": "^7.4 || ^8.0", + "react/child-process": "^0.6.5", + "react/event-loop": "^1.0", + "react/promise": "^2.0 || ^3.0", + "react/socket": "^1.0", + "react/stream": "^1.0", + "sebastian/diff": "^4.0 || ^5.0 || ^6.0", + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", + "symfony/finder": "^5.4 || ^6.0 || ^7.0", + "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0", + "symfony/polyfill-mbstring": "^1.28", + "symfony/polyfill-php80": "^1.28", + "symfony/polyfill-php81": "^1.28", + "symfony/process": "^5.4 || ^6.0 || ^7.0", + "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "facile-it/paraunit": "^1.3 || ^2.3", + "infection/infection": "^0.29.5", + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^2.1", + "mikey179/vfsstream": "^1.6.11", + "php-coveralls/php-coveralls": "^2.7", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", + "phpunit/phpunit": "^9.6.19 || ^10.5.21 || ^11.2", + "symfony/var-dumper": "^5.4 || ^6.0 || ^7.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + }, + "exclude-from-classmap": [ + "src/Fixer/Internal/*" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "keywords": [ + "Static code analysis", + "fixer", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.59.3" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2024-06-16T14:17:03+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.8.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.8.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2023-12-03T20:35:24+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-12-03T20:19:20+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.6.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.6.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-12-03T20:05:35+00:00" + }, + { + "name": "league/openapi-psr7-validator", + "version": "0.17", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/openapi-psr7-validator.git", + "reference": "c3daf7cc679a8c40c591a0272392ab726b92844f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/openapi-psr7-validator/zipball/c3daf7cc679a8c40c591a0272392ab726b92844f", + "reference": "c3daf7cc679a8c40c591a0272392ab726b92844f", + "shasum": "" + }, + "require": { + "cebe/php-openapi": "^1.6", + "ext-json": "*", + "league/uri": "^6.3", + "php": ">=7.2", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "psr/http-message": "^1.0", + "psr/http-server-middleware": "^1.0", + "respect/validation": "^1.1.3 || ^2.0", + "riverline/multipart-parser": "^2.0.3", + "webmozart/assert": "^1.4" + }, + "require-dev": { + "doctrine/coding-standard": "^8.0", + "guzzlehttp/psr7": "^1.5", + "hansott/psr7-cookies": "^3.0.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-webmozart-assert": "^1", + "phpunit/phpunit": "^7 || ^8 || ^9", + "symfony/cache": "^5.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\OpenAPIValidation\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Validate PSR-7 messages against OpenAPI (3.0.2) specifications expressed in YAML or JSON", + "homepage": "https://github.com/thephpleague/openapi-psr7-validator", + "keywords": [ + "http", + "openapi", + "psr7", + "validation" + ], + "support": { + "issues": "https://github.com/thephpleague/openapi-psr7-validator/issues", + "source": "https://github.com/thephpleague/openapi-psr7-validator/tree/0.17" + }, + "time": "2022-02-10T13:54:23+00:00" + }, + { + "name": "league/uri", + "version": "6.8.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/a700b4656e4c54371b799ac61e300ab25a2d1d39", + "reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39", + "shasum": "" + }, + "require": { + "ext-json": "*", + "league/uri-interfaces": "^2.3", + "php": "^8.1", + "psr/http-message": "^1.0.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v3.9.5", + "nyholm/psr7": "^1.5.1", + "php-http/psr7-integration-tests": "^1.1.1", + "phpbench/phpbench": "^1.2.6", + "phpstan/phpstan": "^1.8.5", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.1.1", + "phpstan/phpstan-strict-rules": "^1.4.3", + "phpunit/phpunit": "^9.5.24", + "psr/http-factory": "^1.0.1" + }, + "suggest": { + "ext-fileinfo": "Needed to create Data URI from a filepath", + "ext-intl": "Needed to improve host validation", + "league/uri-components": "Needed to easily manipulate URI objects", + "psr/http-factory": "Needed to use the URI factory" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri/issues", + "source": "https://github.com/thephpleague/uri/tree/6.8.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2022-09-13T19:58:47+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/00e7e2943f76d8cb50c7dfdc2f6dee356e15e383", + "reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.19", + "phpstan/phpstan": "^0.12.90", + "phpstan/phpstan-phpunit": "^0.12.19", + "phpstan/phpstan-strict-rules": "^0.12.9", + "phpunit/phpunit": "^8.5.15 || ^9.5" + }, + "suggest": { + "ext-intl": "to use the IDNA feature", + "symfony/intl": "to use the IDNA feature via Symfony Polyfill" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interface for URI representation", + "homepage": "http://github.com/thephpleague/uri-interfaces", + "keywords": [ + "rfc3986", + "rfc3987", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/thephpleague/uri-interfaces/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2021-06-28T04:27:21+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.12.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2024-06-12T14:39:25+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "f05978827b9343cba381ca05b8c7deee346b6015" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/f05978827b9343cba381ca05b8c7deee346b6015", + "reference": "f05978827b9343cba381ca05b8c7deee346b6015", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.14.5", + "php": "^8.0.0", + "symfony/console": "^6.0.2" + }, + "require-dev": { + "brianium/paratest": "^6.4.1", + "laravel/framework": "^9.26.1", + "laravel/pint": "^1.1.1", + "nunomaduro/larastan": "^1.0.3", + "nunomaduro/mock-final-classes": "^1.1.0", + "orchestra/testbench": "^7.7", + "phpunit/phpunit": "^9.5.23", + "spatie/ignition": "^1.4.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "6.x-dev" + }, + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2023-01-03T12:54:54+00:00" + }, + { + "name": "nyholm/psr7", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "aa5fc277a4f5508013d571341ade0c3886d4d00e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/aa5fc277a4f5508013d571341ade0c3886d4d00e", + "reference": "aa5fc277a4f5508013d571341ade0c3886d4d00e", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0" + }, + "provide": { + "php-http/message-factory-implementation": "1.0", + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.9", + "php-http/message-factory": "^1.0", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4", + "symfony/error-handler": "^4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "https://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/Nyholm/psr7/issues", + "source": "https://github.com/Nyholm/psr7/tree/1.8.1" + }, + "funding": [ + { + "url": "https://github.com/Zegnat", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2023-11-13T09:31:12+00:00" + }, + { + "name": "pestphp/pest", + "version": "v1.23.1", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest.git", + "reference": "5c56ad8772b89611c72a07e23f6e30aa29dc677a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest/zipball/5c56ad8772b89611c72a07e23f6e30aa29dc677a", + "reference": "5c56ad8772b89611c72a07e23f6e30aa29dc677a", + "shasum": "" + }, + "require": { + "nunomaduro/collision": "^5.11.0|^6.4.0", + "pestphp/pest-plugin": "^1.1.0", + "php": "^7.3 || ^8.0", + "phpunit/phpunit": "^9.6.10" + }, + "require-dev": { + "illuminate/console": "^8.83.27", + "illuminate/support": "^8.83.27", + "laravel/dusk": "^6.25.2", + "pestphp/pest-dev-tools": "^1.0.0", + "pestphp/pest-plugin-parallel": "^1.2.1" + }, + "bin": [ + "bin/pest" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + }, + "pest": { + "plugins": [ + "Pest\\Plugins\\Coverage", + "Pest\\Plugins\\Init", + "Pest\\Plugins\\Version", + "Pest\\Plugins\\Environment" + ] + }, + "laravel": { + "providers": [ + "Pest\\Laravel\\PestServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/Functions.php", + "src/Pest.php" + ], + "psr-4": { + "Pest\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An elegant PHP Testing Framework.", + "keywords": [ + "framework", + "pest", + "php", + "test", + "testing", + "unit" + ], + "support": { + "issues": "https://github.com/pestphp/pest/issues", + "source": "https://github.com/pestphp/pest/tree/v1.23.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2023-07-12T19:42:47+00:00" + }, + { + "name": "pestphp/pest-plugin", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin.git", + "reference": "606c5f79c6a339b49838ffbee0151ca519efe378" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/606c5f79c6a339b49838ffbee0151ca519efe378", + "reference": "606c5f79c6a339b49838ffbee0151ca519efe378", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0.0", + "php": "^7.3 || ^8.0" + }, + "conflict": { + "pestphp/pest": "<1.0" + }, + "require-dev": { + "composer/composer": "^2.4.2", + "pestphp/pest": "^1.22.1", + "pestphp/pest-dev-tools": "^1.0.0" + }, + "type": "composer-plugin", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + }, + "class": "Pest\\Plugin\\Manager" + }, + "autoload": { + "psr-4": { + "Pest\\Plugin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Pest plugin manager", + "keywords": [ + "framework", + "manager", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin/tree/v1.1.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2022-09-18T13:18:17+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.10.67", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/16ddbe776f10da6a95ebd25de7c1dbed397dc493", + "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-04-16T07:22:02+00:00" + }, + { + "name": "phpstan/phpstan-beberlei-assert", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-beberlei-assert.git", + "reference": "0918f2c71f93d44839b74fe3ba2682b2083a8729" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-beberlei-assert/zipball/0918f2c71f93d44839b74fe3ba2682b2083a8729", + "reference": "0918f2c71f93d44839b74fe3ba2682b2083a8729", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.10" + }, + "require-dev": { + "beberlei/assert": "^3.3.0", + "nikic/php-parser": "^4.13.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan beberlei/assert extension", + "support": { + "issues": "https://github.com/phpstan/phpstan-beberlei-assert/issues", + "source": "https://github.com/phpstan/phpstan-beberlei-assert/tree/1.1.2" + }, + "time": "2023-09-04T12:13:01+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.31", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:37:42+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.19", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8", + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.28", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2024-04-05T04:35:58+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "time": "2023-04-04T09:50:52+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" + }, + "time": "2023-04-10T20:06:20+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" + }, + "time": "2023-04-11T06:14:47+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/child-process", + "version": "v0.6.5", + "source": { + "type": "git", + "url": "https://github.com/reactphp/child-process.git", + "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", + "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/event-loop": "^1.2", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", + "react/socket": "^1.8", + "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\ChildProcess\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven library for executing child processes with ReactPHP.", + "keywords": [ + "event-driven", + "process", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/child-process/issues", + "source": "https://github.com/reactphp/child-process/tree/v0.6.5" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-09-16T13:41:56+00:00" + }, + { + "name": "react/dns", + "version": "v1.13.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.13.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-13T14:18:03+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-13T13:48:05+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "react/socket", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/216d3aec0b87f04a40ca04f481e6af01bdd1d038", + "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.11", + "react/event-loop": "^1.2", + "react/promise": "^3 || ^2.6 || ^1.2.1", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4 || ^3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.15.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-12-15T11:02:10+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" } ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", "keywords": [ - "coverage", - "testing", - "xunit" + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.15" + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2021-07-26T12:20:09+00:00" + "time": "2024-06-11T12:45:25+00:00" }, { - "name": "phpunit/php-file-iterator", - "version": "2.0.5", + "name": "respect/stringifier", + "version": "0.2.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5" + "url": "https://github.com/Respect/Stringifier.git", + "reference": "e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", - "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", + "url": "https://api.github.com/repos/Respect/Stringifier/zipball/e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59", + "reference": "e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "friendsofphp/php-cs-fixer": "^2.8", + "malukenho/docheader": "^0.1.7", + "phpunit/phpunit": "^6.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { - "classmap": [ - "src/" - ] + "files": [ + "src/stringify.php" + ], + "psr-4": { + "Respect\\Stringifier\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Respect/Stringifier Contributors", + "homepage": "https://github.com/Respect/Stringifier/graphs/contributors" } ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "description": "Converts any value to a string", + "homepage": "http://respect.github.io/Stringifier/", "keywords": [ - "filesystem", - "iterator" + "respect", + "stringifier", + "stringify" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.5" + "issues": "https://github.com/Respect/Stringifier/issues", + "source": "https://github.com/Respect/Stringifier/tree/0.2.0" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-12-02T12:42:26+00:00" + "time": "2017-12-29T19:39:25+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "respect/validation", + "version": "2.3.7", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/Respect/Validation.git", + "reference": "967f7b6cc71e3728bb0f766cc1aea0604b2955aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/Respect/Validation/zipball/967f7b6cc71e3728bb0f766cc1aea0604b2955aa", + "reference": "967f7b6cc71e3728bb0f766cc1aea0604b2955aa", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^8.1 || ^8.2", + "respect/stringifier": "^0.2.0", + "symfony/polyfill-mbstring": "^1.2" + }, + "require-dev": { + "egulias/email-validator": "^3.0", + "giggsey/libphonenumber-for-php-lite": "^8.13", + "malukenho/docheader": "^1.0", + "mikey179/vfsstream": "^1.6", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.6", + "psr/http-message": "^1.0", + "respect/coding-standard": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "suggest": { + "egulias/email-validator": "Improves the Email rule if available", + "ext-bcmath": "Arbitrary Precision Mathematics", + "ext-fileinfo": "File Information", + "ext-mbstring": "Multibyte String Functions", + "giggsey/libphonenumber-for-php-lite": "Enables the phone rule if available" }, "type": "library", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Respect\\Validation\\": "library/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Respect/Validation Contributors", + "homepage": "https://github.com/Respect/Validation/graphs/contributors" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "description": "The most awesome validation engine ever created for PHP", + "homepage": "http://respect.github.io/Validation/", "keywords": [ - "template" + "respect", + "validation", + "validator" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + "issues": "https://github.com/Respect/Validation/issues", + "source": "https://github.com/Respect/Validation/tree/2.3.7" }, - "time": "2015-06-21T13:50:34+00:00" + "time": "2024-04-13T09:45:55+00:00" }, { - "name": "phpunit/php-timer", - "version": "2.1.3", + "name": "riverline/multipart-parser", + "version": "2.1.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" + "url": "https://github.com/Riverline/multipart-parser.git", + "reference": "7a9f4646db5181516c61b8e0225a343189beedcd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", - "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "url": "https://api.github.com/repos/Riverline/multipart-parser/zipball/7a9f4646db5181516c61b8e0225a343189beedcd", + "reference": "7a9f4646db5181516c61b8e0225a343189beedcd", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-mbstring": "*", + "php": ">=5.6.0" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "laminas/laminas-diactoros": "^1.8.7 || ^2.11.1", + "phpunit/phpunit": "^5.7 || ^9.0", + "psr/http-message": "^1.0", + "symfony/psr-http-message-bridge": "^1.1 || ^2.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } - }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Riverline\\MultiPartParser\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Romain Cambien", + "email": "romain@cambien.net" + }, + { + "name": "Riverline", + "homepage": "http://www.riverline.fr" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", + "description": "One class library to parse multipart content with encoding and charset support.", "keywords": [ - "timer" + "http", + "multipart", + "parser" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" + "issues": "https://github.com/Riverline/multipart-parser/issues", + "source": "https://github.com/Riverline/multipart-parser/tree/2.1.2" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T08:20:02+00:00" + "time": "2024-03-12T16:46:05+00:00" }, { - "name": "phpunit/php-token-stream", - "version": "4.0.4", + "name": "sebastian/cli-parser", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", - "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": "^7.3 || ^8.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -7529,17 +10412,15 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { - "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", - "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -7547,61 +10428,32 @@ "type": "github" } ], - "abandoned": true, - "time": "2020-08-04T08:28:15+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { - "name": "phpunit/phpunit", - "version": "8.5.36", + "name": "sebastian/code-unit", + "version": "1.0.8", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "9652df58e06a681429d8cfdaec3c43d6de581d5a" + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9652df58e06a681429d8cfdaec3c43d6de581d5a", - "reference": "9652df58e06a681429d8cfdaec3c43d6de581d5a", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.0", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", - "php": ">=7.2", - "phpunit/php-code-coverage": "^7.0.12", - "phpunit/php-file-iterator": "^2.0.4", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1.2", - "sebastian/comparator": "^3.0.5", - "sebastian/diff": "^3.0.2", - "sebastian/environment": "^4.2.3", - "sebastian/exporter": "^3.1.5", - "sebastian/global-state": "^3.0.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0.1", - "sebastian/type": "^1.1.3", - "sebastian/version": "^2.0.1" + "php": ">=7.3" }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage", - "phpunit/php-invoker": "To allow enforcing time limits" + "require-dev": { + "phpunit/phpunit": "^9.3" }, - "bin": [ - "phpunit" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "8.5-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -7620,58 +10472,44 @@ "role": "lead" } ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.36" + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" }, "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, { "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" } ], - "time": "2023-12-01T16:52:15+00:00" + "time": "2020-10-26T13:08:54+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -7693,7 +10531,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" }, "funding": [ { @@ -7701,34 +10539,34 @@ "type": "github" } ], - "time": "2020-11-30T08:15:22+00:00" + "time": "2020-09-28T05:30:19+00:00" }, { "name": "sebastian/comparator", - "version": "3.0.5", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770" + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dc7ceb4a24aede938c7af2a9ed1de09609ca770", - "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", "shasum": "" }, "require": { - "php": ">=7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -7767,7 +10605,64 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.5" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -7775,33 +10670,33 @@ "type": "github" } ], - "time": "2022-09-14T12:31:48+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", - "version": "3.0.4", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/6296a0c086dd0117c1b78b059374d7fcbe7545ae", - "reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -7833,7 +10728,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/3.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -7841,27 +10736,27 @@ "type": "github" } ], - "time": "2023-05-07T05:30:20+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", - "version": "4.2.4", + "version": "5.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", - "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-posix": "*" @@ -7869,7 +10764,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -7896,7 +10791,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { @@ -7904,34 +10799,34 @@ "type": "github" } ], - "time": "2020-11-30T07:53:42+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "73a9676f2833b9a7c36968f9d882589cd75511e6" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/73a9676f2833b9a7c36968f9d882589cd75511e6", - "reference": "73a9676f2833b9a7c36968f9d882589cd75511e6", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { - "php": ">=7.0", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -7961,19 +10856,83 @@ "email": "aharvey@php.net" }, { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:33:00+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ - "export", - "exporter" + "global state" ], "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.5" + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -7981,38 +10940,33 @@ "type": "github" } ], - "time": "2022-09-14T06:00:17+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { - "name": "sebastian/global-state", - "version": "3.0.3", + "name": "sebastian/lines-of-code", + "version": "1.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "66783ce213de415b451b904bfef9dda0cf9aeae0" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/66783ce213de415b451b904bfef9dda0cf9aeae0", - "reference": "66783ce213de415b451b904bfef9dda0cf9aeae0", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "php": ">=7.2", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" }, "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^8.0" - }, - "suggest": { - "ext-uopz": "*" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -8027,17 +10981,15 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.3" + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -8045,34 +10997,34 @@ "type": "github" } ], - "time": "2023-08-02T09:23:32+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", - "version": "3.0.4", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", - "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", "shasum": "" }, "require": { - "php": ">=7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -8094,7 +11046,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" }, "funding": [ { @@ -8102,32 +11054,32 @@ "type": "github" } ], - "time": "2020-11-30T07:40:27+00:00" + "time": "2020-10-26T13:12:34+00:00" }, { "name": "sebastian/object-reflector", - "version": "1.1.2", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", - "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": ">=7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -8149,7 +11101,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" }, "funding": [ { @@ -8157,32 +11109,32 @@ "type": "github" } ], - "time": "2020-11-30T07:37:18+00:00" + "time": "2020-10-26T13:14:26+00:00" }, { "name": "sebastian/recursion-context", - "version": "3.0.1", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", - "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { - "php": ">=7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -8209,10 +11161,10 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, "funding": [ { @@ -8220,29 +11172,32 @@ "type": "github" } ], - "time": "2020-11-30T07:34:24+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", - "version": "2.0.2", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", - "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -8263,8 +11218,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -8272,32 +11226,32 @@ "type": "github" } ], - "time": "2020-11-30T07:30:19+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", - "version": "1.1.4", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4" + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0150cfbc4495ed2df3872fb31b26781e4e077eb4", - "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.2" + "phpunit/phpunit": "^9.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -8320,7 +11274,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/1.1.4" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, "funding": [ { @@ -8328,29 +11282,29 @@ "type": "github" } ], - "time": "2020-11-30T07:25:11+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -8373,22 +11327,28 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/master" + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" }, - "time": "2016-10-03T07:35:21+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.8.0", + "version": "3.10.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7" + "reference": "8f90f7a53ce271935282967f53d0894f8f1ff877" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/8f90f7a53ce271935282967f53d0894f8f1ff877", + "reference": "8f90f7a53ce271935282967f53d0894f8f1ff877", "shasum": "" }, "require": { @@ -8398,11 +11358,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -8455,20 +11415,238 @@ "type": "open_collective" } ], - "time": "2023-12-08T12:32:31+00:00" + "time": "2024-05-22T21:24:41+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/3fb075789fb91f9ad9af537c4012d523085bd5af", + "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v6.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "63e069eb616049632cde9674c46957819454b8aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/63e069eb616049632cde9674c46957819454b8aa", + "reference": "63e069eb616049632cde9674c46957819454b8aa", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v6.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:49:08+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -8497,7 +11675,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -8505,17 +11683,21 @@ "type": "github" } ], - "time": "2023-11-20T00:12:19+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], "minimum-stability": "stable", "stability-flags": { - "centreon/centreon": 20 + "centreon/centreon": 20, + "centreon/centreon-test-lib": 20 }, "prefer-stable": false, "prefer-lowest": false, - "platform": [], + "platform": { + "ext-openssl": "*", + "ext-json": "*" + }, "platform-dev": [], "platform-overrides": { "php": "8.1" diff --git a/centreon-open-tickets/config/packages/dev/CentreonOpenTickets.yaml b/centreon-open-tickets/config/packages/dev/CentreonOpenTickets.yaml new file mode 100644 index 0000000000..b3d93cd8c5 --- /dev/null +++ b/centreon-open-tickets/config/packages/dev/CentreonOpenTickets.yaml @@ -0,0 +1,8 @@ +services: + _defaults: + public: false + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, controller... + + CentreonOpenTickets\: + resource: '../../../src/CentreonOpenTickets/*' diff --git a/centreon-open-tickets/config/packages/prod/CentreonOpenTickets.yaml b/centreon-open-tickets/config/packages/prod/CentreonOpenTickets.yaml new file mode 100644 index 0000000000..530eea4e85 --- /dev/null +++ b/centreon-open-tickets/config/packages/prod/CentreonOpenTickets.yaml @@ -0,0 +1,14 @@ +services: + _defaults: + public: false + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, controller... + + CentreonOpenTickets\: + resource: '../../../src/CentreonOpenTickets/*' + + _instanceof: + Core\Resources\Infrastructure\Repository\ExtraDataProviders\ExtraDataProviderInterface: + tags: ['monitoring.resource.extra.providers'] + Core\Resources\Infrastructure\API\ExtraDataNormalizer\ExtraDataNormalizerInterface: + tags: ['monitoring.resource.extra.normalizers'] diff --git a/centreon-open-tickets/config/packages/prod/CentreonResourcesOpenTicket.php b/centreon-open-tickets/config/packages/prod/CentreonResourcesOpenTicket.php new file mode 100644 index 0000000000..12601dfd3e --- /dev/null +++ b/centreon-open-tickets/config/packages/prod/CentreonResourcesOpenTicket.php @@ -0,0 +1,42 @@ +services(); + + $services->get(OpenTicketExtraDataProvider::class) + ->tag('monitoring.resource.extra.providers'); + + $services->get(TicketExtraDataFormatter::class) + ->tag('monitoring.resource.extra.presenter.providers'); + } +}; + diff --git a/centreon-open-tickets/config/routes/CentreonOpenTickets.yaml b/centreon-open-tickets/config/routes/CentreonOpenTickets.yaml new file mode 100644 index 0000000000..3584af598f --- /dev/null +++ b/centreon-open-tickets/config/routes/CentreonOpenTickets.yaml @@ -0,0 +1,8 @@ +open_tickets: + prefix: "/{base_uri}api/{version}/open-tickets" + resource: '../../www/modules/centreon-open-tickets/routes/CentreonOpenTickets.yaml' + defaults: + base_uri: "centreon/" + version: "latest" + requirements: + base_uri: "(.+/)|.{0}" diff --git a/centreon-open-tickets/doc/API/centreon-logo.png b/centreon-open-tickets/doc/API/centreon-logo.png new file mode 100644 index 0000000000..a34220331f Binary files /dev/null and b/centreon-open-tickets/doc/API/centreon-logo.png differ diff --git a/centreon-open-tickets/doc/API/centreon-open-tickets-api.yaml b/centreon-open-tickets/doc/API/centreon-open-tickets-api.yaml new file mode 100644 index 0000000000..e43dd592ab --- /dev/null +++ b/centreon-open-tickets/doc/API/centreon-open-tickets-api.yaml @@ -0,0 +1,61 @@ +openapi: 3.0.1 +info: + title: Centreon Open Tickets API + description: | + # New features + + # Authentication + There are two modes of authentication: + * By token: after identification with your login credentials + * By cookie: by reusing a valid session ID + x-logo: + url: ./centreon-logo.png + contact: + url: 'https://www.centreon.com' + version: "v24.10" +servers: + - url: '{protocol}://{server}:{port}/centreon/api/{version}/open-tickets' + variables: + protocol: + enum: + - http + - https + default: http + description: "HTTP schema" + server: + default: localhost + description: "IP address or hostname of Centreon server" + port: + default: '80' + description: "Port used by HTTP server" + version: + enum: + - latest + - v24.10 + default: latest + description: "Version of the API" +security: + - Token: [] + - Cookie: [] +paths: + /providers: + $ref: './latest/Configuration/Providers.yaml' + securitySchemes: + Token: + description: | + The use of the API requires a security token. + + To retrieve it, you will need to authenticate yourself with your login credentials. + + The token will be deleted if it has not been used for more than one hour. + type: apiKey + name: X-AUTH-TOKEN + in: header + Cookie: + description: | + If you have already connected on the Centreon web application, you can reused the PHPSESSID cookie. + + The cookie will be valid as long as the connection to Centreon is maintained. + type: apiKey + name: PHPSESSID + in: cookie diff --git a/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Limit.yaml b/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Limit.yaml new file mode 100644 index 0000000000..b0e2f945b4 --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Limit.yaml @@ -0,0 +1,9 @@ +in: query +name: limit +required: false +description: "Number of items per page" +schema: + type: integer + minimum: 1 + default: 10 + example: 20 diff --git a/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Page.yaml b/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Page.yaml new file mode 100644 index 0000000000..b598be1b6e --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Page.yaml @@ -0,0 +1,9 @@ +in: query +name: page +required: false +description: "Number of the requested page" +schema: + type: integer + minimum: 1 + default: 1 + example: 4 \ No newline at end of file diff --git a/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Search.yaml b/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Search.yaml new file mode 100644 index 0000000000..6e0ca03e18 --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/QueryParameter/Search.yaml @@ -0,0 +1,69 @@ +in: query +name: search +required: false +schema: + type: string +description: > + Retrieve only data matching the defined search value. + + A simple search can be done like in the following example + ``` + search={"host.name":"Central"} + ``` + + A complex search can be done with aggregators and operators. + + Available search aggregators are: + * `$or` + * `$and` + + Available search operators are: + * `$eq` → equal + * `$neq` → not equal + * `$lt` → less than + * `$le` → less or equal than + * `$gt` → greater than + * `$ge` → greater or equal than + * `$lk` → like + * `$nk` → not like + * `$in` → in + * `$ni` → not in + * `$rg` → regex + + Examples without nested aggregators: + ``` + search={ + "$or":[ + {"host.name":{"$eq":"name_1"}}, + {"host.name":{"$eq":"name_2"}} + ] + } + ``` + ``` + search={ + "$and":[ + {"host.address":{"$rg":"^10\.0\.0\.\d+$"}}, + {"host.name":{"$lk":"fr%"}} + ] + } + ``` + + Example with nested aggregators: + ``` + search={ + "$or":[ + { + "$and":[ + {"host.address":{"$rg":"^10\.0\.0\.\d+$"}}, + {"host.name":{"$lk":"fr%"}} + ] + }, + { + "$and":[ + {"host.address":{"$rg":"^192\.168\.0\.\d+$"}}, + {"host.name":{"$lk":"us%"}} + ] + } + ] + } + ``` diff --git a/centreon-open-tickets/doc/API/latest/Common/QueryParameter/SortBy.yaml b/centreon-open-tickets/doc/API/latest/Common/QueryParameter/SortBy.yaml new file mode 100644 index 0000000000..f7d0547853 --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/QueryParameter/SortBy.yaml @@ -0,0 +1,8 @@ +in: query +name: sort_by +required: false +description: "Sort the resulting data by its properties" +schema: + type: string + example: '{"host.name":"ASC"}' + diff --git a/centreon-open-tickets/doc/API/latest/Common/Response/BadRequest.yaml b/centreon-open-tickets/doc/API/latest/Common/Response/BadRequest.yaml new file mode 100644 index 0000000000..d9ec146ecb --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/Response/BadRequest.yaml @@ -0,0 +1,15 @@ +description: | + Indicates that the server cannot or will not process the request due to something that is perceived to be + a client error (e.g., malformed request syntax, invalid request message framing) +content: + application/json: + schema: + type: object + properties: + code: + type: integer + format: int64 + example: 400 + message: + type: string + example: "Property 'name' not found" \ No newline at end of file diff --git a/centreon-open-tickets/doc/API/latest/Common/Response/Forbidden.yaml b/centreon-open-tickets/doc/API/latest/Common/Response/Forbidden.yaml new file mode 100644 index 0000000000..9c8bd17321 --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/Response/Forbidden.yaml @@ -0,0 +1,13 @@ +description: "Forbidden" +content: + application/json: + schema: + type: object + properties: + code: + type: integer + format: int64 + example: 403 + message: + type: string + example: "You are not authorized to access this resource" \ No newline at end of file diff --git a/centreon-open-tickets/doc/API/latest/Common/Response/InternalServerError.yaml b/centreon-open-tickets/doc/API/latest/Common/Response/InternalServerError.yaml new file mode 100644 index 0000000000..b57aed2c39 --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/Response/InternalServerError.yaml @@ -0,0 +1,13 @@ +description: "Internal Server Error" +content: + application/json: + schema: + type: object + properties: + code: + type: integer + format: int64 + example: 500 + message: + type: string + example: "Internal Server Error" \ No newline at end of file diff --git a/centreon-open-tickets/doc/API/latest/Common/Response/Unauthorized.yaml b/centreon-open-tickets/doc/API/latest/Common/Response/Unauthorized.yaml new file mode 100644 index 0000000000..dfefd5ba6a --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/Response/Unauthorized.yaml @@ -0,0 +1,12 @@ +description: "Unauthorized" +content: + application/json: + schema: + type: object + properties: + code: + type: integer + format: int64 + example: 401 + message: + type: string \ No newline at end of file diff --git a/centreon-open-tickets/doc/API/latest/Common/Schema/Meta.yaml b/centreon-open-tickets/doc/API/latest/Common/Schema/Meta.yaml new file mode 100644 index 0000000000..0836fb465a --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Common/Schema/Meta.yaml @@ -0,0 +1,20 @@ +type: object +properties: + page: + type: integer + description: "Number of the paginated page" + example: 1 + limit: + type: integer + description: "Number of items per page" + example: 10 + search: + type: object + description: "Search parameter passed to URL" + sort_by: + type: object + description: "Sort parameter passed to URL" + total: + type: integer + description: "Number of items found" + example: 1 diff --git a/centreon-open-tickets/doc/API/latest/Configuration/Providers.yaml b/centreon-open-tickets/doc/API/latest/Configuration/Providers.yaml new file mode 100644 index 0000000000..eda82610fe --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Configuration/Providers.yaml @@ -0,0 +1,36 @@ +get: + tags: + - Providers + summary: "Find all ticket providers configured" + description: | + Return all ticket providers configurations. + + The available parameters to **search** / **sort_by** are: + + * id + * name + * is_activated + parameters: + - $ref: '../Common/QueryParameter/Limit.yaml' + - $ref: '../Common/QueryParameter/Page.yaml' + - $ref: '../Common/QueryParameter/Search.yaml' + - $ref: '../Common/QueryParameter/SortBy.yaml' + responses: + '200': + description: "OK" + content: + application/json: + schema: + type: object + properties: + result: + type: array + items: + $ref: 'Schema/FindProvidersResponse.yaml' + meta: + $ref: '../Common/Schema/Meta.yaml' + '403': + $ref: '../Common/Response/Forbidden.yaml' + '500': + $ref: '../Common/Response/InternalServerError.yaml' + diff --git a/centreon-open-tickets/doc/API/latest/Configuration/Schema/FindProvidersResponse.yaml b/centreon-open-tickets/doc/API/latest/Configuration/Schema/FindProvidersResponse.yaml new file mode 100644 index 0000000000..a48dc356bf --- /dev/null +++ b/centreon-open-tickets/doc/API/latest/Configuration/Schema/FindProvidersResponse.yaml @@ -0,0 +1,22 @@ +type: object +properties: + id: + type: integer + description: "Provider ID (rule)" + example: 1 + nullable: false + name: + type: string + description: "Provider name (rule)" + example: "glpi" + nullable: false + type: + type: string + description: "Provider type (provider name)" + example: "GlpiApiRest" + nullable: false + is_activated: + type: boolean + description: "Indicates whether the provider configuration (rule) is activated or not" + nullable: false + diff --git a/centreon-open-tickets/packaging/centreon-open-tickets.yaml b/centreon-open-tickets/packaging/centreon-open-tickets.yaml index 38866f59b8..7ee537e882 100644 --- a/centreon-open-tickets/packaging/centreon-open-tickets.yaml +++ b/centreon-open-tickets/packaging/centreon-open-tickets.yaml @@ -15,6 +15,9 @@ homepage: "https://www.centreon.com" license: "Apache-2.0" contents: + - src: "../config" + dst: "/usr/share/centreon/config" + - src: "../www/modules/centreon-open-tickets" dst: "/usr/share/centreon/www/modules/centreon-open-tickets" file_info: @@ -22,6 +25,13 @@ contents: owner: "@APACHE_USER@" group: "@APACHE_GROUP@" + - src: "../src/CentreonOpenTickets" + dst: "/usr/share/centreon/src/CentreonOpenTickets" + file_info: + mode: 0644 + owner: "@APACHE_USER@" + group: "@APACHE_GROUP@" + - src: "../widgets/open-tickets" dst: "/usr/share/centreon/www/widgets/open-tickets" file_info: @@ -29,6 +39,9 @@ contents: owner: "@APACHE_USER@" group: "@APACHE_GROUP@" +scripts: + postinstall: ./scripts/centreon-open-tickets-postinstall.sh + overrides: rpm: depends: diff --git a/centreon-open-tickets/packaging/scripts/centreon-open-tickets-postinstall.sh b/centreon-open-tickets/packaging/scripts/centreon-open-tickets-postinstall.sh new file mode 100644 index 0000000000..e4f6a01517 --- /dev/null +++ b/centreon-open-tickets/packaging/scripts/centreon-open-tickets-postinstall.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# rebuild symfony cache on upgrade +if [ -f /etc/centreon/centreon.conf.php ]; then + if command -v rpm &> /dev/null; then + APACHE_GROUP="apache" + else + APACHE_GROUP="www-data" + fi + su - $APACHE_GROUP -s /bin/bash -c "/usr/share/centreon/bin/console cache:clear --no-warmup" +fi + diff --git a/centreon-open-tickets/phpstan.core.neon b/centreon-open-tickets/phpstan.core.neon new file mode 100644 index 0000000000..f04d90b73f --- /dev/null +++ b/centreon-open-tickets/phpstan.core.neon @@ -0,0 +1,4 @@ +parameters: + level: max + paths: + - src/CentreonOpenTickets diff --git a/centreon-open-tickets/phpstan.neon b/centreon-open-tickets/phpstan.neon index 9c0fad2475..54163a14e3 100644 --- a/centreon-open-tickets/phpstan.neon +++ b/centreon-open-tickets/phpstan.neon @@ -42,6 +42,7 @@ parameters: - www/modules/centreon-open-tickets/views - www/modules/centreon-open-tickets/providers/EasyVistaRest/ajax/call.php - www/modules/centreon-open-tickets/providers/Itop/ajax/call.php + - www/modules/centreon-open-tickets/upgrade/ message: "#^Variable \\$\\w+ might not be defined.$#" - diff --git a/centreon-open-tickets/phpunit.xml b/centreon-open-tickets/phpunit.xml new file mode 100644 index 0000000000..6609b6767c --- /dev/null +++ b/centreon-open-tickets/phpunit.xml @@ -0,0 +1,33 @@ + + + + + ./src/ + + + + + + + + + + + + + + + + + + ./tests/php/*/ + + + + + benchmark + intl-data + + + + diff --git a/centreon-open-tickets/src/CentreonOpenTickets/Providers/Application/Exception/ProviderException.php b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Application/Exception/ProviderException.php new file mode 100644 index 0000000000..7261ecf823 --- /dev/null +++ b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Application/Exception/ProviderException.php @@ -0,0 +1,43 @@ +contact->hasTopologyRole(self::ROLE_CONFIGURATION_OPEN_TICKETS)) { + $this->error( + "User doesn't have sufficient rights to get ticket providers information", + [ + 'user_id' => $this->contact->getId(), + ] + ); + $presenter->presentResponse( + new ForbiddenResponse(ProviderException::listingNotAllowed()->getMessage()) + ); + + return; + } + + try { + $providers = $this->repository->findAll($this->requestParameters); + $presenter->presentResponse($this->createResponse($providers)); + } catch (RequestParametersTranslatorException $ex) { + $presenter->presentResponse(new ErrorResponse($ex->getMessage())); + $this->error($ex->getMessage(), ['trace' => $ex->getTraceAsString()]); + } catch (\Throwable $exception) { + $presenter->presentResponse(new ErrorResponse(ProviderException::errorWhileListingProviders())); + $this->error($exception->getMessage(), ['trace' => $exception->getTraceAsString()]); + } + } + + /** + * @param Provider[] $providers + * + * @return FindProvidersResponse + */ + private function createResponse(array $providers): FindProvidersResponse + { + $response = new FindProvidersResponse(); + $response->providers = array_map( + static fn (Provider $provider): ProviderDto => new ProviderDto( + id: $provider->getId(), + name: $provider->getName(), + type: $provider->getType(), + isActivated: $provider->isActivated() + ), + $providers + ); + + return $response; + } +} diff --git a/centreon-open-tickets/src/CentreonOpenTickets/Providers/Application/UseCase/FindProvidersPresenterInterface.php b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Application/UseCase/FindProvidersPresenterInterface.php new file mode 100644 index 0000000000..3b6f25e088 --- /dev/null +++ b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Application/UseCase/FindProvidersPresenterInterface.php @@ -0,0 +1,32 @@ +id, 'Provider::id'); + Assertion::notEmptyString($this->name, 'Provider::name'); + Assertion::maxLength($this->name, self::MAX_NAME_LENGTH, 'Provider::name'); + } + + /** + * @return ProviderType + */ + public function getType(): ProviderType + { + return $this->type; + } + + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + + /** + * @return bool + */ + public function isActivated(): bool + { + return $this->isActivated; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } +} diff --git a/centreon-open-tickets/src/CentreonOpenTickets/Providers/Domain/Model/ProviderType.php b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Domain/Model/ProviderType.php new file mode 100644 index 0000000000..65f5167d7b --- /dev/null +++ b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Domain/Model/ProviderType.php @@ -0,0 +1,42 @@ +denyAccessUnlessGrantedForApiConfiguration(); + + $useCase($presenter); + + return $presenter->show(); + } +} diff --git a/centreon-open-tickets/src/CentreonOpenTickets/Providers/Infrastructure/API/FindProviders/FindProvidersPresenter.php b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Infrastructure/API/FindProviders/FindProvidersPresenter.php new file mode 100644 index 0000000000..1dbbf01e14 --- /dev/null +++ b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Infrastructure/API/FindProviders/FindProvidersPresenter.php @@ -0,0 +1,97 @@ +setResponseStatus($response); + } else { + $result = array_map( + fn (ProviderDto $provider): array => [ + 'id' => $provider->id, + 'name' => $provider->name, + 'type' => $this->normalizeProviderType($provider->type), + 'is_activated' => $provider->isActivated, + ], + $response->providers + ); + + $this->present([ + 'result' => $result, + 'meta' => $this->requestParameters->toArray(), + ]); + } + } + + /** + * @param ProviderType $type + * + * @return string + */ + private function normalizeProviderType(ProviderType $type): string + { + return match ($type) { + ProviderType::Mail => 'Mail', + ProviderType::Glpi => 'Glpi', + ProviderType::Otrs => 'Otrs', + ProviderType::Simple => 'Simple', + ProviderType::BmcItsm => 'BmcItsm', + ProviderType::Serena => 'Serena', + ProviderType::BmcFootprints11 => 'BmcFootprints11', + ProviderType::EasyvistaSoap => 'EasyvistaSoap', + ProviderType::ServiceNow => 'ServiceNow', + ProviderType::Jira => 'Jira', + ProviderType::GlpiRestApi => 'GlpiRestApi', + ProviderType::RequestTracker2 => 'RequestTracker2', + ProviderType::Itop => 'Itop', + ProviderType::EasyVistaRest => 'EasyVistaRest' + }; + } +} diff --git a/centreon-open-tickets/src/CentreonOpenTickets/Providers/Infrastructure/Repository/DbReadProviderRepository.php b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Infrastructure/Repository/DbReadProviderRepository.php new file mode 100644 index 0000000000..e49a8fca37 --- /dev/null +++ b/centreon-open-tickets/src/CentreonOpenTickets/Providers/Infrastructure/Repository/DbReadProviderRepository.php @@ -0,0 +1,154 @@ +db = $db; + } + + /** + * @inheritDoc + */ + public function findAll(?RequestParametersInterface $requestParameters): array + { + $sqlTranslator = $requestParameters !== null ? new SqlRequestParametersTranslator($requestParameters) : null; + $sqlTranslator?->setConcordanceArray([ + 'name' => 'alias', + 'is_activated' => 'activate', + ]); + + $sqlTranslator?->addNormalizer('is_activated', new BoolToEnumNormalizer()); + + $request = <<<'SQL' + SELECT SQL_CALC_FOUND_ROWS + rule_id, + alias, + provider_id, + activate + FROM `:db`.mod_open_tickets_rule + SQL; + + // handle search + $request .= $sqlTranslator?->translateSearchParameterToSql(); + + // handle sort + $sort = $sqlTranslator?->translateSortParameterToSql(); + $request .= $sort !== null ? $sort : ' ORDER BY alias ASC'; + + // handle pagination + $request .= $sqlTranslator?->translatePaginationToSql(); + + $statement = $this->db->prepare($this->translateDbName($request)); + $sqlTranslator?->bindSearchValues($statement); + + $statement->setFetchMode(\PDO::FETCH_ASSOC); + + $statement->execute(); + + // Set total + $result = $this->db->query('SELECT FOUND_ROWS()'); + if ($result !== false && ($total = $result->fetchColumn()) !== false) { + $sqlTranslator?->getRequestParameters()->setTotal((int) $total); + } + + $providers = []; + + foreach ($statement as $record) { + /** @var _Provider $record */ + $providers[] = $this->createProviderFromRecord($record); + } + + return $providers; + } + + /** + * @param _Provider $record + * + * @return Provider + */ + private function createProviderFromRecord(array $record): Provider + { + $type = $this->providerTypeToEmum((int) $record['provider_id']); + + if ($type === null) { + throw new \InvalidArgumentException('Provider type id not handled'); + } + + return new Provider( + id: (int) $record['rule_id'], + name: $record['alias'], + type: $type, + isActivated: (bool) $record['activate'], + ); + } + + /** + * @param int $type + * + * @return ProviderType|null + */ + private function providerTypeToEmum(int $type): ?ProviderType + { + return match ($type) { + 1 => ProviderType::Mail, + 2 => ProviderType::Glpi, + 3 => ProviderType::Otrs, + 4 => ProviderType::Simple, + 5 => ProviderType::BmcItsm, + 6 => ProviderType::Serena, + 7 => ProviderType::BmcFootprints11, + 8 => ProviderType::EasyvistaSoap, + 9 => ProviderType::ServiceNow, + 10 => ProviderType::Jira, + 11 => ProviderType::GlpiRestApi, + 12 => ProviderType::RequestTracker2, + 13 => ProviderType::Itop, + 14 => ProviderType::EasyVistaRest, + default => null + }; + } +} diff --git a/centreon-open-tickets/src/CentreonOpenTickets/Resources/Infrastructure/API/TicketExtraDataFormatter.php b/centreon-open-tickets/src/CentreonOpenTickets/Resources/Infrastructure/API/TicketExtraDataFormatter.php new file mode 100644 index 0000000000..b14c7b0541 --- /dev/null +++ b/centreon-open-tickets/src/CentreonOpenTickets/Resources/Infrastructure/API/TicketExtraDataFormatter.php @@ -0,0 +1,66 @@ + [ + 'id' => $data['id'], + 'subject' => $data['subject'], + 'created_at' => $this->formatDateToIso8601($data['created_at']) + ] + ]; + } + + /** + * @inheritDoc + */ + public function isValidFor(string $providerName): bool + { + return $providerName === self::EXTRA_DATA_SOURCE_NAME; + } +} diff --git a/centreon-open-tickets/src/CentreonOpenTickets/Resources/Infrastructure/Repository/OpenTicketExtraDataProvider.php b/centreon-open-tickets/src/CentreonOpenTickets/Resources/Infrastructure/Repository/OpenTicketExtraDataProvider.php new file mode 100644 index 0000000000..ff95ccb73f --- /dev/null +++ b/centreon-open-tickets/src/CentreonOpenTickets/Resources/Infrastructure/Repository/OpenTicketExtraDataProvider.php @@ -0,0 +1,363 @@ +db = $db; + } + + /** + * @inheritDoc + */ + public function getExtraDataSourceName(): string + { + return self::DATA_PROVIDER_SOURCE_NAME; + } + + /** + * @inheritDoc + */ + public function supportsExtraData(ResourceFilter $filter): bool + { + return $filter->getRuleId() !== null; + } + + /** + * @inheritDoc + */ + public function getSubFilter(ResourceFilter $filter): string + { + + // Only get subRequest is asked and if ruleId is provided + if ( + $filter->getOnlyWithTicketsOpened() === false + || $filter->getRuleId() === null + ) { + return ''; + } + + $macroName = $this->getMacroNameFromRuleId($filter->getRuleId()); + + if ($macroName === null) { + throw new \Exception('Macro name used for rule not found'); + } + + return << h.last_time_up OR h.last_time_up IS NULL) + ) + LEFT JOIN `:dbstg`.customvariables service_customvariables + ON ( + s.service_id = service_customvariables.service_id + AND s.host_id = service_customvariables.host_id + AND service_customvariables.name = '{$macroName}' + ) + LEFT JOIN `:dbstg`.mod_open_tickets service_tickets + ON ( + service_customvariables.value = service_tickets.ticket_value + AND (service_tickets.timestamp > s.last_time_ok OR s.last_time_ok IS NULL) + ) + WHERE ( + (h.host_id = resources.parent_id AND s.service_id = resources.id) + OR (h.host_id = resources.id AND s.service_id IS NULL) + ) + AND (host_tickets.timestamp IS NOT NULL OR service_tickets.timestamp IS NOT NULL) + LIMIT 1 + ) + SQL; + } + + /** + * @param Resource[] $resources + * @return Resource[] + */ + private function getServiceResources(array $resources): array + { + return array_filter( + $resources, + static fn (Resource $resource) => $resource->getType() === Resource::TYPE_SERVICE + ); + } + + /** + * @param Resource[] $resources + * @return Resource[] + */ + private function getHostResources(array $resources): array + { + return array_filter( + $resources, + static fn (Resource $resource) => $resource->getType() === Resource::TYPE_HOST + ); + } + + /** + * @inheritDoc + */ + public function getExtraDataForResources(ResourceFilter $filter, array $resources): array + { + $data = []; + + // Provide information only if rule ID is provided and resources is not EMPTY + if ($filter->getRuleId() === null || $resources === []) { + return $data; + } + + $macroName = $this->getMacroNameFromRuleId($filter->getRuleId()); + + if ($macroName === null) { + throw new \Exception('Macro name used for rule not found'); + } + + $parentResourceIds = []; + $resourceIds = []; + + // extract resource id for services and linked hosts + foreach ($this->getServiceResources($resources) as $resource) { + if ( + $resource->getResourceId() !== null + && ! in_array($resource->getResourceId(), $parentResourceIds) + ) { + $resourceIds[] = $resource->getResourceId(); + } + + if ( + $resource->getParent() !== null + && $resource->getParent()->getResourceId() !== null + && ! in_array($resource->getParent()->getResourceId(), $parentResourceIds) + ) { + $parentResourceIds[] = $resource->getParent()->getResourceId(); + } + } + + // extract resource ids for hosts + foreach ($this->getHostResources($resources) as $resource) { + if ( + $resource->getResourceId() !== null + && ! in_array($resource->getResourceId(), $parentResourceIds) + ) { + $parentResourceIds[] = $resource->getResourceId(); + } + } + + // avoid key re-indexing. index = resource_id + return $this->getResourceTickets($resourceIds, $macroName) + + $this->getParentResourceTickets($parentResourceIds, $macroName); + } + + /** + * @param int[] $resources + * @param string $macroName + * @return array|array{} + + */ + private function getResourceTickets(array $resources, string $macroName): array + { + if ($resources === []) { + return []; + } + + [$bindValues, $bindQuery] = $this->createMultipleBindQuery(array_values($resources), ':resource_id'); + + $request = << s.last_time_ok OR s.last_time_ok IS NULL) + LEFT JOIN `:dbstg`.mod_open_tickets_data tickets_data + ON tickets_data.ticket_id = tickets.ticket_id + WHERE r.resource_id IN ({$bindQuery}) + AND tickets.timestamp IS NOT NULL; + SQL; + + $statement = $this->db->prepare($this->translateDbName($request)); + $statement->bindValue(':macroName', $macroName, \PDO::PARAM_STR); + + foreach ($bindValues as $key => $value) { + $statement->bindValue($key, $value, \PDO::PARAM_INT); + } + + $statement->setFetchMode(\PDO::FETCH_ASSOC); + $statement->execute(); + + $tickets = []; + + while (($record = $statement->fetch(\PDO::FETCH_ASSOC)) !== false) { + /** + * @var _TicketData $record + */ + $tickets[(int) $record['resource_id']] = [ + 'id' => (int) $record['ticket_value'], + 'subject' => $record['subject'], + 'created_at' => (new \DateTimeImmutable())->setTimestamp((int) $record['timestamp']) + ]; + } + + return $tickets; + } + + /** + * @param int[] $parentResources + * @param string $macroName + * @return array|array{} + */ + private function getParentResourceTickets(array $parentResources, string $macroName): array + { + if ($parentResources === []) { + return []; + } + + [$bindValues, $bindQuery] = $this->createMultipleBindQuery(array_values($parentResources), ':resource_id'); + + $request = << h.last_time_up OR h.last_time_up IS NULL) + LEFT JOIN `:dbstg`.mod_open_tickets_data tickets_data + ON tickets_data.ticket_id = tickets.ticket_id + WHERE r.resource_id IN ({$bindQuery}) + AND tickets.timestamp IS NOT NULL; + SQL; + + $statement = $this->db->prepare($this->translateDbName($request)); + $statement->bindValue(':macroName', $macroName, \PDO::PARAM_STR); + + foreach ($bindValues as $key => $value) { + $statement->bindValue($key, $value, \PDO::PARAM_INT); + } + + $statement->setFetchMode(\PDO::FETCH_ASSOC); + $statement->execute(); + + $tickets = []; + while (($record = $statement->fetch(\PDO::FETCH_ASSOC)) !== false) { + /** + * @var _TicketData $record + */ + $tickets[(int) $record['resource_id']] = [ + 'id' => (int) $record['ticket_value'], + 'subject' => $record['subject'], + 'created_at' => (new \DateTimeImmutable())->setTimestamp((int) $record['timestamp']) + ]; + } + + return $tickets; + } + + /** + * Get the name of the macro configured for the given rule ID. + * + * @param int $ruleId + * + * @return string + */ + private function getMacroNameFromRuleId(int $ruleId): ?string + { + $request = <<<'SQL' + SELECT `value` FROM `:db`.mod_open_tickets_form_value WHERE rule_id = :ruleId AND uniq_id = 'macro_ticket_id'; + SQL; + + $statement = $this->db->prepare($this->translateDbName($request)); + $statement->bindValue(':ruleId', $ruleId, \PDO::PARAM_INT); + $statement->setFetchMode(\PDO::FETCH_ASSOC); + $statement->execute(); + + /** @var string|null|false $result */ + $result = $statement->fetchColumn(); + + return $result !== false ? $result : null; + } +} diff --git a/centreon-open-tickets/tests/php/CentreonOpenTickets/Providers/Application/UseCase/FindProviders/FindProvidersTest.php b/centreon-open-tickets/tests/php/CentreonOpenTickets/Providers/Application/UseCase/FindProviders/FindProvidersTest.php new file mode 100644 index 0000000000..79ba03ed70 --- /dev/null +++ b/centreon-open-tickets/tests/php/CentreonOpenTickets/Providers/Application/UseCase/FindProviders/FindProvidersTest.php @@ -0,0 +1,125 @@ +useCase = new FindProviders( + contact: $this->contact = $this->createMock(ContactInterface::class), + requestParameters: $this->requestParameters = $this->createMock(RequestParametersInterface::class), + repository: $this->repository = $this->createMock(ReadProviderRepositoryInterface::class) + ); + + $this->presenter = new FindProvidersPresenterStub($this->createMock(PresenterFormatterInterface::class)); +}); + +it('should present a Forbidden response when user does not have sufficient rights (missing page access)', function (): void { + $this->contact + ->expects($this->once()) + ->method('hasTopologyRole') + ->willReturn(false); + + ($this->useCase)($this->presenter); + + expect($this->presenter->response) + ->toBeInstanceOf(ForbiddenResponse::class) + ->and($this->presenter->response->getMessage()) + ->toBe(ProviderException::listingNotAllowed()->getMessage()); +}); + +it('should present an ErrorResponse when an exception occurs for ticket provider search', function (): void { + $this->contact + ->expects($this->once()) + ->method('hasTopologyRole') + ->willReturn(true); + + $exception = new \Exception(); + $this->repository + ->expects($this->once()) + ->method('findAll') + ->willThrowException($exception); + + ($this->useCase)($this->presenter); + expect($this->presenter->response) + ->toBeInstanceOf(ErrorResponse::class) + ->and($this->presenter->response->getMessage()) + ->toBe(ProviderException::errorWhileListingProviders()->getMessage()); +}); + +it('should present an ErrorResponse when an error occurs concerning the request parameters', function (): void { + $this->contact + ->expects($this->once()) + ->method('hasTopologyRole') + ->willReturn(true); + + $this->repository + ->expects($this->once()) + ->method('findAll') + ->willThrowException(new RequestParametersTranslatorException()); + + ($this->useCase)($this->presenter); + expect($this->presenter->response) + ->toBeInstanceOf(ErrorResponse::class); +}); + +it('should present a FindProvidersResponse when everything goes well', function (): void { + $this->contact + ->expects($this->once()) + ->method('hasTopologyRole') + ->willReturn(true); + + $provider = new Provider( + id: 1, + name: 'glpi', + type: ProviderType::GlpiRestApi, + isActivated: true + ); + + $this->repository + ->expects($this->once()) + ->method('findAll') + ->willReturn([$provider]); + + ($this->useCase)($this->presenter); + $response = $this->presenter->response; + expect($response) + ->toBeInstanceOf(FindProvidersResponse::class) + ->and($response->providers[0]->id)->toBe($provider->getId()) + ->and($response->providers[0]->name)->toBe($provider->getName()) + ->and($response->providers[0]->type)->toBe($provider->getType()) + ->and($response->providers[0]->isActivated)->toBe($provider->isActivated()); +}); diff --git a/centreon-open-tickets/tests/php/CentreonOpenTickets/Providers/Infrastructure/API/FindProviders/FindProvidersPresenterStub.php b/centreon-open-tickets/tests/php/CentreonOpenTickets/Providers/Infrastructure/API/FindProviders/FindProvidersPresenterStub.php new file mode 100644 index 0000000000..45c4efa3dc --- /dev/null +++ b/centreon-open-tickets/tests/php/CentreonOpenTickets/Providers/Infrastructure/API/FindProviders/FindProvidersPresenterStub.php @@ -0,0 +1,42 @@ +response = $response; + } +} diff --git a/centreon-open-tickets/widgets/open-tickets/configs.xml b/centreon-open-tickets/widgets/open-tickets/configs.xml index 8ccf27aa90..5df64c42dd 100644 --- a/centreon-open-tickets/widgets/open-tickets/configs.xml +++ b/centreon-open-tickets/widgets/open-tickets/configs.xml @@ -4,7 +4,7 @@ contact@centreon.com http://www.centreon.com This widget is associated to the Open Tickets Module and allows for selecting hosts or services events for which to create tickets in your favorite ITSM tools. This widget can also list already created tickets with their ID and datetime. - 24.05.0 + 24.07.0 centreon, widget, tickets ./widgets/open-tickets/resources/centreon-logo.png diff --git a/centreon-open-tickets/widgets/open-tickets/src/index.php b/centreon-open-tickets/widgets/open-tickets/src/index.php index 55358d4e18..7dcfbdb522 100644 --- a/centreon-open-tickets/widgets/open-tickets/src/index.php +++ b/centreon-open-tickets/widgets/open-tickets/src/index.php @@ -568,6 +568,20 @@ ); $data[$row['host_id'] . "_" . $row['service_id']]['ticket_subject'] = $row['service_ticket_subject']; } + + $kernel = \App\Kernel::createForWeb(); + $resourceController = $kernel->getContainer()->get( + \Centreon\Application\Controller\MonitoringResourceController::class + ); + + $data[$row['host_id'] . '_' . $row['service_id']]['h_details_uri'] = $useDeprecatedPages + ? '../../main.php?p=0202&o=hd&host_name=' . $row['hostname'] + : $resourceController->buildHostDetailsUri($row['host_id']); + + $data[$row['host_id'] . '_' . $row['service_id']]['s_details_uri'] = $useDeprecatedPages + ? '../../main.php?p=0202&o=hd&host_name=' . $row['hostname'] + . '&service_description=' . $row['description'] + : $resourceController->buildServiceDetailsUri($row['host_id'], $row['service_id']); } $template->assign('widgetId', $widgetId); diff --git a/centreon-open-tickets/widgets/open-tickets/src/templates/table.ihtml b/centreon-open-tickets/widgets/open-tickets/src/templates/table.ihtml index 8b26fb5811..47ca54c135 100644 --- a/centreon-open-tickets/widgets/open-tickets/src/templates/table.ihtml +++ b/centreon-open-tickets/widgets/open-tickets/src/templates/table.ihtml @@ -49,7 +49,7 @@ {/if} - {$elem.hostname} + {$elem.hostname}
@@ -79,7 +79,7 @@ {if $preferences.display_status == 0}
{/if} - {$elem.description} + {$elem.description} {if $preferences.display_status == 0}
{/if} diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/conf.php b/centreon-open-tickets/www/modules/centreon-open-tickets/conf.php index b18bfabcbc..b3154570ea 100644 --- a/centreon-open-tickets/www/modules/centreon-open-tickets/conf.php +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/conf.php @@ -22,7 +22,7 @@ $module_conf['centreon-open-tickets']["rname"] = "Centreon Open Tickets"; $module_conf['centreon-open-tickets']["name"] = "centreon-open-tickets"; -$module_conf['centreon-open-tickets']["mod_release"] = "24.05.0"; +$module_conf['centreon-open-tickets']["mod_release"] = "24.09.0"; $module_conf['centreon-open-tickets']["infos"] = "Centreon Open Tickets is a community module developed to " . "create tickets to your favorite ITSM tools using API. @@ -37,7 +37,7 @@ $module_conf['centreon-open-tickets']["is_removeable"] = "1"; $module_conf['centreon-open-tickets']["author"] = "Centreon"; $module_conf['centreon-open-tickets']["stability"] = "stable"; -$module_conf['centreon-open-tickets']["last_update"] = "2024-04-12"; +$module_conf['centreon-open-tickets']["last_update"] = "2024-08-27"; $module_conf['centreon-open-tickets']["release_note"] = "https://docs.centreon.com/23.10/en/releases/centreon-os-extensions.html"; $module_conf['centreon-open-tickets']["images"] = [ diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/php/clear_cache.php b/centreon-open-tickets/www/modules/centreon-open-tickets/php/clear_cache.php new file mode 100644 index 0000000000..b4888ca7bb --- /dev/null +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/php/clear_cache.php @@ -0,0 +1,64 @@ +fetch(); + $messages = explode("\n", $rawMessage); + $filteredMessages = []; + foreach ($messages as $rawMessage) { + if (!empty(trim($rawMessage))) { + $filteredMessages[] = $rawMessage; + } + } + if (!empty($filteredMessages)) { + if (substr(strtolower($filteredMessages[0]), 0, 2) === 'in') { + array_shift($filteredMessages); + } + return implode('
', $filteredMessages); + } + return null; +}; + +if (!class_exists(Application::class)) { + throw new RuntimeException('You need to add "symfony/framework-bundle" as a Composer dependency.'); +} + +require _CENTREON_PATH_ . '/config/bootstrap.php'; +$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); +$application = new Application($kernel); +$application->setAutoExit(false); + +$consoleOutput = new BufferedOutput(); +$consoleOutput->setVerbosity(OutputInterface::VERBOSITY_QUIET | OutputInterface::OUTPUT_RAW); +$input = new ArgvInput(['', 'cache:clear']); + +$code = $application->run($input, $consoleOutput); +if (!is_null($message = $extractErrorMessage($consoleOutput))) { + throw new \Exception($message); +} + diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/php/generate_routes.php b/centreon-open-tickets/www/modules/centreon-open-tickets/php/generate_routes.php new file mode 100644 index 0000000000..b0b685c0f6 --- /dev/null +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/php/generate_routes.php @@ -0,0 +1,34 @@ + $host_problems, 'service_problems' => $service_problems, 'ticket_value' => $ticketId, - 'subject' => $ticketArguments[self::ARG_TITLE], + 'subject' => $ticketArguments[$this->internal_arg_name[self::ARG_TITLE]], 'data_type' => self::DATA_TYPE_JSON, 'data' => json_encode($ticketArguments) )); diff --git a/centreon-gorgone/.veracode-exclusions b/centreon-open-tickets/www/modules/centreon-open-tickets/routes/CentreonOpenTickets.yaml similarity index 100% rename from centreon-gorgone/.veracode-exclusions rename to centreon-open-tickets/www/modules/centreon-open-tickets/routes/CentreonOpenTickets.yaml diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/routes/CentreonOpenTickets.yaml.wait b/centreon-open-tickets/www/modules/centreon-open-tickets/routes/CentreonOpenTickets.yaml.wait new file mode 100644 index 0000000000..3ea8d0bc46 --- /dev/null +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/routes/CentreonOpenTickets.yaml.wait @@ -0,0 +1,6 @@ +FindProviders: + methods: GET + path: /providers + controller: 'CentreonOpenTickets\Providers\Infrastructure\API\FindProviders\FindProvidersController' + condition: "request.attributes.get('version') >= 24.04" + diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/sql/install.sql b/centreon-open-tickets/www/modules/centreon-open-tickets/sql/install.sql index 4a226f8bb7..e7c144cc8e 100644 --- a/centreon-open-tickets/www/modules/centreon-open-tickets/sql/install.sql +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/sql/install.sql @@ -5,6 +5,10 @@ INSERT INTO `topology` (`topology_id`, `topology_name`, `topology_parent`, `topology_page`, `topology_order`, `topology_group`, `topology_url`, `topology_url_opt`, `topology_popup`, `topology_modules`, `topology_show`) VALUES (NULL, 'Open Tickets', '604', NULL, NULL, '8', NULL, NULL, '0', '1', '1'), (NULL, 'Rules', '604', '60420', '10', '8', './modules/centreon-open-tickets/views/rules/index.php', NULL, NULL, '1', '1'); + +INSERT INTO `topology` (`topology_name`, `topology_parent`, `topology_page`, `topology_url`, `topology_show`, `readonly`) +VALUES ('Submit Ticket', 604, 60421, './modules/centreon-open-tickets/views/rules/submitTicket/action.php', '0', '0'); + INSERT INTO `topology_JS` (`id_page`, `PathName_js`) VALUES ('60420', './modules/centreon-open-tickets/lib/jquery.sheepItPlugin.js'); INSERT INTO `topology_JS` (`id_page`, `PathName_js`) VALUES ('60420', './modules/centreon-open-tickets/lib/jquery.serialize-object.min.js'); INSERT INTO `topology_JS` (`id_page`, `PathName_js`) VALUES ('60420', './modules/centreon-open-tickets/lib/doClone.js'); diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/sql/uninstall.sql b/centreon-open-tickets/www/modules/centreon-open-tickets/sql/uninstall.sql index 26b592ee33..853ecec2bb 100644 --- a/centreon-open-tickets/www/modules/centreon-open-tickets/sql/uninstall.sql +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/sql/uninstall.sql @@ -14,3 +14,4 @@ DELETE FROM topology WHERE topology_page = '20320' AND topology_name = 'Ticket L DELETE FROM topology_JS WHERE id_page = '20320'; DELETE FROM widget_parameters_field_type WHERE ft_typename = 'openTicketsRule'; +DELETE FROM `topology` WHERE topology_page = 60421; diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/upgrade/24.09.0/php/upgrade.php b/centreon-open-tickets/www/modules/centreon-open-tickets/upgrade/24.09.0/php/upgrade.php new file mode 100644 index 0000000000..28430e99c0 --- /dev/null +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/upgrade/24.09.0/php/upgrade.php @@ -0,0 +1,79 @@ +query('SELECT 1 FROM topology WHERE topology_page = 60421'); + if ((bool) $statement->fetchColumn() === false) { + $pearDB->query( + <<<'SQL' + INSERT INTO topology + ( + topology_name, + topology_parent, + topology_page, + topology_url, + topology_show, + readonly + ) VALUES ( + 'Submit Ticket', + 604, + 60421, + './modules/centreon-open-tickets/views/rules/submitTicket/action.php', + '0', + '0' + ) + SQL + ); + } +}; + +try { + if (! $pearDB->inTransaction()) { + $pearDB->beginTransaction(); + } + $insertSubmitTicketTopology($pearDB); + $pearDB->commit(); +} catch (Exception $e) { + if ($pearDB->inTransaction()) { + $pearDB->rollBack(); + } + + $centreonLog->insertLog( + 4, + $versionOfTheUpgrade . $errorMessage + . ' - Code : ' . (int) $e->getCode() + . ' - Error : ' . $e->getMessage() + . ' - Trace : ' . $e->getTraceAsString() + ); + + throw new Exception($versionOfTheUpgrade . $errorMessage, (int) $e->getCode(), $e); +} diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/closeTicket/action.php b/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/closeTicket/action.php new file mode 100644 index 0000000000..4c518e3504 --- /dev/null +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/closeTicket/action.php @@ -0,0 +1,110 @@ + 1, 'msg' => 'Invalid session']; + header('Content-type: text/plain'); + echo json_encode($resultat); + + exit; +} + +$centreon_bg = new CentreonXMLBGRequest($dependencyInjector, session_id(), 1, 1, 0, 1); +$db = $dependencyInjector['configuration_db']; +$rule = new Centreon_OpenTickets_Rule($db); + +$data = isset($_POST['data']) ? json_decode($_POST['data'], true) : null; + +if ($data === null) { + $resultat = ['code' => 1, 'msg' => 'POST data key missing']; + header('Content-type: text/plain'); + echo json_encode($resultat); + + exit; +} + +if ( + ! isset($data['rule_id']) + || ! is_int($data['rule_id']) +) { + $resultat = ['code' => 1, 'msg' => 'Rule ID should be provided as an integer']; + header('Content-type: text/plain'); + echo json_encode($resultat); + + exit; +} + +$ruleInformation = $rule->getAliasAndProviderId($data['rule_id']); + +if ( + ! isset($data['selection']) + || ! isSelectionValid($data['selection']) +) { + $resultat = ['code' => 1, 'msg' => 'Resource selection not provided or not well formatted']; + header('Content-type: text/plain'); + echo json_encode($resultat); + + exit; +} + +// re-create payload sent from the widget directly from this file +$get_information = [ + 'action' => 'close-ticket', + 'rule_id' => $data['rule_id'], + 'provider_id' => $ruleInformation['provider_id'], + 'form' => [ + 'rule_id' => $data['rule_id'], + 'provider_id' => $ruleInformation['provider_id'], + 'selection' => $data['selection'], + ], +]; + +require_once __DIR__ . '/../ajax/actions/closeTicket.php'; + +header('Content-type: text/plain'); +echo json_encode($resultat); diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/submitTicket/action.php b/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/submitTicket/action.php new file mode 100644 index 0000000000..7df8032d3a --- /dev/null +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/submitTicket/action.php @@ -0,0 +1,160 @@ + + + + + + + +query('SELECT rule_id, alias, provider_id FROM mod_open_tickets_rule'); + + while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { + $rules[$row['rule_id']] = $row; + } + + $uniqId = uniqid(); + + $title = $cmd === SERVICE_OPEN_TICKET_COMMAND_ID + ? _('Open Service Ticket') + : _('Open Host Ticket'); + + $result = null; + + if (isset($_GET['rule_id'])) { + $selection = $_GET['selection'] ?? $_GET['host_id'] . ';' . $_GET['service_id']; + $result = $rule->getFormatPopupProvider( + $_GET['rule_id'], + [ + 'title' => $title, + 'user' => [ + 'name' => $centreon->user->name, + 'alias' => $centreon->user->alias, + 'email' => $centreon->user->email, + ], + ], + 0, + $uniqId, + $_GET['cmd'], + $selection + ); + } + + $path = $centreon_path . 'www/widgets/open-tickets/src/'; + $template = new Smarty(); + $template = initSmartyTplForPopup($path . 'templates/', $template, './', $centreon_path); + + if (isset($_GET['rule_id'])) { + $template->assign('provider_id', $rules[$_GET['rule_id']]['provider_id']); + $template->assign('rule_id', $_GET['rule_id']); + $template->assign('widgetId', 0); + $template->assign('uniqId', $uniqId); + $template->assign('title', $title); + $template->assign('cmd', $cmd); + $template->assign('selection', $selection); + $template->assign('continue', (! is_null($result) && isset($result['format_popup'])) ? 0 : 1); + $template->assign( + 'attach_files_enable', + (! is_null($result) + && isset($result['attach_files_enable']) + && $result['attach_files_enable'] === 'yes' + ) ? 1 : 0 + ); + + $template->assign( + 'formatPopupProvider', + (! is_null($result) + && isset($result['format_popup']) + ) ? $result['format_popup'] : '' + ); + + $template->assign('submitLabel', _('Open')); + } else { + $template->assign('rules', $rules); + $template->assign('submitRule', _('Select')); + } + + $template->display(__DIR__ . '/submitTicket.ihtml'); +} + +try { + if (! isset($_SESSION['centreon']) || ! isset($_GET['cmd'])) { + throw new Exception('Missing data'); + } + $db = new CentreonDB(); + if (CentreonSession::checkSession(session_id(), $db) === 0) { + throw new Exception('Invalid session'); + } + /** @var Centreon $centreon */ + $centreon = $_SESSION['centreon']; + $oreon = $centreon->user; + + $cmd = filter_input(INPUT_GET, 'cmd', FILTER_VALIDATE_INT, ['options' => ['default' => 0]]); + + $widgetId = filter_input(INPUT_GET, 'widgetId', FILTER_VALIDATE_INT, ['options' => ['default' => 0]]); + $selections = explode(',', $_REQUEST['selection']); + + $widgetObj = new CentreonWidget($centreon, $db); + $preferences = $widgetObj->getWidgetPreferences($widgetId); + + $rule = new Centreon_OpenTickets_Rule($db); + + if ( + $cmd === SERVICE_OPEN_TICKET_COMMAND_ID + || $cmd === HOST_OPEN_TICKET_COMMAND_ID + ) { + format_popup(); + } else { + throw new Exception('Unhandled data provided for cmd parameter'); + } +} catch (Exception $e) { + echo $e->getMessage() . '
'; +} +?> diff --git a/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/submitTicket/submitTicket.ihtml b/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/submitTicket/submitTicket.ihtml new file mode 100644 index 0000000000..024340fb5f --- /dev/null +++ b/centreon-open-tickets/www/modules/centreon-open-tickets/views/rules/submitTicket/submitTicket.ihtml @@ -0,0 +1,190 @@ +
+
+
+ +
+ {if ! isset($rule_id)} + + {/if} + {$formatPopupProvider} +
+
+ + + + + + + + + + {if isset($submitLabel)} + + {/if} + {if isset($submitRule)} + + {/if} +
+
+
+
+{if $attach_files_enable} +
+{/if} + +{literal} + +{/literal} diff --git a/centreon/.eslintignore b/centreon/.eslintignore deleted file mode 100644 index 3cd4c7c663..0000000000 --- a/centreon/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -**/*{.,-}min.js -**/mockServiceWorker.js \ No newline at end of file diff --git a/centreon/.eslintrc.js b/centreon/.eslintrc.js deleted file mode 100644 index 03ed239de2..0000000000 --- a/centreon/.eslintrc.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - extends: './packages/js-config/eslint/react/typescript.eslintrc.js', - settings: { - 'import/resolver': { - alias: { - extensions: ['.js', '.jsx', '.ts', '.tsx'] - }, - node: { - extensions: ['.js', '.jsx', '.ts', '.tsx'], - moduleDirectory: ['node_modules', '.'] - } - } - } -}; diff --git a/centreon/bin/centreon b/centreon/bin/centreon index d2420bca2a..6388b65a94 100755 --- a/centreon/bin/centreon +++ b/centreon/bin/centreon @@ -99,12 +99,12 @@ require_once _CENTREON_ETC_ . "/centreon.conf.php"; require_once _CLAPI_CLASS_ . "/centreonAPI.class.php"; require_once _CLAPI_CLASS_ . "/centreonUtils.class.php"; -$dbConfig['host'] = $conf_centreon['hostCentreon']; -$dbConfig['username'] = $conf_centreon['user']; -$dbConfig['password'] = $conf_centreon['password']; -$dbConfig['dbname'] = $conf_centreon['db']; -if (isset($conf_centreon['port'])) { - $dbConfig['port'] = $conf_centreon['port']; +$dbConfig['host'] = hostCentreon; +$dbConfig['username'] = user; +$dbConfig['password'] = password; +$dbConfig['dbname'] = db; +if (defined('port')) { + $dbConfig['port'] = port; } elseif ($p = strstr($dbConfig['host'], ':')) { $p = substr($p, 1); if (is_numeric($p)) { diff --git a/centreon/bin/migrateCredentials.php b/centreon/bin/migrateCredentials.php new file mode 100644 index 0000000000..18af960308 --- /dev/null +++ b/centreon/bin/migrateCredentials.php @@ -0,0 +1,84 @@ +getMessage() . PHP_EOL); +} + +/** + * Migrate database credentials into the vault and update configuration files. + * + * This is handle outside of Symfony Command as this should be executed as root. + * + * @throws Throwable + */ +function migrateAndUpdateDatabaseCredentials(): void { + $kernel = Kernel::createForWeb(); + $readVaultConfigurationRepository = $kernel->getContainer()->get( + ReadVaultConfigurationRepositoryInterface::class + ); + $vaultConfiguration = $readVaultConfigurationRepository->find(); + + if ($vaultConfiguration === null) { + throw new Exception('No vault configured'); + } + + echo('Migration of database credentials' . PHP_EOL); + /** @var WriteVaultRepositoryInterface $writeVaultRepository */ + $writeVaultRepository = $kernel->getContainer()->get(WriteVaultRepositoryInterface::class); + $writeVaultRepository->setCustomPath(AbstractVaultRepository::DATABASE_VAULT_PATH); + $vaultPaths = migrateDatabaseCredentialsToVault($writeVaultRepository); + if (! empty($vaultPaths)) { + updateConfigFilesWithVaultPath($vaultPaths); + } + echo('Migration of database credentials completed' . PHP_EOL); +} + +/** + * Execute Symfony command to migrate web and modules credentials. + * + * @throws ProcessFailedException + */ +function migrateApplicationCredentials(): void +{ + echo('Migration of application credentials' . PHP_EOL); + $process = Process::fromShellCommandline( + 'sudo -u apache php ' . _CENTREON_PATH_ . '/bin/console list vault:migrate-credentials' + ); + $process->setWorkingDirectory(_CENTREON_PATH_); + $process->mustRun(); + + preg_match_all('/\S*vault:migrate-credentials:\S*/', $process->getOutput(), $matches); + foreach ($matches[0] as $migrationCommand) { + $process = Process::fromShellCommandline( + 'sudo -u apache php ' . _CENTREON_PATH_ . '/bin/console ' . $migrationCommand + ); + $process->setWorkingDirectory(_CENTREON_PATH_); + $process->mustRun(function ($type, $buffer): void { + if (Process::ERR === $type) { + echo 'ERROR: ' . $buffer . PHP_EOL; + } else { + echo $buffer; + } + }); + } + echo('Migration of application credentials completed' . PHP_EOL); +} diff --git a/centreon/biome.json b/centreon/biome.json new file mode 100644 index 0000000000..2786660a6d --- /dev/null +++ b/centreon/biome.json @@ -0,0 +1,6 @@ +{ + "extends": ["./packages/js-config/biome/base.json"], + "files": { + "ignore": ["**/*{.,-}min.js", "**/mockServiceWorker.js", "**/initPendo.js"] + } +} diff --git a/centreon/check-centreon-gpg-key.sh b/centreon/check-centreon-gpg-key.sh index 196c746ed9..65488d9e83 100644 --- a/centreon/check-centreon-gpg-key.sh +++ b/centreon/check-centreon-gpg-key.sh @@ -17,7 +17,7 @@ fi OLDKEY_NAME="gpg-pubkey-8a7652bc-4cb6f1f6" OLDKEY_ID="1024D/8A7652BC" -NEWKEY_NAME="gpg-pubkey-3fc49c1b-6166eb52" +NEWKEY_NAME="gpg-pubkey-3fc49c1b-651d4c25" rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n' | grep -q "${OLDKEY_NAME}" diff --git a/centreon/composer.json b/centreon/composer.json index 1b3aa1d777..4aab25230d 100644 --- a/centreon/composer.json +++ b/centreon/composer.json @@ -91,7 +91,8 @@ "onelogin/php-saml": "^4.1", "symfony/uid": "6.4.*", "symfony/mime": "6.4.*", - "monolog/monolog": "^3.3" + "monolog/monolog": "^3.3", + "symfony/security-core": "6.4.*" }, "autoload": { "psr-4": { diff --git a/centreon/composer.lock b/centreon/composer.lock index 364c581b24..0ac7b14982 100644 --- a/centreon/composer.lock +++ b/centreon/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ccc6b3097d589620480b46a5c1a1dcf8", + "content-hash": "e2de73fccafa394ceb7ef7dcf886f1e5", "packages": [ { "name": "beberlei/assert", @@ -601,28 +601,29 @@ }, { "name": "friendsofsymfony/rest-bundle", - "version": "3.6.0", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSRestBundle.git", - "reference": "e01be8113d4451adb3cbb29d7d2cc96bbc698179" + "reference": "db7d9a17da2bcae1bb8e2d7ff320ef3915903373" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/e01be8113d4451adb3cbb29d7d2cc96bbc698179", - "reference": "e01be8113d4451adb3cbb29d7d2cc96bbc698179", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/db7d9a17da2bcae1bb8e2d7ff320ef3915903373", + "reference": "db7d9a17da2bcae1bb8e2d7ff320ef3915903373", "shasum": "" }, "require": { - "php": "^7.2|^8.0", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/framework-bundle": "^4.4.1|^5.0|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/routing": "^5.4|^6.0", - "symfony/security-core": "^5.4|^6.0", + "php": "^7.4|^8.0", + "symfony/config": "^5.4|^6.4|^7.0", + "symfony/dependency-injection": "^5.4|^6.4|^7.0", + "symfony/deprecation-contracts": "^2.1|^3.0", + "symfony/event-dispatcher": "^5.4|^6.4|^7.0", + "symfony/framework-bundle": "^5.4|^6.4|^7.0", + "symfony/http-foundation": "^5.4|^6.4|^7.0", + "symfony/http-kernel": "^5.4|^6.4|^7.0", + "symfony/routing": "^5.4|^6.4|^7.0", + "symfony/security-core": "^5.4|^6.4|^7.0", "willdurand/jsonp-callback-validator": "^1.0|^2.0", "willdurand/negotiation": "^2.0|^3.0" }, @@ -633,32 +634,32 @@ "sensio/framework-extra-bundle": "<6.1" }, "require-dev": { - "doctrine/annotations": "^1.13.2|^2.0 ", - "friendsofphp/php-cs-fixer": "^3.0", + "doctrine/annotations": "^1.13.2|^2.0", + "friendsofphp/php-cs-fixer": "^3.43", "jms/serializer": "^1.13|^2.0|^3.0", "jms/serializer-bundle": "^2.4.3|^3.0.1|^4.0|^5.0", "psr/http-message": "^1.0", "psr/log": "^1.0|^2.0|^3.0", "sensio/framework-extra-bundle": "^6.1", - "symfony/asset": "^5.4|^6.0", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/css-selector": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", - "symfony/phpunit-bridge": "^5.4|^6.0", - "symfony/security-bundle": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0", - "symfony/twig-bundle": "^5.4|^6.0", - "symfony/validator": "^5.4|^6.0", - "symfony/web-profiler-bundle": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" + "symfony/asset": "^5.4|^6.4|^7.0", + "symfony/browser-kit": "^5.4|^6.4|^7.0", + "symfony/css-selector": "^5.4|^6.4|^7.0", + "symfony/expression-language": "^5.4|^6.4|^7.0", + "symfony/form": "^5.4|^6.4|^7.0", + "symfony/mime": "^5.4|^6.4|^7.0", + "symfony/phpunit-bridge": "^7.0.1", + "symfony/security-bundle": "^5.4|^6.4|^7.0", + "symfony/serializer": "^5.4|^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.4|^7.0", + "symfony/validator": "^5.4|^6.4|^7.0", + "symfony/web-profiler-bundle": "^5.4|^6.4|^7.0", + "symfony/yaml": "^5.4|^6.4|^7.0" }, "suggest": { - "jms/serializer-bundle": "Add support for advanced serialization capabilities, recommended, requires ^2.0|^3.0", - "sensio/framework-extra-bundle": "Add support for the request body converter and the view response listener, requires ^3.0", - "symfony/serializer": "Add support for basic serialization capabilities and xml decoding, requires ^2.7|^3.0", - "symfony/validator": "Add support for validation capabilities in the ParamFetcher, requires ^2.7|^3.0" + "jms/serializer-bundle": "Add support for advanced serialization capabilities, recommended", + "sensio/framework-extra-bundle": "Add support for the request body converter and the view response listener, not supported with Symfony >=7.0", + "symfony/serializer": "Add support for basic serialization capabilities and xml decoding", + "symfony/validator": "Add support for validation capabilities in the ParamFetcher" }, "type": "symfony-bundle", "extra": { @@ -700,9 +701,9 @@ ], "support": { "issues": "https://github.com/FriendsOfSymfony/FOSRestBundle/issues", - "source": "https://github.com/FriendsOfSymfony/FOSRestBundle/tree/3.6.0" + "source": "https://github.com/FriendsOfSymfony/FOSRestBundle/tree/3.7.1" }, - "time": "2023-09-27T11:41:02+00:00" + "time": "2024-04-12T22:57:10+00:00" }, { "name": "jms/metadata", @@ -958,12 +959,12 @@ "version": "v5.2.13", "source": { "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", + "url": "https://github.com/jsonrainbow/json-schema.git", "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", "shasum": "" }, @@ -1018,23 +1019,23 @@ "schema" ], "support": { - "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/v5.2.13" + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/v5.2.13" }, "time": "2023-09-26T02:20:38+00:00" }, { "name": "monolog/monolog", - "version": "3.5.0", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448" + "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448", - "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", + "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", "shasum": "" }, "require": { @@ -1057,7 +1058,7 @@ "phpstan/phpstan": "^1.9", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "^10.1", + "phpunit/phpunit": "^10.5.17", "predis/predis": "^1.1 || ^2", "ruflin/elastica": "^7", "symfony/mailer": "^5.4 || ^6", @@ -1110,7 +1111,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.5.0" + "source": "https://github.com/Seldaek/monolog/tree/3.6.0" }, "funding": [ { @@ -1122,7 +1123,7 @@ "type": "tidelift" } ], - "time": "2023-10-27T15:32:31+00:00" + "time": "2024-04-12T21:02:21+00:00" }, { "name": "nelmio/cors-bundle", @@ -1246,21 +1247,21 @@ }, { "name": "onelogin/php-saml", - "version": "4.1.0", + "version": "4.2.0", "source": { "type": "git", - "url": "https://github.com/onelogin/php-saml.git", - "reference": "b22a57ebd13e838b90df5d3346090bc37056409d" + "url": "https://github.com/SAML-Toolkits/php-saml.git", + "reference": "d3b5172f137db2f412239432d77253ceaaa1e939" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/onelogin/php-saml/zipball/b22a57ebd13e838b90df5d3346090bc37056409d", - "reference": "b22a57ebd13e838b90df5d3346090bc37056409d", + "url": "https://api.github.com/repos/SAML-Toolkits/php-saml/zipball/d3b5172f137db2f412239432d77253ceaaa1e939", + "reference": "d3b5172f137db2f412239432d77253ceaaa1e939", "shasum": "" }, "require": { "php": ">=7.3", - "robrichards/xmlseclibs": ">=3.1.1" + "robrichards/xmlseclibs": "^3.1" }, "require-dev": { "pdepend/pdepend": "^2.8.0", @@ -1286,19 +1287,27 @@ "license": [ "MIT" ], - "description": "OneLogin PHP SAML Toolkit", - "homepage": "https://developers.onelogin.com/saml/php", + "description": "PHP SAML Toolkit", + "homepage": "https://github.com/SAML-Toolkits/php-saml", "keywords": [ + "Federation", "SAML2", - "onelogin", + "SSO", + "identity", "saml" ], "support": { - "email": "sixto.garcia@onelogin.com", - "issues": "https://github.com/onelogin/php-saml/issues", - "source": "https://github.com/onelogin/php-saml/" + "email": "sixto.martin.garcia@gmail.com", + "issues": "https://github.com/onelogin/SAML-Toolkits/issues", + "source": "https://github.com/onelogin/SAML-Toolkits/" }, - "time": "2022-07-15T20:44:36+00:00" + "funding": [ + { + "url": "https://github.com/SAML-Toolkits", + "type": "github" + } + ], + "time": "2024-05-30T15:10:40+00:00" }, { "name": "openpsa/quickform", @@ -1407,12 +1416,12 @@ "source": { "type": "git", "url": "https://github.com/pear/pear-core-minimal.git", - "reference": "d457b5c93e5001fbf4b5726d21038266e029e3be" + "reference": "ce0adade8b97561656ace07cdaac4751c271ea8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/d457b5c93e5001fbf4b5726d21038266e029e3be", - "reference": "d457b5c93e5001fbf4b5726d21038266e029e3be", + "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/ce0adade8b97561656ace07cdaac4751c271ea8c", + "reference": "ce0adade8b97561656ace07cdaac4751c271ea8c", "shasum": "" }, "require": { @@ -1425,9 +1434,9 @@ }, "type": "library", "autoload": { - "psr-0": { - "": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "include-path": [ @@ -1448,7 +1457,7 @@ "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR", "source": "https://github.com/pear/pear-core-minimal" }, - "time": "2024-03-09T19:38:40+00:00" + "time": "2024-03-16T18:41:45+00:00" }, { "name": "pear/pear_exception", @@ -1564,28 +1573,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "5.4.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.1", "ext-filter": "*", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.13" }, "type": "library", "extra": { @@ -1609,15 +1625,15 @@ }, { "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "opensource@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2024-05-21T05:55:05+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -1679,16 +1695,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.26.0", + "version": "1.29.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "231e3186624c03d7e7c890ec662b81e6b0405227" + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/231e3186624c03d7e7c890ec662b81e6b0405227", - "reference": "231e3186624c03d7e7c890ec662b81e6b0405227", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4", + "reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4", "shasum": "" }, "require": { @@ -1720,9 +1736,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.26.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1" }, - "time": "2024-02-23T16:05:55+00:00" + "time": "2024-05-31T08:52:43+00:00" }, { "name": "pimple/pimple", @@ -2200,16 +2216,16 @@ }, { "name": "smarty/smarty", - "version": "v4.4.1", + "version": "v4.5.3", "source": { "type": "git", "url": "https://github.com/smarty-php/smarty.git", - "reference": "f4152e9b814ae2369b6e4935c05e1e0c3654318d" + "reference": "9fc96a13dbaf546c3d7bcf95466726578cd4e0fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/smarty-php/smarty/zipball/f4152e9b814ae2369b6e4935c05e1e0c3654318d", - "reference": "f4152e9b814ae2369b6e4935c05e1e0c3654318d", + "url": "https://api.github.com/repos/smarty-php/smarty/zipball/9fc96a13dbaf546c3d7bcf95466726578cd4e0fa", + "reference": "9fc96a13dbaf546c3d7bcf95466726578cd4e0fa", "shasum": "" }, "require": { @@ -2260,22 +2276,22 @@ "support": { "forum": "https://github.com/smarty-php/smarty/discussions", "issues": "https://github.com/smarty-php/smarty/issues", - "source": "https://github.com/smarty-php/smarty/tree/v4.4.1" + "source": "https://github.com/smarty-php/smarty/tree/v4.5.3" }, - "time": "2024-02-26T13:58:37+00:00" + "time": "2024-05-28T21:46:01+00:00" }, { "name": "symfony/cache", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "0ef36534694c572ff526d91c7181f3edede176e7" + "reference": "287142df5579ce223c485b3872df3efae8390984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/0ef36534694c572ff526d91c7181f3edede176e7", - "reference": "0ef36534694c572ff526d91c7181f3edede176e7", + "url": "https://api.github.com/repos/symfony/cache/zipball/287142df5579ce223c485b3872df3efae8390984", + "reference": "287142df5579ce223c485b3872df3efae8390984", "shasum": "" }, "require": { @@ -2342,7 +2358,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.4" + "source": "https://github.com/symfony/cache/tree/v6.4.8" }, "funding": [ { @@ -2358,20 +2374,20 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/cache-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "1d74b127da04ffa87aa940abe15446fa89653778" + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/1d74b127da04ffa87aa940abe15446fa89653778", - "reference": "1d74b127da04ffa87aa940abe15446fa89653778", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/df6a1a44c890faded49a5fca33c2d5c5fd3c2197", + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197", "shasum": "" }, "require": { @@ -2381,7 +2397,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -2418,7 +2434,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/cache-contracts/tree/v3.5.0" }, "funding": [ { @@ -2434,20 +2450,20 @@ "type": "tidelift" } ], - "time": "2023-09-25T12:52:38+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/clock", - "version": "v6.4.5", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "ecba44be4def12cd71e0460b956ab7e51a2c980e" + "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/ecba44be4def12cd71e0460b956ab7e51a2c980e", - "reference": "ecba44be4def12cd71e0460b956ab7e51a2c980e", + "url": "https://api.github.com/repos/symfony/clock/zipball/7a4840efd17135cbd547e41ec49fb910ed4f8b98", + "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98", "shasum": "" }, "require": { @@ -2492,7 +2508,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v6.4.5" + "source": "https://github.com/symfony/clock/tree/v6.4.8" }, "funding": [ { @@ -2508,20 +2524,20 @@ "type": "tidelift" } ], - "time": "2024-03-01T14:02:27+00:00" + "time": "2024-05-31T14:51:39+00:00" }, { "name": "symfony/config", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "6ea4affc27f2086c9d16b92ab5429ce1e3c38047" + "reference": "12e7e52515ce37191b193cf3365903c4f3951e35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/6ea4affc27f2086c9d16b92ab5429ce1e3c38047", - "reference": "6ea4affc27f2086c9d16b92ab5429ce1e3c38047", + "url": "https://api.github.com/repos/symfony/config/zipball/12e7e52515ce37191b193cf3365903c4f3951e35", + "reference": "12e7e52515ce37191b193cf3365903c4f3951e35", "shasum": "" }, "require": { @@ -2567,7 +2583,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.4" + "source": "https://github.com/symfony/config/tree/v6.4.8" }, "funding": [ { @@ -2583,20 +2599,20 @@ "type": "tidelift" } ], - "time": "2024-02-26T07:52:26+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/console", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0d9e4eb5ad413075624378f474c4167ea202de78" + "reference": "be5854cee0e8c7b110f00d695d11debdfa1a2a91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0d9e4eb5ad413075624378f474c4167ea202de78", - "reference": "0d9e4eb5ad413075624378f474c4167ea202de78", + "url": "https://api.github.com/repos/symfony/console/zipball/be5854cee0e8c7b110f00d695d11debdfa1a2a91", + "reference": "be5854cee0e8c7b110f00d695d11debdfa1a2a91", "shasum": "" }, "require": { @@ -2661,7 +2677,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.4" + "source": "https://github.com/symfony/console/tree/v6.4.8" }, "funding": [ { @@ -2677,20 +2693,20 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "6236e5e843cb763e9d0f74245678b994afea5363" + "reference": "d3b618176e8c3a9e5772151c51eba0c52a0c771c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/6236e5e843cb763e9d0f74245678b994afea5363", - "reference": "6236e5e843cb763e9d0f74245678b994afea5363", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d3b618176e8c3a9e5772151c51eba0c52a0c771c", + "reference": "d3b618176e8c3a9e5772151c51eba0c52a0c771c", "shasum": "" }, "require": { @@ -2742,7 +2758,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.4" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.8" }, "funding": [ { @@ -2758,20 +2774,20 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { @@ -2780,7 +2796,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -2809,7 +2825,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -2825,20 +2841,20 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/dotenv", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "f6f0a3dd102915b4c5bfdf4f4e3139a8cbf477a0" + "reference": "55aefa0029adff89ecffdb560820e945c7983f06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/f6f0a3dd102915b4c5bfdf4f4e3139a8cbf477a0", - "reference": "f6f0a3dd102915b4c5bfdf4f4e3139a8cbf477a0", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/55aefa0029adff89ecffdb560820e945c7983f06", + "reference": "55aefa0029adff89ecffdb560820e945c7983f06", "shasum": "" }, "require": { @@ -2883,7 +2899,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.4" + "source": "https://github.com/symfony/dotenv/tree/v6.4.8" }, "funding": [ { @@ -2899,20 +2915,20 @@ "type": "tidelift" } ], - "time": "2024-02-08T17:53:17+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "c725219bdf2afc59423c32793d5019d2a904e13a" + "reference": "ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/c725219bdf2afc59423c32793d5019d2a904e13a", - "reference": "c725219bdf2afc59423c32793d5019d2a904e13a", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc", + "reference": "ef836152bf13472dc5fb5b08b0c0c4cfeddc0fcc", "shasum": "" }, "require": { @@ -2958,7 +2974,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.4" + "source": "https://github.com/symfony/error-handler/tree/v6.4.8" }, "funding": [ { @@ -2974,20 +2990,20 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "ae9d3a6f3003a6caf56acd7466d8d52378d44fef" + "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae9d3a6f3003a6caf56acd7466d8d52378d44fef", - "reference": "ae9d3a6f3003a6caf56acd7466d8d52378d44fef", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8d7507f02b06e06815e56bb39aa0128e3806208b", + "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b", "shasum": "" }, "require": { @@ -3038,7 +3054,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.8" }, "funding": [ { @@ -3054,20 +3070,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.4.0", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" + "reference": "4e64b49bf370ade88e567de29465762e316e4224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/4e64b49bf370ade88e567de29465762e316e4224", + "reference": "4e64b49bf370ade88e567de29465762e316e4224", "shasum": "" }, "require": { @@ -3114,7 +3130,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.2" }, "funding": [ { @@ -3130,20 +3146,20 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-01-23T14:51:35+00:00" }, { "name": "symfony/expression-language", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "b4a4ae33fbb33a99d23c5698faaecadb76ad0fe4" + "reference": "0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/b4a4ae33fbb33a99d23c5698faaecadb76ad0fe4", - "reference": "b4a4ae33fbb33a99d23c5698faaecadb76ad0fe4", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a", + "reference": "0b63cb437741a42104d3ccc9bf60bbd8e1acbd2a", "shasum": "" }, "require": { @@ -3178,7 +3194,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v6.4.3" + "source": "https://github.com/symfony/expression-language/tree/v6.4.8" }, "funding": [ { @@ -3194,20 +3210,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb" + "reference": "4d37529150e7081c51b3c5d5718c55a04a9503f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb", - "reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/4d37529150e7081c51b3c5d5718c55a04a9503f3", + "reference": "4d37529150e7081c51b3c5d5718c55a04a9503f3", "shasum": "" }, "require": { @@ -3215,6 +3231,9 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, + "require-dev": { + "symfony/process": "^5.4|^6.4|^7.0" + }, "type": "library", "autoload": { "psr-4": { @@ -3241,7 +3260,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.3" + "source": "https://github.com/symfony/filesystem/tree/v6.4.8" }, "funding": [ { @@ -3257,20 +3276,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/finder", - "version": "v6.4.0", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "11d736e97f116ac375a81f96e662911a34cd50ce" + "reference": "3ef977a43883215d560a2cecb82ec8e62131471c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/11d736e97f116ac375a81f96e662911a34cd50ce", - "reference": "11d736e97f116ac375a81f96e662911a34cd50ce", + "url": "https://api.github.com/repos/symfony/finder/zipball/3ef977a43883215d560a2cecb82ec8e62131471c", + "reference": "3ef977a43883215d560a2cecb82ec8e62131471c", "shasum": "" }, "require": { @@ -3305,7 +3324,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.0" + "source": "https://github.com/symfony/finder/tree/v6.4.8" }, "funding": [ { @@ -3321,7 +3340,7 @@ "type": "tidelift" } ], - "time": "2023-10-31T17:30:12+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/flex", @@ -3390,16 +3409,16 @@ }, { "name": "symfony/framework-bundle", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "c76d3881596860ead95f5444a5ce4414447f0067" + "reference": "7c7739f87f1a8be1c2f5e7d28addfe763a917acb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c76d3881596860ead95f5444a5ce4414447f0067", - "reference": "c76d3881596860ead95f5444a5ce4414447f0067", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/7c7739f87f1a8be1c2f5e7d28addfe763a917acb", + "reference": "7c7739f87f1a8be1c2f5e7d28addfe763a917acb", "shasum": "" }, "require": { @@ -3518,7 +3537,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.4.4" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.8" }, "funding": [ { @@ -3534,27 +3553,27 @@ "type": "tidelift" } ], - "time": "2024-02-22T22:50:59+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.5", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "f3c86a60a3615f466333a11fd42010d4382a82c7" + "reference": "61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/f3c86a60a3615f466333a11fd42010d4382a82c7", - "reference": "f3c86a60a3615f466333a11fd42010d4382a82c7", + "url": "https://api.github.com/repos/symfony/http-client/zipball/61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05", + "reference": "61faba993e620fc22d4f0ab3b6bcf8fbb0d44b05", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "^3", + "symfony/http-client-contracts": "^3.4.1", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -3572,7 +3591,7 @@ "amphp/http-client": "^4.2.1", "amphp/http-tunnel": "^1.0", "amphp/socket": "^1.1", - "guzzlehttp/promises": "^1.4", + "guzzlehttp/promises": "^1.4|^2.0", "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", @@ -3611,7 +3630,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.5" + "source": "https://github.com/symfony/http-client/tree/v6.4.8" }, "funding": [ { @@ -3627,20 +3646,20 @@ "type": "tidelift" } ], - "time": "2024-03-02T12:45:30+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "1ee70e699b41909c209a0c930f11034b93578654" + "reference": "20414d96f391677bf80078aa55baece78b82647d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/1ee70e699b41909c209a0c930f11034b93578654", - "reference": "1ee70e699b41909c209a0c930f11034b93578654", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", + "reference": "20414d96f391677bf80078aa55baece78b82647d", "shasum": "" }, "require": { @@ -3649,7 +3668,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3689,7 +3708,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" }, "funding": [ { @@ -3705,20 +3724,20 @@ "type": "tidelift" } ], - "time": "2023-07-30T20:28:31+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304" + "reference": "27de8cc95e11db7a50b027e71caaab9024545947" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304", - "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/27de8cc95e11db7a50b027e71caaab9024545947", + "reference": "27de8cc95e11db7a50b027e71caaab9024545947", "shasum": "" }, "require": { @@ -3766,7 +3785,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.4" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.8" }, "funding": [ { @@ -3782,20 +3801,20 @@ "type": "tidelift" } ], - "time": "2024-02-08T15:01:18+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.5", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "f6947cb939d8efee137797382cb4db1af653ef75" + "reference": "6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f6947cb939d8efee137797382cb4db1af653ef75", - "reference": "f6947cb939d8efee137797382cb4db1af653ef75", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1", + "reference": "6c519aa3f32adcfd1d1f18d923f6b227d9acf3c1", "shasum": "" }, "require": { @@ -3850,6 +3869,7 @@ "symfony/translation-contracts": "^2.5|^3", "symfony/uid": "^5.4|^6.0|^7.0", "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.4|^7.0", "symfony/var-exporter": "^6.2|^7.0", "twig/twig": "^2.13|^3.0.4" }, @@ -3879,7 +3899,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.5" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.8" }, "funding": [ { @@ -3895,20 +3915,20 @@ "type": "tidelift" } ], - "time": "2024-03-04T21:00:47+00:00" + "time": "2024-06-02T16:06:25+00:00" }, { "name": "symfony/lock", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/lock.git", - "reference": "1cabf3cc775b1aa6008ebd471fa773444af4e956" + "reference": "1387f50285c23607467c1f05b258bde65f1ab276" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/lock/zipball/1cabf3cc775b1aa6008ebd471fa773444af4e956", - "reference": "1cabf3cc775b1aa6008ebd471fa773444af4e956", + "url": "https://api.github.com/repos/symfony/lock/zipball/1387f50285c23607467c1f05b258bde65f1ab276", + "reference": "1387f50285c23607467c1f05b258bde65f1ab276", "shasum": "" }, "require": { @@ -3958,7 +3978,7 @@ "semaphore" ], "support": { - "source": "https://github.com/symfony/lock/tree/v6.4.3" + "source": "https://github.com/symfony/lock/tree/v6.4.8" }, "funding": [ { @@ -3974,20 +3994,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/maker-bundle", - "version": "v1.56.0", + "version": "v1.60.0", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "bbb7949ae048363df7c8439abeddef8befd155ce" + "reference": "c305a02a22974670f359d4274c9431e1a191f559" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/bbb7949ae048363df7c8439abeddef8befd155ce", - "reference": "bbb7949ae048363df7c8439abeddef8befd155ce", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/c305a02a22974670f359d4274c9431e1a191f559", + "reference": "c305a02a22974670f359d4274c9431e1a191f559", "shasum": "" }, "require": { @@ -4050,7 +4070,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.56.0" + "source": "https://github.com/symfony/maker-bundle/tree/v1.60.0" }, "funding": [ { @@ -4066,20 +4086,20 @@ "type": "tidelift" } ], - "time": "2024-03-04T13:36:45+00:00" + "time": "2024-06-10T06:03:18+00:00" }, { "name": "symfony/mime", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "5017e0a9398c77090b7694be46f20eb796262a34" + "reference": "618597ab8b78ac86d1c75a9d0b35540cda074f33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/5017e0a9398c77090b7694be46f20eb796262a34", - "reference": "5017e0a9398c77090b7694be46f20eb796262a34", + "url": "https://api.github.com/repos/symfony/mime/zipball/618597ab8b78ac86d1c75a9d0b35540cda074f33", + "reference": "618597ab8b78ac86d1c75a9d0b35540cda074f33", "shasum": "" }, "require": { @@ -4100,6 +4120,7 @@ "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.4|^7.0", "symfony/property-access": "^5.4|^6.0|^7.0", "symfony/property-info": "^5.4|^6.0|^7.0", "symfony/serializer": "^6.3.2|^7.0" @@ -4134,7 +4155,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.3" + "source": "https://github.com/symfony/mime/tree/v6.4.8" }, "funding": [ { @@ -4150,20 +4171,20 @@ "type": "tidelift" } ], - "time": "2024-01-30T08:32:12+00:00" + "time": "2024-06-01T07:50:16+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "db7468152b27242f1a4d10fabe278a2cfaa4eac0" + "reference": "0fbee64913b1c595e7650a1919ba3edba8d49ea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/db7468152b27242f1a4d10fabe278a2cfaa4eac0", - "reference": "db7468152b27242f1a4d10fabe278a2cfaa4eac0", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/0fbee64913b1c595e7650a1919ba3edba8d49ea7", + "reference": "0fbee64913b1c595e7650a1919ba3edba8d49ea7", "shasum": "" }, "require": { @@ -4213,7 +4234,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.4" + "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.8" }, "funding": [ { @@ -4229,7 +4250,7 @@ "type": "tidelift" } ], - "time": "2024-02-01T11:49:25+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/monolog-bundle", @@ -4314,16 +4335,16 @@ }, { "name": "symfony/options-resolver", - "version": "v6.4.0", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "22301f0e7fdeaacc14318928612dee79be99860e" + "reference": "22ab9e9101ab18de37839074f8a1197f55590c1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/22301f0e7fdeaacc14318928612dee79be99860e", - "reference": "22301f0e7fdeaacc14318928612dee79be99860e", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/22ab9e9101ab18de37839074f8a1197f55590c1b", + "reference": "22ab9e9101ab18de37839074f8a1197f55590c1b", "shasum": "" }, "require": { @@ -4361,7 +4382,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.0" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.8" }, "funding": [ { @@ -4377,20 +4398,20 @@ "type": "tidelift" } ], - "time": "2023-08-08T10:16:24+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "114788555e6d768d25fffdbae618cee48cbcd112" + "reference": "90ebbe946e5d64a5fad9ac9427e335045cf2bd31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/114788555e6d768d25fffdbae618cee48cbcd112", - "reference": "114788555e6d768d25fffdbae618cee48cbcd112", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/90ebbe946e5d64a5fad9ac9427e335045cf2bd31", + "reference": "90ebbe946e5d64a5fad9ac9427e335045cf2bd31", "shasum": "" }, "require": { @@ -4433,7 +4454,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.4" + "source": "https://github.com/symfony/password-hasher/tree/v6.4.8" }, "funding": [ { @@ -4449,7 +4470,7 @@ "type": "tidelift" } ], - "time": "2024-02-12T11:14:32+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -5085,16 +5106,16 @@ }, { "name": "symfony/process", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "710e27879e9be3395de2b98da3f52a946039f297" + "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/710e27879e9be3395de2b98da3f52a946039f297", - "reference": "710e27879e9be3395de2b98da3f52a946039f297", + "url": "https://api.github.com/repos/symfony/process/zipball/8d92dd79149f29e89ee0f480254db595f6a6a2c5", + "reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5", "shasum": "" }, "require": { @@ -5126,7 +5147,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.4" + "source": "https://github.com/symfony/process/tree/v6.4.8" }, "funding": [ { @@ -5142,20 +5163,20 @@ "type": "tidelift" } ], - "time": "2024-02-20T12:31:00+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/property-access", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "c0664db266024013e31446dd690b6bfcf218ad93" + "reference": "e4d9b00983612f9c0013ca37c61affdba2dd975a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/c0664db266024013e31446dd690b6bfcf218ad93", - "reference": "c0664db266024013e31446dd690b6bfcf218ad93", + "url": "https://api.github.com/repos/symfony/property-access/zipball/e4d9b00983612f9c0013ca37c61affdba2dd975a", + "reference": "e4d9b00983612f9c0013ca37c61affdba2dd975a", "shasum": "" }, "require": { @@ -5203,7 +5224,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.4.4" + "source": "https://github.com/symfony/property-access/tree/v6.4.8" }, "funding": [ { @@ -5219,20 +5240,20 @@ "type": "tidelift" } ], - "time": "2024-02-16T13:31:43+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/property-info", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "e96d740ab5ac39aa530c8eaa0720ea8169118e26" + "reference": "7f544bc6ceb1a6a2283c7af8e8621262c43b7ede" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/e96d740ab5ac39aa530c8eaa0720ea8169118e26", - "reference": "e96d740ab5ac39aa530c8eaa0720ea8169118e26", + "url": "https://api.github.com/repos/symfony/property-info/zipball/7f544bc6ceb1a6a2283c7af8e8621262c43b7ede", + "reference": "7f544bc6ceb1a6a2283c7af8e8621262c43b7ede", "shasum": "" }, "require": { @@ -5286,7 +5307,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.3" + "source": "https://github.com/symfony/property-info/tree/v6.4.8" }, "funding": [ { @@ -5302,20 +5323,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/routing", - "version": "v6.4.5", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "7fe30068e207d9c31c0138501ab40358eb2d49a4" + "reference": "8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/7fe30068e207d9c31c0138501ab40358eb2d49a4", - "reference": "7fe30068e207d9c31c0138501ab40358eb2d49a4", + "url": "https://api.github.com/repos/symfony/routing/zipball/8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58", + "reference": "8a40d0f9b01f0fbb80885d3ce0ad6714fb603a58", "shasum": "" }, "require": { @@ -5369,7 +5390,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.5" + "source": "https://github.com/symfony/routing/tree/v6.4.8" }, "funding": [ { @@ -5385,20 +5406,20 @@ "type": "tidelift" } ], - "time": "2024-02-27T12:33:30+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-bundle", - "version": "v6.4.5", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "b7825ec970f51fcc4982397856405728544df9ce" + "reference": "dfb286069b0332e1f1c21962133d17c0fbc1e5e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/b7825ec970f51fcc4982397856405728544df9ce", - "reference": "b7825ec970f51fcc4982397856405728544df9ce", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/dfb286069b0332e1f1c21962133d17c0fbc1e5e7", + "reference": "dfb286069b0332e1f1c21962133d17c0fbc1e5e7", "shasum": "" }, "require": { @@ -5481,7 +5502,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v6.4.5" + "source": "https://github.com/symfony/security-bundle/tree/v6.4.8" }, "funding": [ { @@ -5497,20 +5518,20 @@ "type": "tidelift" } ], - "time": "2024-03-02T12:45:30+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-core", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "bb10f630cf5b1819ff80aa3ad57a09c61268fc48" + "reference": "5fc7850ada5e8e03d78c1739c82c64d5e2f7d495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/bb10f630cf5b1819ff80aa3ad57a09c61268fc48", - "reference": "bb10f630cf5b1819ff80aa3ad57a09c61268fc48", + "url": "https://api.github.com/repos/symfony/security-core/zipball/5fc7850ada5e8e03d78c1739c82c64d5e2f7d495", + "reference": "5fc7850ada5e8e03d78c1739c82c64d5e2f7d495", "shasum": "" }, "require": { @@ -5567,7 +5588,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.3" + "source": "https://github.com/symfony/security-core/tree/v6.4.8" }, "funding": [ { @@ -5583,20 +5604,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "e10257dd26f965d75e96bbfc27e46efd943f3010" + "reference": "f46ab02b76311087873257071559edcaf6d7ab99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/e10257dd26f965d75e96bbfc27e46efd943f3010", - "reference": "e10257dd26f965d75e96bbfc27e46efd943f3010", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/f46ab02b76311087873257071559edcaf6d7ab99", + "reference": "f46ab02b76311087873257071559edcaf6d7ab99", "shasum": "" }, "require": { @@ -5635,7 +5656,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.3" + "source": "https://github.com/symfony/security-csrf/tree/v6.4.8" }, "funding": [ { @@ -5651,20 +5672,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/security-http", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "bf7548976c19ce751c95a3d012d0dcd27409e506" + "reference": "fb82ddec887dc67f3bcf4d6df3cb8efd529be104" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/bf7548976c19ce751c95a3d012d0dcd27409e506", - "reference": "bf7548976c19ce751c95a3d012d0dcd27409e506", + "url": "https://api.github.com/repos/symfony/security-http/zipball/fb82ddec887dc67f3bcf4d6df3cb8efd529be104", + "reference": "fb82ddec887dc67f3bcf4d6df3cb8efd529be104", "shasum": "" }, "require": { @@ -5723,7 +5744,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v6.4.4" + "source": "https://github.com/symfony/security-http/tree/v6.4.8" }, "funding": [ { @@ -5739,20 +5760,20 @@ "type": "tidelift" } ], - "time": "2024-02-26T07:52:26+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/serializer", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "88da7f8fe03c5f4c2a69da907f1de03fab2e6872" + "reference": "d6eda9966a3e5d1823c1cedf41bf98f8ed969d7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/88da7f8fe03c5f4c2a69da907f1de03fab2e6872", - "reference": "88da7f8fe03c5f4c2a69da907f1de03fab2e6872", + "url": "https://api.github.com/repos/symfony/serializer/zipball/d6eda9966a3e5d1823c1cedf41bf98f8ed969d7c", + "reference": "d6eda9966a3e5d1823c1cedf41bf98f8ed969d7c", "shasum": "" }, "require": { @@ -5821,7 +5842,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v6.4.4" + "source": "https://github.com/symfony/serializer/tree/v6.4.8" }, "funding": [ { @@ -5837,25 +5858,26 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.4.1", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -5863,7 +5885,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -5903,7 +5925,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" }, "funding": [ { @@ -5919,20 +5941,20 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/string", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9" + "reference": "a147c0f826c4a1f3afb763ab8e009e37c877a44d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9", - "reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9", + "url": "https://api.github.com/repos/symfony/string/zipball/a147c0f826c4a1f3afb763ab8e009e37c877a44d", + "reference": "a147c0f826c4a1f3afb763ab8e009e37c877a44d", "shasum": "" }, "require": { @@ -5989,7 +6011,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.4" + "source": "https://github.com/symfony/string/tree/v6.4.8" }, "funding": [ { @@ -6005,20 +6027,20 @@ "type": "tidelift" } ], - "time": "2024-02-01T13:16:41+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/translation", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "bce6a5a78e94566641b2594d17e48b0da3184a8e" + "reference": "a002933b13989fc4bd0b58e04bf7eec5210e438a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bce6a5a78e94566641b2594d17e48b0da3184a8e", - "reference": "bce6a5a78e94566641b2594d17e48b0da3184a8e", + "url": "https://api.github.com/repos/symfony/translation/zipball/a002933b13989fc4bd0b58e04bf7eec5210e438a", + "reference": "a002933b13989fc4bd0b58e04bf7eec5210e438a", "shasum": "" }, "require": { @@ -6084,7 +6106,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.4" + "source": "https://github.com/symfony/translation/tree/v6.4.8" }, "funding": [ { @@ -6100,20 +6122,20 @@ "type": "tidelift" } ], - "time": "2024-02-20T13:16:58+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.4.1", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "06450585bf65e978026bda220cdebca3f867fde7" + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/06450585bf65e978026bda220cdebca3f867fde7", - "reference": "06450585bf65e978026bda220cdebca3f867fde7", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", "shasum": "" }, "require": { @@ -6122,7 +6144,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -6162,7 +6184,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" }, "funding": [ { @@ -6178,20 +6200,20 @@ "type": "tidelift" } ], - "time": "2023-12-26T14:02:43+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/uid", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "1d31267211cc3a2fff32bcfc7c1818dac41b6fc0" + "reference": "35904eca37a84bb764c560cbfcac9f0ac2bcdbdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/1d31267211cc3a2fff32bcfc7c1818dac41b6fc0", - "reference": "1d31267211cc3a2fff32bcfc7c1818dac41b6fc0", + "url": "https://api.github.com/repos/symfony/uid/zipball/35904eca37a84bb764c560cbfcac9f0ac2bcdbdf", + "reference": "35904eca37a84bb764c560cbfcac9f0ac2bcdbdf", "shasum": "" }, "require": { @@ -6236,7 +6258,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v6.4.3" + "source": "https://github.com/symfony/uid/tree/v6.4.8" }, "funding": [ { @@ -6252,20 +6274,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/validator", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "1cf92edc9a94d16275efef949fa6748d11cc8f47" + "reference": "dab2781371d54c86f6b25623ab16abb2dde2870c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/1cf92edc9a94d16275efef949fa6748d11cc8f47", - "reference": "1cf92edc9a94d16275efef949fa6748d11cc8f47", + "url": "https://api.github.com/repos/symfony/validator/zipball/dab2781371d54c86f6b25623ab16abb2dde2870c", + "reference": "dab2781371d54c86f6b25623ab16abb2dde2870c", "shasum": "" }, "require": { @@ -6312,7 +6334,8 @@ "Symfony\\Component\\Validator\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/Resources/bin/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -6332,7 +6355,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.4" + "source": "https://github.com/symfony/validator/tree/v6.4.8" }, "funding": [ { @@ -6348,20 +6371,20 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-06-02T15:48:50+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "b439823f04c98b84d4366c79507e9da6230944b1" + "reference": "ad23ca4312395f0a8a8633c831ef4c4ee542ed25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b439823f04c98b84d4366c79507e9da6230944b1", - "reference": "b439823f04c98b84d4366c79507e9da6230944b1", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ad23ca4312395f0a8a8633c831ef4c4ee542ed25", + "reference": "ad23ca4312395f0a8a8633c831ef4c4ee542ed25", "shasum": "" }, "require": { @@ -6417,7 +6440,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.4" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.8" }, "funding": [ { @@ -6433,20 +6456,20 @@ "type": "tidelift" } ], - "time": "2024-02-15T11:23:52+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "0bd342e24aef49fc82a21bd4eedd3e665d177e5b" + "reference": "792ca836f99b340f2e9ca9497c7953948c49a504" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0bd342e24aef49fc82a21bd4eedd3e665d177e5b", - "reference": "0bd342e24aef49fc82a21bd4eedd3e665d177e5b", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/792ca836f99b340f2e9ca9497c7953948c49a504", + "reference": "792ca836f99b340f2e9ca9497c7953948c49a504", "shasum": "" }, "require": { @@ -6454,6 +6477,8 @@ "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", @@ -6492,7 +6517,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.4" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.8" }, "funding": [ { @@ -6508,20 +6533,20 @@ "type": "tidelift" } ], - "time": "2024-02-26T08:37:45+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/yaml", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "d75715985f0f94f978e3a8fa42533e10db921b90" + "reference": "52903de178d542850f6f341ba92995d3d63e60c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/d75715985f0f94f978e3a8fa42533e10db921b90", - "reference": "d75715985f0f94f978e3a8fa42533e10db921b90", + "url": "https://api.github.com/repos/symfony/yaml/zipball/52903de178d542850f6f341ba92995d3d63e60c9", + "reference": "52903de178d542850f6f341ba92995d3d63e60c9", "shasum": "" }, "require": { @@ -6564,7 +6589,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.3" + "source": "https://github.com/symfony/yaml/tree/v6.4.8" }, "funding": [ { @@ -6580,7 +6605,7 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "webmozart/assert", @@ -7083,12 +7108,12 @@ "source": { "type": "git", "url": "https://github.com/centreon/centreon-test-lib.git", - "reference": "d686936d55f7d2d20ee3ebcece13c12c6e6001db" + "reference": "67cb5c7117a04459c48453edb98413fda6a7183a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/centreon/centreon-test-lib/zipball/d686936d55f7d2d20ee3ebcece13c12c6e6001db", - "reference": "d686936d55f7d2d20ee3ebcece13c12c6e6001db", + "url": "https://api.github.com/repos/centreon/centreon-test-lib/zipball/67cb5c7117a04459c48453edb98413fda6a7183a", + "reference": "67cb5c7117a04459c48453edb98413fda6a7183a", "shasum": "" }, "require": { @@ -7138,20 +7163,84 @@ "issues": "https://github.com/centreon/centreon-test-lib/issues", "source": "https://github.com/centreon/centreon-test-lib/tree/master" }, - "time": "2024-06-03T09:51:01+00:00" + "time": "2024-08-30T15:03:34+00:00" + }, + { + "name": "clue/ndjson-react", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/clue/reactphp-ndjson.git", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "react/event-loop": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\React\\NDJson\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", + "homepage": "https://github.com/clue/reactphp-ndjson", + "keywords": [ + "NDJSON", + "json", + "jsonlines", + "newline", + "reactphp", + "streaming" + ], + "support": { + "issues": "https://github.com/clue/reactphp-ndjson/issues", + "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-12-23T10:58:28+00:00" }, { "name": "composer/pcre", - "version": "3.1.2", + "version": "3.1.4", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "4775f35b2d70865807c89d32c8e7385b86eb0ace" + "reference": "04229f163664973f68f38f6f73d917799168ef24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4775f35b2d70865807c89d32c8e7385b86eb0ace", - "reference": "4775f35b2d70865807c89d32c8e7385b86eb0ace", + "url": "https://api.github.com/repos/composer/pcre/zipball/04229f163664973f68f38f6f73d917799168ef24", + "reference": "04229f163664973f68f38f6f73d917799168ef24", "shasum": "" }, "require": { @@ -7193,7 +7282,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.2" + "source": "https://github.com/composer/pcre/tree/3.1.4" }, "funding": [ { @@ -7209,7 +7298,7 @@ "type": "tidelift" } ], - "time": "2024-03-07T15:38:35+00:00" + "time": "2024-05-27T13:40:54+00:00" }, { "name": "composer/semver", @@ -7294,16 +7383,16 @@ }, { "name": "composer/xdebug-handler", - "version": "3.0.3", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -7314,7 +7403,7 @@ "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, "type": "library", "autoload": { @@ -7338,9 +7427,9 @@ "performance" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -7356,7 +7445,115 @@ "type": "tidelift" } ], - "time": "2022-02-25T21:32:43+00:00" + "time": "2024-05-06T16:37:16+00:00" + }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^1.9.2", + "phpstan/phpstan-deprecation-rules": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.2.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2024-02-07T09:43:46+00:00" }, { "name": "filp/whoops", @@ -7562,25 +7759,32 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.51.0", + "version": "v3.58.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "127fa74f010da99053e3f5b62672615b72dd6efd" + "reference": "04e9424025677a86914b9a4944dbbf4060bb0aff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/127fa74f010da99053e3f5b62672615b72dd6efd", - "reference": "127fa74f010da99053e3f5b62672615b72dd6efd", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/04e9424025677a86914b9a4944dbbf4060bb0aff", + "reference": "04e9424025677a86914b9a4944dbbf4060bb0aff", "shasum": "" }, "require": { + "clue/ndjson-react": "^1.0", "composer/semver": "^3.4", "composer/xdebug-handler": "^3.0.3", "ext-filter": "*", "ext-json": "*", "ext-tokenizer": "*", + "fidry/cpu-core-counter": "^1.0", "php": "^7.4 || ^8.0", + "react/child-process": "^0.6.5", + "react/event-loop": "^1.0", + "react/promise": "^2.0 || ^3.0", + "react/socket": "^1.0", + "react/stream": "^1.0", "sebastian/diff": "^4.0 || ^5.0 || ^6.0", "symfony/console": "^5.4 || ^6.0 || ^7.0", "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", @@ -7595,6 +7799,7 @@ }, "require-dev": { "facile-it/paraunit": "^1.3 || ^2.0", + "infection/infection": "^0.27.11", "justinrainbow/json-schema": "^5.2", "keradus/cli-executor": "^2.1", "mikey179/vfsstream": "^1.6.11", @@ -7642,7 +7847,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.51.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.58.1" }, "funding": [ { @@ -7650,7 +7855,7 @@ "type": "github" } ], - "time": "2024-02-28T19:50:06+00:00" + "time": "2024-05-29T16:39:07+00:00" }, { "name": "guzzlehttp/guzzle", @@ -7979,16 +8184,16 @@ }, { "name": "instaclick/php-webdriver", - "version": "1.4.18", + "version": "1.4.19", "source": { "type": "git", "url": "https://github.com/instaclick/php-webdriver.git", - "reference": "a61a8459f86c79dd1f19934ea3929804f2e41f8c" + "reference": "3b2a2ddc4e0a690cc691d7e5952964cc4b9538b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/instaclick/php-webdriver/zipball/a61a8459f86c79dd1f19934ea3929804f2e41f8c", - "reference": "a61a8459f86c79dd1f19934ea3929804f2e41f8c", + "url": "https://api.github.com/repos/instaclick/php-webdriver/zipball/3b2a2ddc4e0a690cc691d7e5952964cc4b9538b1", + "reference": "3b2a2ddc4e0a690cc691d7e5952964cc4b9538b1", "shasum": "" }, "require": { @@ -8036,9 +8241,9 @@ ], "support": { "issues": "https://github.com/instaclick/php-webdriver/issues", - "source": "https://github.com/instaclick/php-webdriver/tree/1.4.18" + "source": "https://github.com/instaclick/php-webdriver/tree/1.4.19" }, - "time": "2023-12-08T07:11:19+00:00" + "time": "2024-03-19T01:58:53+00:00" }, { "name": "league/openapi-psr7-validator", @@ -8274,16 +8479,16 @@ }, { "name": "masterminds/html5", - "version": "2.8.1", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf" + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf", - "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", "shasum": "" }, "require": { @@ -8291,7 +8496,7 @@ "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8" + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" }, "type": "library", "extra": { @@ -8335,9 +8540,9 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.8.1" + "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" }, - "time": "2023-05-10T11:58:31+00:00" + "time": "2024-03-31T07:05:07+00:00" }, { "name": "myclabs/deep-copy", @@ -8971,16 +9176,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.62", + "version": "1.10.67", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "cd5c8a1660ed3540b211407c77abf4af193a6af9" + "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd5c8a1660ed3540b211407c77abf4af193a6af9", - "reference": "cd5c8a1660ed3540b211407c77abf4af193a6af9", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/16ddbe776f10da6a95ebd25de7c1dbed397dc493", + "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493", "shasum": "" }, "require": { @@ -9023,13 +9228,9 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2024-03-13T12:27:20+00:00" + "time": "2024-04-16T07:22:02+00:00" }, { "name": "phpstan/phpstan-beberlei-assert", @@ -9402,16 +9603,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.17", + "version": "9.6.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd" + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1a156980d78a6666721b7e8e8502fe210b587fcd", - "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8", + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8", "shasum": "" }, "require": { @@ -9485,7 +9686,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.17" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19" }, "funding": [ { @@ -9501,7 +9702,7 @@ "type": "tidelift" } ], - "time": "2024-02-23T13:14:51+00:00" + "time": "2024-04-05T04:35:58+00:00" }, { "name": "psr/http-client", @@ -9557,20 +9758,20 @@ }, { "name": "psr/http-factory", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -9594,7 +9795,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -9606,9 +9807,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -9820,18 +10021,548 @@ }, "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/child-process", + "version": "v0.6.5", + "source": { + "type": "git", + "url": "https://github.com/reactphp/child-process.git", + "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", + "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/event-loop": "^1.2", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", + "react/socket": "^1.8", + "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\ChildProcess\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven library for executing child processes with ReactPHP.", + "keywords": [ + "event-driven", + "process", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/child-process/issues", + "source": "https://github.com/reactphp/child-process/tree/v0.6.5" + }, + "funding": [ + { + "url": "https://github.com/WyriHaximus", + "type": "github" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-09-16T13:41:56+00:00" + }, + { + "name": "react/dns", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "c134600642fa615b46b41237ef243daa65bb64ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/c134600642fa615b46b41237ef243daa65bb64ec", + "reference": "c134600642fa615b46b41237ef243daa65bb64ec", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.0 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4 || ^3 || ^2", + "react/promise-timer": "^1.9" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.12.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-29T12:41:06+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-13T13:48:05+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "react/socket", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/216d3aec0b87f04a40ca04f481e6af01bdd1d038", + "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.11", + "react/event-loop": "^1.2", + "react/promise": "^3 || ^2.6 || ^1.2.1", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4 || ^3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.15.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-12-15T11:02:10+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" + }, { "name": "rector/rector", - "version": "1.0.2", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "7596fa6da06c6a20c012efe6bb3d9188a9113b11" + "reference": "73eb63e4f9011dba6b7c66c3262543014e352f34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/7596fa6da06c6a20c012efe6bb3d9188a9113b11", - "reference": "7596fa6da06c6a20c012efe6bb3d9188a9113b11", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/73eb63e4f9011dba6b7c66c3262543014e352f34", + "reference": "73eb63e4f9011dba6b7c66c3262543014e352f34", "shasum": "" }, "require": { @@ -9844,6 +10575,9 @@ "rector/rector-phpunit": "*", "rector/rector-symfony": "*" }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, "bin": [ "bin/rector" ], @@ -9866,7 +10600,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/1.0.2" + "source": "https://github.com/rectorphp/rector/tree/1.0.5" }, "funding": [ { @@ -9874,7 +10608,7 @@ "type": "github" } ], - "time": "2024-03-03T12:32:31+00:00" + "time": "2024-05-10T05:31:15+00:00" }, { "name": "respect/stringifier", @@ -9932,16 +10666,16 @@ }, { "name": "respect/validation", - "version": "2.3.4", + "version": "2.3.7", "source": { "type": "git", "url": "https://github.com/Respect/Validation.git", - "reference": "788939e35909cbc3dcd72202d616e04dd553b572" + "reference": "967f7b6cc71e3728bb0f766cc1aea0604b2955aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Respect/Validation/zipball/788939e35909cbc3dcd72202d616e04dd553b572", - "reference": "788939e35909cbc3dcd72202d616e04dd553b572", + "url": "https://api.github.com/repos/Respect/Validation/zipball/967f7b6cc71e3728bb0f766cc1aea0604b2955aa", + "reference": "967f7b6cc71e3728bb0f766cc1aea0604b2955aa", "shasum": "" }, "require": { @@ -9994,9 +10728,9 @@ ], "support": { "issues": "https://github.com/Respect/Validation/issues", - "source": "https://github.com/Respect/Validation/tree/2.3.4" + "source": "https://github.com/Respect/Validation/tree/2.3.7" }, - "time": "2024-03-11T21:14:03+00:00" + "time": "2024-04-13T09:45:55+00:00" }, { "name": "riverline/multipart-parser", @@ -10056,16 +10790,16 @@ }, { "name": "robertfausk/mink-panther-driver", - "version": "v1.1.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/robertfausk/mink-panther-driver.git", - "reference": "2a4067d419655eda0604ac4085916a7c42b3b904" + "reference": "52aa735bc0cf05f5fd9406f4da56136b00b9c5cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/robertfausk/mink-panther-driver/zipball/2a4067d419655eda0604ac4085916a7c42b3b904", - "reference": "2a4067d419655eda0604ac4085916a7c42b3b904", + "url": "https://api.github.com/repos/robertfausk/mink-panther-driver/zipball/52aa735bc0cf05f5fd9406f4da56136b00b9c5cb", + "reference": "52aa735bc0cf05f5fd9406f4da56136b00b9c5cb", "shasum": "" }, "require": { @@ -10087,7 +10821,7 @@ "type": "mink-driver", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-main": "1.1.x-dev" } }, "autoload": { @@ -10120,9 +10854,9 @@ ], "support": { "issues": "https://github.com/robertfausk/mink-panther-driver/issues", - "source": "https://github.com/robertfausk/mink-panther-driver/tree/v1.1.0" + "source": "https://github.com/robertfausk/mink-panther-driver/tree/v1.1.1" }, - "time": "2022-07-25T16:04:56+00:00" + "time": "2024-04-18T10:43:40+00:00" }, { "name": "sebastian/cli-parser", @@ -10926,16 +11660,16 @@ }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -10947,7 +11681,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -10968,8 +11702,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -10977,8 +11710,7 @@ "type": "github" } ], - "abandoned": true, - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", @@ -11161,16 +11893,16 @@ }, { "name": "symfony/browser-kit", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "495ffa2e6d17e199213f93768efa01af32bbf70e" + "reference": "62ab90b92066ef6cce5e79365625b4b1432464c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/495ffa2e6d17e199213f93768efa01af32bbf70e", - "reference": "495ffa2e6d17e199213f93768efa01af32bbf70e", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/62ab90b92066ef6cce5e79365625b4b1432464c8", + "reference": "62ab90b92066ef6cce5e79365625b4b1432464c8", "shasum": "" }, "require": { @@ -11209,7 +11941,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v6.4.3" + "source": "https://github.com/symfony/browser-kit/tree/v6.4.8" }, "funding": [ { @@ -11225,20 +11957,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/css-selector", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "ee0f7ed5cf298cc019431bb3b3977ebc52b86229" + "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/ee0f7ed5cf298cc019431bb3b3977ebc52b86229", - "reference": "ee0f7ed5cf298cc019431bb3b3977ebc52b86229", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/4b61b02fe15db48e3687ce1c45ea385d1780fe08", + "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08", "shasum": "" }, "require": { @@ -11274,7 +12006,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.3" + "source": "https://github.com/symfony/css-selector/tree/v6.4.8" }, "funding": [ { @@ -11290,20 +12022,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/dom-crawler", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "f0e7ec3fa17000e2d0cb4557b4b47c88a6a63531" + "reference": "105b56a0305d219349edeb60a800082eca864e4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/f0e7ec3fa17000e2d0cb4557b4b47c88a6a63531", - "reference": "f0e7ec3fa17000e2d0cb4557b4b47c88a6a63531", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/105b56a0305d219349edeb60a800082eca864e4b", + "reference": "105b56a0305d219349edeb60a800082eca864e4b", "shasum": "" }, "require": { @@ -11341,7 +12073,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.4.4" + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.8" }, "funding": [ { @@ -11357,7 +12089,7 @@ "type": "tidelift" } ], - "time": "2024-02-07T09:17:57+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/panther", @@ -11450,16 +12182,16 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "16ed5bdfd18e14fc7de347c8688e8ac479284222" + "reference": "937f47cc64922f283bb0c474f33415bba0a9fc0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/16ed5bdfd18e14fc7de347c8688e8ac479284222", - "reference": "16ed5bdfd18e14fc7de347c8688e8ac479284222", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/937f47cc64922f283bb0c474f33415bba0a9fc0d", + "reference": "937f47cc64922f283bb0c474f33415bba0a9fc0d", "shasum": "" }, "require": { @@ -11491,7 +12223,8 @@ "Symfony\\Bridge\\PhpUnit\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/bin/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -11511,7 +12244,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.4.4" + "source": "https://github.com/symfony/phpunit-bridge/tree/v6.4.8" }, "funding": [ { @@ -11527,7 +12260,7 @@ "type": "tidelift" } ], - "time": "2024-02-08T14:08:19+00:00" + "time": "2024-06-02T15:48:50+00:00" }, { "name": "symfony/polyfill-php81", @@ -11607,16 +12340,16 @@ }, { "name": "symfony/stopwatch", - "version": "v6.4.3", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "416596166641f1f728b0a64f5b9dd07cceb410c1" + "reference": "63e069eb616049632cde9674c46957819454b8aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/416596166641f1f728b0a64f5b9dd07cceb410c1", - "reference": "416596166641f1f728b0a64f5b9dd07cceb410c1", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/63e069eb616049632cde9674c46957819454b8aa", + "reference": "63e069eb616049632cde9674c46957819454b8aa", "shasum": "" }, "require": { @@ -11649,7 +12382,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.4.3" + "source": "https://github.com/symfony/stopwatch/tree/v6.4.8" }, "funding": [ { @@ -11665,20 +12398,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:35:58+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/twig-bridge", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "256f330026d1c97187b61aa5c29e529499877f13" + "reference": "57de1b7d7499053a2c5beb9344751e8bfd332649" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/256f330026d1c97187b61aa5c29e529499877f13", - "reference": "256f330026d1c97187b61aa5c29e529499877f13", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/57de1b7d7499053a2c5beb9344751e8bfd332649", + "reference": "57de1b7d7499053a2c5beb9344751e8bfd332649", "shasum": "" }, "require": { @@ -11758,7 +12491,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.4" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.8" }, "funding": [ { @@ -11774,20 +12507,20 @@ "type": "tidelift" } ], - "time": "2024-02-15T11:26:02+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "f60ba43a09d88395d05797af982588b57331ff4d" + "reference": "ef17bc8fc2cb2376b235cd1b98f0275a78c5ba65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/f60ba43a09d88395d05797af982588b57331ff4d", - "reference": "f60ba43a09d88395d05797af982588b57331ff4d", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/ef17bc8fc2cb2376b235cd1b98f0275a78c5ba65", + "reference": "ef17bc8fc2cb2376b235cd1b98f0275a78c5ba65", "shasum": "" }, "require": { @@ -11842,7 +12575,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.4.4" + "source": "https://github.com/symfony/twig-bundle/tree/v6.4.8" }, "funding": [ { @@ -11858,20 +12591,20 @@ "type": "tidelift" } ], - "time": "2024-02-15T11:23:52+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v6.4.4", + "version": "v6.4.8", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "a69d7124bfb2e15638ba0a1be94f0845d8d05ee4" + "reference": "bcc806d1360991de3bf78ac5ca0202db85de9bfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/a69d7124bfb2e15638ba0a1be94f0845d8d05ee4", - "reference": "a69d7124bfb2e15638ba0a1be94f0845d8d05ee4", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/bcc806d1360991de3bf78ac5ca0202db85de9bfc", + "reference": "bcc806d1360991de3bf78ac5ca0202db85de9bfc", "shasum": "" }, "require": { @@ -11924,7 +12657,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.4" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.8" }, "funding": [ { @@ -11940,7 +12673,7 @@ "type": "tidelift" } ], - "time": "2024-02-22T20:27:10+00:00" + "time": "2024-05-31T14:49:08+00:00" }, { "name": "theseer/tokenizer", @@ -11994,30 +12727,37 @@ }, { "name": "twig/twig", - "version": "v3.8.0", + "version": "v3.10.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" + "reference": "67f29781ffafa520b0bbfbd8384674b42db04572" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572", + "reference": "67f29781ffafa520b0bbfbd8384674b42db04572", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-php80": "^1.22" }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { "Twig\\": "src/" } @@ -12050,7 +12790,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.8.0" + "source": "https://github.com/twigphp/Twig/tree/v3.10.3" }, "funding": [ { @@ -12062,20 +12802,20 @@ "type": "tidelift" } ], - "time": "2023-11-21T18:54:41+00:00" + "time": "2024-05-16T10:04:27+00:00" }, { "name": "zircote/swagger-php", - "version": "4.8.5", + "version": "4.10.0", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "038da8ad219f1e9c3f82c5d84c47da3b6f35039c" + "reference": "2d983ce67b9eb7e18403ae7bc5e765f8ce7b8d56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/038da8ad219f1e9c3f82c5d84c47da3b6f35039c", - "reference": "038da8ad219f1e9c3f82c5d84c47da3b6f35039c", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/2d983ce67b9eb7e18403ae7bc5e765f8ce7b8d56", + "reference": "2d983ce67b9eb7e18403ae7bc5e765f8ce7b8d56", "shasum": "" }, "require": { @@ -12141,9 +12881,9 @@ ], "support": { "issues": "https://github.com/zircote/swagger-php/issues", - "source": "https://github.com/zircote/swagger-php/tree/4.8.5" + "source": "https://github.com/zircote/swagger-php/tree/4.10.0" }, - "time": "2024-03-07T23:56:26+00:00" + "time": "2024-06-06T22:42:02+00:00" } ], "aliases": [], @@ -12165,5 +12905,5 @@ "platform-overrides": { "php": "8.1" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/centreon/config/centreon.config.php.template b/centreon/config/centreon.config.php.template index e55a5b1b3b..ba1021de63 100644 --- a/centreon/config/centreon.config.php.template +++ b/centreon/config/centreon.config.php.template @@ -19,6 +19,13 @@ * */ +require_once __DIR__ . '/../vendor/autoload.php'; + +use Core\Security\Vault\Domain\Model\VaultConfiguration; +use Security\Encryption; +use Symfony\Component\Dotenv\Dotenv; +use Symfony\Component\HttpClient\CurlHttpClient; + // Define constants $constants = [ '_CENTREON_PATH_' => realpath(__DIR__ . '/..') . '/', @@ -30,6 +37,67 @@ $constants = [ '_CENTREON_MARIA_DB_MIN_VERSION_' => '10.5', ]; +$createVaultConfiguration = function(): VaultConfiguration +{ + $vaultConfigurationInformation = json_decode(file_get_contents(_CENTREON_VARLIB_ . '/vault/vault.json'), true); + $encryptionManager = new Encryption(); + (new Dotenv())->bootEnv('/usr/share/centreon/.env'); + $encryptionManager->setFirstKey($_ENV["APP_SECRET"]); + return new VaultConfiguration( + encryption: $encryptionManager, + name: $vaultConfigurationInformation['name'], + address: $vaultConfigurationInformation['url'], + port: (int)$vaultConfigurationInformation['port'], + rootPath: $vaultConfigurationInformation['root_path'], + encryptedRoleId: $vaultConfigurationInformation['role_id'], + encryptedSecretId: $vaultConfigurationInformation['secret_id'], + salt: $vaultConfigurationInformation['salt'] + ); +}; + +$authenticateToVault = function( + CurlHttpClient $httpClient, + VaultConfiguration $vaultConfiguration +): string { + $url = 'https://' . $vaultConfiguration->getAddress() . ':' + . $vaultConfiguration->getPort() . '/v1/auth/approle/login'; + $body = [ + 'role_id' => $vaultConfiguration->getRoleId(), + 'secret_id' => $vaultConfiguration->getSecretId(), + ]; + $loginResponse = $httpClient->request('POST', $url, ['json' => $body]); + $content = json_decode($loginResponse->getContent(), true); + if (! isset($content['auth']['client_token'])) { + error_log($url . ' Unable to retrieve client token from Vault'); + + throw new \Exception('Unable to authenticate to Vault'); + } + + return $content['auth']['client_token']; +}; + +$retrieveDatabaseCredentialsFromVault = function( + string $token, + string $vaultPath, + CurlHttpClient $httpClient, + VaultConfiguration $vaultConfiguration +): array { + $databaseCredentialsUrl = 'https://' . $vaultConfiguration->getAddress() . ':' + . $vaultConfiguration->getPort() . '/v1/' . $vaultPath; + $credentialsResponse = $httpClient->request('GET', $databaseCredentialsUrl, ['headers' => ['X-Vault-Token' => $token]]); + $credentialContent = json_decode($credentialsResponse->getContent(), true); + if (! isset($credentialContent['data']['data']['_DBUSERNAME'], $credentialContent['data']['data']['_DBPASSWORD'])) { + error_log('Unable to retrieve database credentials from Vault'); + + throw new \Exception('Unable to retrieve database credentials from Vault'); + } + + return [ + 'username' => $credentialContent['data']['data']['_DBUSERNAME'], + 'password' => $credentialContent['data']['data']['_DBPASSWORD'] + ]; +}; + foreach ($constants as $name => $value) { if (!defined($name)) { define($name, $value); @@ -47,6 +115,29 @@ if (file_exists(_CENTREON_ETC_ . '/centreon.conf.php')) { define('hostCentstorage', $conf_centreon['hostCentstorage']); } + + if ( + ! defined('user') + && ! defined('password') + && file_exists(_CENTREON_VARLIB_ . '/vault/vault.json') + && str_starts_with($conf_centreon['user'], 'secret::') + && str_starts_with($conf_centreon['password'], 'secret::') + ) { + try { + $vaultConfiguration = $createVaultConfiguration(); + $httpClient = new CurlHttpClient(); + $token = $authenticateToVault($httpClient, $vaultConfiguration); + $databaseVaultPathPart = explode("::", $conf_centreon['user']); + array_pop($databaseVaultPathPart); + $vaultPath = end($databaseVaultPathPart); + $credentialContent = $retrieveDatabaseCredentialsFromVault($token, $vaultPath, $httpClient, $vaultConfiguration); + $conf_centreon['user'] = $credentialContent['username']; + $conf_centreon['password'] = $credentialContent['password']; + } catch (\Throwable $ex) { + error_log((string) $ex); + } + } + if (!defined('user')) { define('user', $conf_centreon['user']); } diff --git a/centreon/config/features.json b/centreon/config/features.json index c716b5c1b1..170a1ced01 100644 --- a/centreon/config/features.json +++ b/centreon/config/features.json @@ -1,11 +1,10 @@ { "notification": 2, - "dashboard": 3, "map_visx_viewer": 0, "vault": 0, + "vault_broker": 0, + "vault_gorgone": 0, "ad_exclusion_periods": 0, - "resource_status_tree_view": 3, - "resource_status_filter_revamp": 3, "resource_access_management": 2, - "dashboard_playlist": 3 + "resources_table_widget_open_tickets": 0 } diff --git a/centreon/config/packages/Centreon.yaml b/centreon/config/packages/Centreon.yaml index 30536bb3d2..60be43b7de 100644 --- a/centreon/config/packages/Centreon.yaml +++ b/centreon/config/packages/Centreon.yaml @@ -38,17 +38,22 @@ services: - '../../src/Core/Media/*' - '../../src/Core/Command/*' - '../../src/Core/ResourceAccess/*' + - '../../src/Core/TimePeriod/*' - '../../src/Core/Service/*' - '../../src/Core/HostGroup/*' - '../../src/Core/ServiceGroup/*' - '../../src/Core/Host/*' - '../../src/Core/Broker/*' + - '../../src/Core/AdditionalConnectorConfiguration/*' + - '../../src/Core/Security/Vault/*' bind: $isCloudPlatform: '%env(bool:IS_CLOUD_PLATFORM)%' Logger: class: Centreon\Domain\Log\Logger + + Core\Common\Infrastructure\FeatureFlags: arguments: ['%env(bool:IS_CLOUD_PLATFORM)%', '%env(file:resolve:FILE_FEATURE_FLAGS)%'] public: true @@ -89,11 +94,14 @@ services: arguments: ['%env(APP_SECRET)%'] public: true - Core\Security\Vault\Application\Repository\WriteVaultConfigurationRepositoryInterface: - class: Core\Security\Vault\Infrastructure\Repository\FsWriteVaultConfigurationRepository + + Core\Common\Application\Repository\WriteVaultRepositoryInterface: + class: Core\Common\Infrastructure\Repository\WriteVaultRepository + public: true + + Core\Common\Application\Repository\ReadVaultRepositoryInterface: + class: Core\Common\Infrastructure\Repository\ReadVaultRepository public: true - arguments: - $configurationFile: '%vault_conf_path%' # JSON Validator Centreon\Domain\Service\JsonValidator\Interfaces\JsonValidatorInterface: @@ -162,8 +170,8 @@ services: class: Centreon\Infrastructure\MonitoringServer\Repository\MonitoringServerConfigurationRepositoryApi public: true calls: - - method: setTimeout - arguments: ['%curl.timeout%'] + - method: setTimeout + arguments: ['%curl.timeout%'] # Platform topology register server Centreon\Domain\PlatformTopology\Interfaces\PlatformTopologyServiceInterface: @@ -303,11 +311,6 @@ services: arguments: ['%centreon_var_lib%', '%centreon_install_path%'] public: true - Core\Security\Vault\Application\Repository\ReadVaultConfigurationRepositoryInterface: - class: Core\Security\Vault\Infrastructure\Repository\FsReadVaultConfigurationRepository - public: true - arguments: - $configurationFile: '%vault_conf_path%' # Monitoring resources @@ -320,10 +323,8 @@ services: tags: ['monitoring.resource.acl'] Core\Security\ProviderConfiguration\Application\Repository\ReadProviderConfigurationsRepositoryInterface: tags: ['authentication.provider.repositories'] - Core\Security\ProviderConfiguration\Application\UseCase\FindProviderConfigurations\ProviderResponse\ProviderResponseInterface: - tags: ['authentication.provider.responses'] - Core\Security\ProviderConfiguration\Infrastructure\Api\FindProviderConfigurations\ProviderPresenter\ProviderPresenterInterface: - tags: ['authentication.provider.presenters'] + Core\Security\ProviderConfiguration\Application\UseCase\FindProviderConfigurations\ProviderConfigurationDtoFactoryInterface: + tags: ['authentication.provider.response.factories'] Core\Platform\Application\Validator\RequirementValidatorInterface: tags: ['platform.requirement.validators'] Core\Platform\Infrastructure\Validator\RequirementValidators\DatabaseRequirementValidatorInterface: @@ -336,19 +337,20 @@ services: tags: ['dashboard.playlist.widget.data.providers'] Symfony\Component\Console\Command\Command: tags: ['script.command'] + Core\Resources\Infrastructure\Repository\ExtraDataProviders\ExtraDataProviderInterface: + tags: ['monitoring.resource.extra.providers'] + Core\Resources\Infrastructure\API\ExtraDataNormalizer\ExtraDataNormalizerInterface: + tags: ['monitoring.resource.extra.normalizers'] Core\Common\Infrastructure\CommandInitializer: class: Core\Common\Infrastructure\CommandInitializer public: true arguments: - - !tagged_iterator script.command + - !tagged_iterator script.command Core\Security\ProviderConfiguration\Application\UseCase\FindProviderConfigurations\FindProviderConfigurations: arguments: - - !tagged_iterator 'authentication.provider.responses' - - Core\Security\ProviderConfiguration\Infrastructure\Api\FindProviderConfigurations\FindProviderConfigurationsPresenter: - arguments: [!tagged_iterator 'authentication.provider.presenters'] + - !tagged_iterator 'authentication.provider.response.factories' Core\Infrastructure\RealTime\Hypermedia\HypermediaCreator: class: Core\Infrastructure\RealTime\Hypermedia\HypermediaCreator @@ -451,6 +453,8 @@ services: Security\Domain\Authentication\Interfaces\OpenIdProviderInterface: class: Core\Security\Authentication\Domain\Provider\OpenIdProvider + bind: + $isCloudPlatform: '%env(bool:IS_CLOUD_PLATFORM)%' tags: ['authentication.providers'] Security\Domain\Authentication\Interfaces\WebSSOProviderInterface: diff --git a/centreon/config/packages/framework.yaml b/centreon/config/packages/framework.yaml index e105d26d2d..d5356ce92c 100644 --- a/centreon/config/packages/framework.yaml +++ b/centreon/config/packages/framework.yaml @@ -15,3 +15,10 @@ framework: cookie_secure: auto cookie_samesite: lax storage_factory_id: session.storage.factory.native + + serializer: + enabled: true + name_converter: 'serializer.name_converter.camel_case_to_snake_case' + mapping: + paths: + - '%kernel.project_dir%/config/symfony_serializer' diff --git a/centreon/config/packages/validator.yaml b/centreon/config/packages/validator.yaml index 876384c785..bbd2e443f3 100644 --- a/centreon/config/packages/validator.yaml +++ b/centreon/config/packages/validator.yaml @@ -1,6 +1,6 @@ framework: validation: enabled: true - enable_annotations: false + enable_annotations: true email_validation_mode: html5 diff --git a/centreon/config/services.yaml b/centreon/config/services.yaml index c3168976f3..6f358ae30e 100644 --- a/centreon/config/services.yaml +++ b/centreon/config/services.yaml @@ -7,7 +7,7 @@ parameters: locale: en api.header: "Api-Version" - api.version.latest: "24.04" + api.version.latest: "24.09" database_host: "%env(hostCentreon)%" database_port: "%env(port)%" database_db: "%env(db)%" @@ -18,7 +18,7 @@ parameters: validation_path: "%env(_CENTREON_PATH_)%config/packages/validator" centreon_path: "%env(_CENTREON_PATH_)%" centreon_etc_path: "%env(_CENTREON_ETC_)%" - vault_conf_path: "%centreon_var_lib%/vault/vault.yaml" + vault_conf_path: "%centreon_var_lib%/vault/vault.json" centreon_install_path: "%centreon_path%/www/install" translation_path: "%centreon_path%/www/locale" log_path: "%env(_CENTREON_LOG_)%" @@ -105,6 +105,23 @@ services: $resourceTypes: !tagged_iterator 'monitoring.resource.type' $sqlRequestTranslator: '@sqlRequestTranslator' $resourceACLProviders: !tagged_iterator 'monitoring.resource.acl' + $extraDataProviders: !tagged_iterator 'monitoring.resource.extra.providers' + + Core\Resources\Application\UseCase\FindResources\FindResources: + arguments: + $extraDataProviders: !tagged_iterator 'monitoring.resource.extra.providers' + + Core\Resources\Application\UseCase\FindResourcesByParent\FindResourcesByParent: + arguments: + $extraDataProviders: !tagged_iterator 'monitoring.resource.extra.providers' + + Core\Resources\Infrastructure\API\FindResources\FindResourcesPresenter: + arguments: + $extraDataNormalizers: !tagged_iterator 'monitoring.resource.extra.normalizers' + + Core\Resources\Infrastructure\API\FindResourcesByParent\FindResourcesByParentPresenter: + arguments: + $extraDataNormalizers: !tagged_iterator 'monitoring.resource.extra.normalizers' Centreon\Application\Controller\MonitoringResourceController: arguments: diff --git a/centreon/config/symfony_serializer/TimePeriod/Day.yaml b/centreon/config/symfony_serializer/TimePeriod/Day.yaml new file mode 100644 index 0000000000..c2d74e453a --- /dev/null +++ b/centreon/config/symfony_serializer/TimePeriod/Day.yaml @@ -0,0 +1,6 @@ +Core\TimePeriod\Domain\Model\Day: + attributes: + day: + groups: ['TimePeriod:Read'] + timeRange: + groups: ['TimePeriod:Read'] diff --git a/centreon/config/symfony_serializer/TimePeriod/ExtraTimePeriod.yaml b/centreon/config/symfony_serializer/TimePeriod/ExtraTimePeriod.yaml new file mode 100644 index 0000000000..666a3d3385 --- /dev/null +++ b/centreon/config/symfony_serializer/TimePeriod/ExtraTimePeriod.yaml @@ -0,0 +1,8 @@ +Core\TimePeriod\Domain\Model\ExtraTimePeriod: + attributes: + id: + groups: ['TimePeriod:Read'] + day_range: + groups: ['TimePeriod:Read'] + time_range: + groups: ['TimePeriod:Read'] diff --git a/centreon/config/symfony_serializer/TimePeriod/Template.yaml b/centreon/config/symfony_serializer/TimePeriod/Template.yaml new file mode 100644 index 0000000000..b0b2efe525 --- /dev/null +++ b/centreon/config/symfony_serializer/TimePeriod/Template.yaml @@ -0,0 +1,6 @@ +Core\TimePeriod\Domain\Model\Template: + attributes: + id: + groups: ['TimePeriod:Read'] + alias: + groups: ['TimePeriod:Read'] diff --git a/centreon/config/symfony_serializer/TimePeriod/TimePeriod.yaml b/centreon/config/symfony_serializer/TimePeriod/TimePeriod.yaml new file mode 100644 index 0000000000..3d49264e5d --- /dev/null +++ b/centreon/config/symfony_serializer/TimePeriod/TimePeriod.yaml @@ -0,0 +1,17 @@ +Core\TimePeriod\Domain\Model\TimePeriod: + attributes: + id: + groups: ['TimePeriod:Read'] + name: + groups: ['TimePeriod:Read'] + alias: + groups: ['TimePeriod:Read'] + days: + groups: ['TimePeriod:Read'] + templates: + groups: ['TimePeriod:Read'] + extraTimePeriods: + serialized_name: 'exceptions' + groups: ['TimePeriod:Read'] + + diff --git a/centreon/cron/outdated-token-removal.php b/centreon/cron/outdated-token-removal.php index 7b274fee24..9805513f30 100644 --- a/centreon/cron/outdated-token-removal.php +++ b/centreon/cron/outdated-token-removal.php @@ -35,12 +35,12 @@ $pearDB = new CentreonDB(); $pearDB->beginTransaction(); - try { - deleteExpiredProviderRefreshTokens($centreonLog, $pearDB); - deleteExpiredProviderTokens($centreonLog, $pearDB); - deleteExpiredSessions($centreonLog, $pearDB); +try { + deleteExpiredProviderRefreshTokens($centreonLog, $pearDB); + deleteExpiredProviderTokens($centreonLog, $pearDB); + deleteExpiredSessions($centreonLog, $pearDB); - $pearDB->commit(); + $pearDB->commit(); } catch (\Throwable) { $pearDB->rollBack(); $centreonLog->insertLog( diff --git a/centreon/cypress/fixtures/ACC/additionalConnector.json b/centreon/cypress/fixtures/ACC/additionalConnector.json new file mode 100644 index 0000000000..f7c9154614 --- /dev/null +++ b/centreon/cypress/fixtures/ACC/additionalConnector.json @@ -0,0 +1,31 @@ +{ + "id": 1, + "type": "vmware_v6", + "name": "VMWare1", + "description": "Description for VMWare1", + "pollers": [ + {"id": 101, "name": "Poller1"}, + {"id": 102, "name": "Poller2"} + ], + "parameters": { + "port": 443, + "vcenters": [ + { + "name": "vCenter1", + "url": "https://vcenter1.example.com/sdk", + "username": "user1", + "password": "password1" + }, + { + "name": "vCenter2", + "url": "192.0.0.1", + "username": "user2", + "password": "password2" + } + ] + }, + "created_by": {"id": 1, "name": "Alice"}, + "created_at": "2024-07-23T10:00:00Z", + "updated_by": {"id": 2, "name": "Bob"}, + "updated_at": "2024-07-23T10:30:00Z" +} diff --git a/centreon/cypress/fixtures/ACC/additionalConnectors.json b/centreon/cypress/fixtures/ACC/additionalConnectors.json new file mode 100644 index 0000000000..e7fb9cb128 --- /dev/null +++ b/centreon/cypress/fixtures/ACC/additionalConnectors.json @@ -0,0 +1,112 @@ +{ + "result": [ + { + "id": 1, + "type": "vmware_v6", + "name": "VMWare1", + "description": "Description for VMWare1", + "created_by": {"id": 1, "name": "Alice"}, + "created_at": "2024-07-23T10:00:00Z", + "updated_by": {"id": 2, "name": "Bob"}, + "updated_at": "2024-07-23T10:30:00Z" + }, + { + "id": 2, + "type": "vmware_v6", + "name": "VMWare2", + "description": "Description for VMWare2", + "created_by": {"id": 3, "name": "Charlie"}, + "created_at": "2024-07-22T11:00:00Z", + "updated_by": {"id": 4, "name": "Diana"}, + "updated_at": "2024-07-22T11:30:00Z" + }, + { + "id": 3, + "type": "vmware_v6", + "name": "VMWare3", + "description": "Description for VMWare3", + "created_by": {"id": 5, "name": "Eve"}, + "created_at": "2024-07-21T12:00:00Z", + "updated_by": {"id": 6, "name": "Frank"}, + "updated_at": "2024-07-21T12:30:00Z" + }, + { + "id": 4, + "type": "vmware_v6", + "name": "VMWare4", + "description": "Description for VMWare4", + "created_by": {"id": 7, "name": "Grace"}, + "created_at": "2024-07-20T13:00:00Z", + "updated_by": {"id": 8, "name": "Hank"}, + "updated_at": "2024-07-20T13:30:00Z" + }, + { + "id": 5, + "type": "vmware_v6", + "name": "VMWare5", + "description": "Description for VMWare5", + "created_by": {"id": 9, "name": "Ivy"}, + "created_at": "2024-07-19T14:00:00Z", + "updated_by": {"id": 10, "name": "Jack"}, + "updated_at": "2024-07-19T14:30:00Z" + }, + { + "id": 6, + "type": "vmware_v6", + "name": "VMWare6", + "description": "Description for VMWare6", + "created_by": {"id": 11, "name": "Kara"}, + "created_at": "2024-07-18T15:00:00Z", + "updated_by": {"id": 12, "name": "Leo"}, + "updated_at": "2024-07-18T15:30:00Z" + }, + { + "id": 7, + "type": "vmware_v6", + "name": "VMWare7", + "description": "Description for VMWare7", + "created_by": {"id": 13, "name": "Mia"}, + "created_at": "2024-07-17T16:00:00Z", + "updated_by": {"id": 14, "name": "Nate"}, + "updated_at": "2024-07-17T16:30:00Z" + }, + { + "id": 8, + "type": "vmware_v6", + "name": "VMWare8", + "description": "Description for VMWare8", + "created_by": {"id": 15, "name": "Olivia"}, + "created_at": "2024-07-16T17:00:00Z", + "updated_by": {"id": 16, "name": "Paul"}, + "updated_at": "2024-07-16T17:30:00Z" + }, + { + "id": 9, + "type": "vmware_v6", + "name": "VMWare9", + "description": "Description for VMWare9", + "created_by": {"id": 17, "name": "Quinn"}, + "created_at": "2024-07-15T18:00:00Z", + "updated_by": {"id": 18, "name": "Rita"}, + "updated_at": "2024-07-15T18:30:00Z" + }, + { + "id": 10, + "type": "vmware_v6", + "name": "VMWare10", + "description": "Description for VMWare10", + "created_by": {"id": 19, "name": "Steve"}, + "created_at": "2024-07-14T19:00:00Z", + "updated_by": {"id": 20, "name": "Tina"}, + "updated_at": "2024-07-14T19:30:00Z" + } + ], + "meta": { + "page": 1, + "limit": 10, + "search": {}, + "sort_by": {}, + "total": 44 + } + } + \ No newline at end of file diff --git a/centreon/cypress/fixtures/ACC/pollers-vmware.json b/centreon/cypress/fixtures/ACC/pollers-vmware.json new file mode 100644 index 0000000000..054df89776 --- /dev/null +++ b/centreon/cypress/fixtures/ACC/pollers-vmware.json @@ -0,0 +1,52 @@ +{ + "result": [ + { + "id": 1, + "name": "poller1" + }, + { + "id": 2, + "name": "poller2" + }, + { + "id": 3, + "name": "poller3" + }, + { + "id": 4, + "name": "poller4" + }, + { + "id": 5, + "name": "poller5" + }, + { + "id": 6, + "name": "poller6" + }, + { + "id": 7, + "name": "poller7" + }, + { + "id": 8, + "name": "poller8" + }, + { + "id": 9, + "name": "poller9" + }, + { + "id": 10, + "name": "poller10" + } + ], + "meta": { + "page": 1, + "limit": 10, + "search": {}, + "sort_by": {}, + "total": 10 + } + } + \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/ResourcesTable/resourcesStatus.json b/centreon/cypress/fixtures/Widgets/ResourcesTable/resourcesStatus.json index ac64b17334..9d63dd89c5 100644 --- a/centreon/cypress/fixtures/Widgets/ResourcesTable/resourcesStatus.json +++ b/centreon/cypress/fixtures/Widgets/ResourcesTable/resourcesStatus.json @@ -1,463 +1,481 @@ { - "result": [ - { - "uuid": "h14-s19", - "duration": "13h 29m", - "last_check": "4m 20s", - "short_type": "s", - "id": 19, - "type": "service", - "name": "Disk-\/", - "alias": null, - "fqdn": null, - "host_id": 14, - "service_id": 19, - "icon": null, - "monitoring_server_name": "Central", - "parent": { - "uuid": "h14", - "id": 14, - "name": "Centreon-Server", - "type": "host", - "short_type": "h", - "status": { - "code": 0, - "name": "UP", - "severity_code": 5 - }, - "alias": "Monitoring Server", - "fqdn": "127.0.0.1", - "monitoring_server_name": null - }, - "status": { - "code": 3, - "name": "UNKNOWN", - "severity_code": 3 - }, - "is_in_downtime": true, - "is_acknowledged": false, - "has_active_checks_enabled": true, - "has_passive_checks_enabled": false, - "last_status_change": "2024-01-21T22:33:57+01:00", - "tries": "3\/3 (H)", - "information": "(Execute command failed)", - "performance_data": null, - "is_notification_enabled": false, - "severity": null, - "links": { - "endpoints": { - "details": "\/centreon\/api\/latest\/monitoring\/resources\/hosts\/14\/services\/19", - "timeline": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/19\/timeline", - "status_graph": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/19\/metrics\/status", - "performance_graph": null, - "acknowledgement": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/19\/acknowledgements?limit=1", - "downtime": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/19\/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", - "check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/19\/check", - "forced_check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/19\/check", - "metrics": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/19\/metrics" - }, - "uris": { - "configuration": "\/centreon\/main.php?p=60201\u0026o=c\u0026service_id=19", - "logs": "\/centreon\/main.php?p=20301\u0026svc=14_19", - "reporting": "\/centreon\/main.php?p=30702\u0026period=yesterday\u0026start=\u0026end=\u0026host_id=14\u0026item=19" - }, - "externals": { - "action_url": "", - "notes": { - "label": "", - "url": "" - } - } - } + "result": [ + { + "uuid": "h14-s19", + "duration": "13h 29m", + "last_check": "4m 20s", + "short_type": "s", + "id": 19, + "type": "service", + "name": "Disk-/", + "alias": null, + "fqdn": null, + "host_id": 14, + "service_id": 19, + "icon": null, + "extra": { + "open_tickets": { + "tickets": { + "id": 2, + "subject": "description", + "created_at": "2024-02-24T14:35:17+01:00" + } + } + }, + "monitoring_server_name": "Central", + "parent": { + "uuid": "h14", + "id": 14, + "name": "Centreon-Server", + "type": "host", + "short_type": "h", + "status": { + "code": 0, + "name": "UP", + "severity_code": 5 }, - { - "uuid": "h14-s24", - "duration": "13h 30m", - "last_check": "1m 10s", - "short_type": "s", - "id": 24, - "type": "service", - "name": "Load", - "alias": null, - "fqdn": null, - "host_id": 14, - "service_id": 24, - "icon": null, - "monitoring_server_name": "Central", - "parent": { - "uuid": "h14", - "id": 14, - "name": "Centreon-Server", - "type": "host", - "short_type": "h", - "status": { - "code": 0, - "name": "UP", - "severity_code": 5 - }, - "alias": "Monitoring Server", - "fqdn": "127.0.0.1", - "monitoring_server_name": null - }, - "status": { - "code": 3, - "name": "UNKNOWN", - "severity_code": 3 - }, - "is_in_downtime": false, - "is_acknowledged": true, - "has_active_checks_enabled": true, - "has_passive_checks_enabled": false, - "last_status_change": "2024-01-21T22:32:42+01:00", - "tries": "3\/3 (H)", - "information": "(Execute command failed)", - "performance_data": null, - "is_notification_enabled": false, - "severity": null, - "links": { - "endpoints": { - "details": "\/centreon\/api\/latest\/monitoring\/resources\/hosts\/14\/services\/24", - "timeline": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/24\/timeline", - "status_graph": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/24\/metrics\/status", - "performance_graph": null, - "acknowledgement": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/24\/acknowledgements?limit=1", - "downtime": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/24\/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", - "check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/24\/check", - "forced_check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/24\/check", - "metrics": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/24\/metrics" - }, - "uris": { - "configuration": "\/centreon\/main.php?p=60201\u0026o=c\u0026service_id=24", - "logs": "\/centreon\/main.php?p=20301\u0026svc=14_24", - "reporting": "\/centreon\/main.php?p=30702\u0026period=yesterday\u0026start=\u0026end=\u0026host_id=14\u0026item=24" - }, - "externals": { - "action_url": "", - "notes": { - "label": "", - "url": "" - } - } - } + "alias": "Monitoring Server", + "fqdn": "127.0.0.1", + "monitoring_server_name": null + }, + "status": { + "code": 3, + "name": "UNKNOWN", + "severity_code": 3 + }, + "is_in_downtime": true, + "is_acknowledged": false, + "has_active_checks_enabled": true, + "has_passive_checks_enabled": false, + "last_status_change": "2024-01-21T22:33:57+01:00", + "tries": "3/3 (H)", + "information": "(Execute command failed)", + "performance_data": null, + "is_notification_enabled": false, + "severity": null, + "links": { + "endpoints": { + "details": "/centreon/api/latest/monitoring/resources/hosts/14/services/19", + "timeline": "/centreon/api/latest/monitoring/hosts/14/services/19/timeline", + "status_graph": "/centreon/api/latest/monitoring/hosts/14/services/19/metrics/status", + "performance_graph": null, + "acknowledgement": "/centreon/api/latest/monitoring/hosts/14/services/19/acknowledgements?limit=1", + "downtime": "/centreon/api/latest/monitoring/hosts/14/services/19/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", + "check": "/centreon/api/latest/monitoring/hosts/14/services/19/check", + "forced_check": "/centreon/api/latest/monitoring/hosts/14/services/19/check", + "metrics": "/centreon/api/latest/monitoring/hosts/14/services/19/metrics" }, - { - "uuid": "h14-s25", - "duration": "13h 32m", - "last_check": "1m 50s", - "short_type": "s", - "id": 25, - "type": "service", - "name": "Memory", - "alias": null, - "fqdn": null, - "host_id": 14, - "service_id": 25, - "icon": null, - "monitoring_server_name": "Central", - "parent": { - "uuid": "h14", - "id": 14, - "name": "Centreon-Server", - "type": "host", - "short_type": "h", - "status": { - "code": 0, - "name": "UP", - "severity_code": 5 - }, - "alias": "Monitoring Server", - "fqdn": "127.0.0.1", - "monitoring_server_name": null - }, - "status": { - "code": 3, - "name": "UNKNOWN", - "severity_code": 3 - }, - "is_in_downtime": false, - "is_acknowledged": false, - "has_active_checks_enabled": true, - "has_passive_checks_enabled": false, - "last_status_change": "2024-01-21T22:31:27+01:00", - "tries": "3\/3 (H)", - "information": "(Execute command failed)", - "performance_data": null, - "is_notification_enabled": false, - "severity": null, - "links": { - "endpoints": { - "details": "\/centreon\/api\/latest\/monitoring\/resources\/hosts\/14\/services\/25", - "timeline": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/25\/timeline", - "status_graph": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/25\/metrics\/status", - "performance_graph": null, - "acknowledgement": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/25\/acknowledgements?limit=1", - "downtime": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/25\/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", - "check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/25\/check", - "forced_check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/25\/check", - "metrics": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/25\/metrics" - }, - "uris": { - "configuration": "\/centreon\/main.php?p=60201\u0026o=c\u0026service_id=25", - "logs": "\/centreon\/main.php?p=20301\u0026svc=14_25", - "reporting": "\/centreon\/main.php?p=30702\u0026period=yesterday\u0026start=\u0026end=\u0026host_id=14\u0026item=25" - }, - "externals": { - "action_url": "", - "notes": { - "label": "", - "url": "" - } - } - } + "uris": { + "configuration": "/centreon/main.php?p=60201\u0026o=c\u0026service_id=19", + "logs": "/centreon/main.php?p=20301\u0026svc=14_19", + "reporting": "/centreon/main.php?p=30702\u0026period=yesterday\u0026start=\u0026end=\u0026host_id=14\u0026item=19" }, - { - "uuid": "h14-s26", - "duration": "13h 33m", - "last_check": "3m 5s", - "short_type": "s", - "id": 26, - "type": "service", - "name": "Ping", - "alias": null, - "fqdn": null, - "host_id": 14, - "service_id": 26, - "icon": null, - "monitoring_server_name": "Central", - "parent": { - "uuid": "h14", - "id": 14, - "name": "Centreon-Server", - "type": "host", - "short_type": "h", - "status": { - "code": 0, - "name": "UP", - "severity_code": 5 - }, - "alias": "Monitoring Server", - "fqdn": "127.0.0.1", - "monitoring_server_name": null - }, - "status": { - "code": 0, - "name": "OK", - "severity_code": 5 - }, - "is_in_downtime": false, - "is_acknowledged": false, - "has_active_checks_enabled": true, - "has_passive_checks_enabled": false, - "last_status_change": "2024-01-21T22:30:12+01:00", - "tries": "1\/3 (H)", - "information": "OK - 127.0.0.1 rta 0.023ms lost 0%", - "performance_data": null, - "is_notification_enabled": false, - "severity": null, - "links": { - "endpoints": { - "details": "\/centreon\/api\/latest\/monitoring\/resources\/hosts\/14\/services\/26", - "timeline": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/26\/timeline", - "status_graph": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/26\/metrics\/status", - "performance_graph": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/26\/metrics\/performance", - "acknowledgement": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/26\/acknowledgements?limit=1", - "downtime": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/26\/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", - "check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/26\/check", - "forced_check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/26\/check", - "metrics": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/services\/26\/metrics" - }, - "uris": { - "configuration": "\/centreon\/main.php?p=60201\u0026o=c\u0026service_id=26", - "logs": "\/centreon\/main.php?p=20301\u0026svc=14_26", - "reporting": "\/centreon\/main.php?p=30702\u0026period=yesterday\u0026start=\u0026end=\u0026host_id=14\u0026item=26" - }, - "externals": { - "action_url": "", - "notes": { - "label": "", - "url": "" - } - } - } + "externals": { + "action_url": "", + "notes": { + "label": "", + "url": "" + } + } + } + }, + { + "uuid": "h14-s24", + "duration": "13h 30m", + "last_check": "1m 10s", + "short_type": "s", + "id": 24, + "type": "service", + "name": "Load", + "alias": null, + "fqdn": null, + "host_id": 14, + "service_id": 24, + "icon": null, + "monitoring_server_name": "Central", + "parent": { + "uuid": "h14", + "id": 14, + "name": "Centreon-Server", + "type": "host", + "short_type": "h", + "status": { + "code": 0, + "name": "UP", + "severity_code": 5 }, - { - "uuid": "h14", - "duration": "13h 33m", - "last_check": "4m 20s", - "short_type": "h", - "id": 14, - "type": "host", - "name": "Centreon-Server", - "alias": "Monitoring Server", - "fqdn": "127.0.0.1", - "host_id": 14, - "service_id": null, - "icon": null, - "monitoring_server_name": "Central", - "parent": null, - "status": { - "code": 0, - "name": "UP", - "severity_code": 5 - }, - "is_in_downtime": false, - "is_acknowledged": false, - "has_active_checks_enabled": true, - "has_passive_checks_enabled": false, - "last_status_change": "2024-01-21T22:30:12+01:00", - "tries": "1\/5 (H)", - "information": "OK - 127.0.0.1 rta 0.051ms lost 0%", - "performance_data": null, - "is_notification_enabled": false, - "severity": null, - "links": { - "endpoints": { - "details": "\/centreon\/api\/latest\/monitoring\/resources\/hosts\/14", - "timeline": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/timeline", - "status_graph": null, - "performance_graph": null, - "acknowledgement": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/acknowledgements?limit=1", - "downtime": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", - "check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/check", - "forced_check": "\/centreon\/api\/latest\/monitoring\/hosts\/14\/check", - "metrics": null - }, - "uris": { - "configuration": "\/centreon\/main.php?p=60101\u0026o=c\u0026host_id=14", - "logs": "\/centreon\/main.php?p=20301\u0026h=14", - "reporting": "\/centreon\/main.php?p=307\u0026host=14" - }, - "externals": { - "action_url": "", - "notes": { - "label": "", - "url": "" - } - } - } + "alias": "Monitoring Server", + "fqdn": "127.0.0.1", + "monitoring_server_name": null + }, + "status": { + "code": 3, + "name": "UNKNOWN", + "severity_code": 3 + }, + "is_in_downtime": false, + "is_acknowledged": true, + "has_active_checks_enabled": true, + "has_passive_checks_enabled": false, + "last_status_change": "2024-01-21T22:32:42+01:00", + "tries": "3/3 (H)", + "information": "(Execute command failed)", + "performance_data": null, + "is_notification_enabled": false, + "severity": null, + "links": { + "endpoints": { + "details": "/centreon/api/latest/monitoring/resources/hosts/14/services/24", + "timeline": "/centreon/api/latest/monitoring/hosts/14/services/24/timeline", + "status_graph": "/centreon/api/latest/monitoring/hosts/14/services/24/metrics/status", + "performance_graph": null, + "acknowledgement": "/centreon/api/latest/monitoring/hosts/14/services/24/acknowledgements?limit=1", + "downtime": "/centreon/api/latest/monitoring/hosts/14/services/24/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", + "check": "/centreon/api/latest/monitoring/hosts/14/services/24/check", + "forced_check": "/centreon/api/latest/monitoring/hosts/14/services/24/check", + "metrics": "/centreon/api/latest/monitoring/hosts/14/services/24/metrics" }, - { - "uuid": "m2", - "duration": "1M 1w", - "last_check": "14m 55s", - "short_type": "m", - "id": 2, - "type": "metaservice", - "name": "AS_Total_FW_Connexion", - "alias": null, - "fqdn": null, - "host_id": 1972, - "service_id": null, - "icon": null, - "monitoring_server_name": "Central", - "parent": null, - "status": { - "code": 0, - "name": "OK", - "severity_code": 5 - }, - "is_in_downtime": false, - "is_acknowledged": false, - "has_active_checks_enabled": true, - "has_passive_checks_enabled": false, - "last_status_change": "2024-04-21T13:43:05+02:00", - "tries": "1\/2 (H)", - "information": "OK: AS FW Connect number: 200", - "performance_data": null, - "is_notification_enabled": false, - "severity": null, - "links": { - "endpoints": { - "details": "\/centreon\/api\/latest\/monitoring\/resources\/metaservices\/2", - "timeline": "\/centreon\/api\/latest\/monitoring\/metaservice\/2\/timeline", - "status_graph": "\/centreon\/api\/latest\/monitoring\/metaservices\/2\/metrics\/status", - "performance_graph": "\/centreon\/api\/latest\/monitoring\/metaservices\/2\/metrics\/performance", - "acknowledgement": "\/centreon\/api\/latest\/monitoring\/metaservices\/2\/acknowledgements?limit=1", - "downtime": "\/centreon\/api\/latest\/monitoring\/metaservices\/2\/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1716969848%7D,%22end_time%22:%7B%22%24gt%22:1716969848%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1716969848%7D%7D%7D%7D%5D%7D", - "check": null, - "forced_check": null, - "metrics": "\/centreon\/api\/latest\/monitoring\/metaservices\/2\/metrics" - }, - "uris": { - "configuration": null, - "logs": null, - "reporting": null - }, - "externals": { - "action_url": "", - "notes": { - "label": "", - "url": "" - } - } - } + "uris": { + "configuration": "/centreon/main.php?p=60201\u0026o=c\u0026service_id=24", + "logs": "/centreon/main.php?p=20301\u0026svc=14_24", + "reporting": "/centreon/main.php?p=30702\u0026period=yesterday\u0026start=\u0026end=\u0026host_id=14\u0026item=24" + }, + "externals": { + "action_url": "", + "notes": { + "label": "", + "url": "" + } + } + } + }, + { + "uuid": "h14-s25", + "duration": "13h 32m", + "last_check": "1m 50s", + "short_type": "s", + "id": 25, + "type": "service", + "name": "Memory", + "alias": null, + "fqdn": null, + "host_id": 14, + "service_id": 25, + "icon": null, + "monitoring_server_name": "Central", + "parent": { + "uuid": "h14", + "id": 14, + "name": "Centreon-Server", + "type": "host", + "short_type": "h", + "status": { + "code": 0, + "name": "UP", + "severity_code": 5 + }, + "alias": "Monitoring Server", + "fqdn": "127.0.0.1", + "monitoring_server_name": null + }, + "status": { + "code": 3, + "name": "UNKNOWN", + "severity_code": 3 + }, + "is_in_downtime": false, + "is_acknowledged": false, + "has_active_checks_enabled": true, + "has_passive_checks_enabled": false, + "last_status_change": "2024-01-21T22:31:27+01:00", + "tries": "3/3 (H)", + "information": "(Execute command failed)", + "performance_data": null, + "is_notification_enabled": false, + "severity": null, + "links": { + "endpoints": { + "details": "/centreon/api/latest/monitoring/resources/hosts/14/services/25", + "timeline": "/centreon/api/latest/monitoring/hosts/14/services/25/timeline", + "status_graph": "/centreon/api/latest/monitoring/hosts/14/services/25/metrics/status", + "performance_graph": null, + "acknowledgement": "/centreon/api/latest/monitoring/hosts/14/services/25/acknowledgements?limit=1", + "downtime": "/centreon/api/latest/monitoring/hosts/14/services/25/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", + "check": "/centreon/api/latest/monitoring/hosts/14/services/25/check", + "forced_check": "/centreon/api/latest/monitoring/hosts/14/services/25/check", + "metrics": "/centreon/api/latest/monitoring/hosts/14/services/25/metrics" + }, + "uris": { + "configuration": "/centreon/main.php?p=60201\u0026o=c\u0026service_id=25", + "logs": "/centreon/main.php?p=20301\u0026svc=14_25", + "reporting": "/centreon/main.php?p=30702\u0026period=yesterday\u0026start=\u0026end=\u0026host_id=14\u0026item=25" + }, + "externals": { + "action_url": "", + "notes": { + "label": "", + "url": "" + } + } + } + }, + { + "uuid": "h14-s26", + "duration": "13h 33m", + "last_check": "3m 5s", + "short_type": "s", + "id": 26, + "type": "service", + "name": "Ping", + "alias": null, + "fqdn": null, + "host_id": 14, + "service_id": 26, + "icon": null, + "monitoring_server_name": "Central", + "parent": { + "uuid": "h14", + "id": 14, + "name": "Centreon-Server", + "type": "host", + "short_type": "h", + "status": { + "code": 0, + "name": "UP", + "severity_code": 5 }, - { - "uuid": "m6", - "duration": "3M 3d", - "last_check": "14m 49s", - "short_type": "m", - "id": 6, - "type": "metaservice", - "name": "SA_Total_FW_Connexion", - "alias": null, - "fqdn": null, - "host_id": 1976, - "service_id": null, - "icon": null, - "monitoring_server_name": "Central", - "parent": null, - "status": { - "code": 0, - "name": "OK", - "severity_code": 5 - }, - "is_in_downtime": false, - "is_acknowledged": false, - "has_active_checks_enabled": true, - "has_passive_checks_enabled": false, - "last_status_change": "2024-02-24T14:35:17+01:00", - "tries": "1\/2 (H)", - "information": "OK: SA FW Connect number: 100", - "performance_data": null, - "is_notification_enabled": false, - "severity": null, - "links": { - "endpoints": { - "details": "\/centreon\/api\/latest\/monitoring\/resources\/metaservices\/6", - "timeline": "\/centreon\/api\/latest\/monitoring\/metaservice\/6\/timeline", - "status_graph": "\/centreon\/api\/latest\/monitoring\/metaservices\/6\/metrics\/status", - "performance_graph": "\/centreon\/api\/latest\/monitoring\/metaservices\/6\/metrics\/performance", - "acknowledgement": "\/centreon\/api\/latest\/monitoring\/metaservices\/6\/acknowledgements?limit=1", - "downtime": "\/centreon\/api\/latest\/monitoring\/metaservices\/6\/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1716969848%7D,%22end_time%22:%7B%22%24gt%22:1716969848%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1716969848%7D%7D%7D%7D%5D%7D", - "check": null, - "forced_check": null, - "metrics": "\/centreon\/api\/latest\/monitoring\/metaservices\/6\/metrics" - }, - "uris": { - "configuration": null, - "logs": null, - "reporting": null - }, - "externals": { - "action_url": "", - "notes": { - "label": "", - "url": "" - } - } - } + "alias": "Monitoring Server", + "fqdn": "127.0.0.1", + "monitoring_server_name": null + }, + "status": { + "code": 0, + "name": "OK", + "severity_code": 5 + }, + "is_in_downtime": false, + "is_acknowledged": false, + "has_active_checks_enabled": true, + "has_passive_checks_enabled": false, + "last_status_change": "2024-01-21T22:30:12+01:00", + "tries": "1/3 (H)", + "information": "OK - 127.0.0.1 rta 0.023ms lost 0%", + "performance_data": null, + "is_notification_enabled": false, + "severity": null, + "links": { + "endpoints": { + "details": "/centreon/api/latest/monitoring/resources/hosts/14/services/26", + "timeline": "/centreon/api/latest/monitoring/hosts/14/services/26/timeline", + "status_graph": "/centreon/api/latest/monitoring/hosts/14/services/26/metrics/status", + "performance_graph": "/centreon/api/latest/monitoring/hosts/14/services/26/metrics/performance", + "acknowledgement": "/centreon/api/latest/monitoring/hosts/14/services/26/acknowledgements?limit=1", + "downtime": "/centreon/api/latest/monitoring/hosts/14/services/26/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", + "check": "/centreon/api/latest/monitoring/hosts/14/services/26/check", + "forced_check": "/centreon/api/latest/monitoring/hosts/14/services/26/check", + "metrics": "/centreon/api/latest/monitoring/hosts/14/services/26/metrics" + }, + "uris": { + "configuration": "/centreon/main.php?p=60201\u0026o=c\u0026service_id=26", + "logs": "/centreon/main.php?p=20301\u0026svc=14_26", + "reporting": "/centreon/main.php?p=30702\u0026period=yesterday\u0026start=\u0026end=\u0026host_id=14\u0026item=26" + }, + "externals": { + "action_url": "", + "notes": { + "label": "", + "url": "" + } + } + } + }, + { + "uuid": "h14", + "duration": "13h 33m", + "last_check": "4m 20s", + "short_type": "h", + "id": 14, + "type": "host", + "name": "Centreon-Server", + "alias": "Monitoring Server", + "fqdn": "127.0.0.1", + "host_id": 14, + "service_id": null, + "icon": null, + "monitoring_server_name": "Central", + "parent": null, + "status": { + "code": 0, + "name": "UP", + "severity_code": 5 + }, + "is_in_downtime": false, + "is_acknowledged": false, + "has_active_checks_enabled": true, + "has_passive_checks_enabled": false, + "last_status_change": "2024-01-21T22:30:12+01:00", + "tries": "1/5 (H)", + "information": "OK - 127.0.0.1 rta 0.051ms lost 0%", + "performance_data": null, + "is_notification_enabled": false, + "severity": null, + "links": { + "endpoints": { + "details": "/centreon/api/latest/monitoring/resources/hosts/14", + "timeline": "/centreon/api/latest/monitoring/hosts/14/timeline", + "status_graph": null, + "performance_graph": null, + "acknowledgement": "/centreon/api/latest/monitoring/hosts/14/acknowledgements?limit=1", + "downtime": "/centreon/api/latest/monitoring/hosts/14/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1705921421%7D,%22end_time%22:%7B%22%24gt%22:1705921421%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1705921421%7D%7D%7D%7D%5D%7D", + "check": "/centreon/api/latest/monitoring/hosts/14/check", + "forced_check": "/centreon/api/latest/monitoring/hosts/14/check", + "metrics": null + }, + "uris": { + "configuration": "/centreon/main.php?p=60101\u0026o=c\u0026host_id=14", + "logs": "/centreon/main.php?p=20301\u0026h=14", + "reporting": "/centreon/main.php?p=307\u0026host=14" + }, + "externals": { + "action_url": "", + "notes": { + "label": "", + "url": "" + } } - ], - "meta": { - "page": 1, - "limit": 30, - "search": { - "$and": [] + } + }, + { + "uuid": "m2", + "duration": "1M 1w", + "last_check": "14m 55s", + "short_type": "m", + "id": 2, + "type": "metaservice", + "name": "AS_Total_FW_Connexion", + "alias": null, + "fqdn": null, + "host_id": 1972, + "service_id": null, + "icon": null, + "monitoring_server_name": "Central", + "parent": null, + "status": { + "code": 0, + "name": "OK", + "severity_code": 5 + }, + "is_in_downtime": false, + "is_acknowledged": false, + "has_active_checks_enabled": true, + "has_passive_checks_enabled": false, + "last_status_change": "2024-04-21T13:43:05+02:00", + "tries": "1/2 (H)", + "information": "OK: AS FW Connect number: 200", + "performance_data": null, + "is_notification_enabled": false, + "severity": null, + "links": { + "endpoints": { + "details": "/centreon/api/latest/monitoring/resources/metaservices/2", + "timeline": "/centreon/api/latest/monitoring/metaservice/2/timeline", + "status_graph": "/centreon/api/latest/monitoring/metaservices/2/metrics/status", + "performance_graph": "/centreon/api/latest/monitoring/metaservices/2/metrics/performance", + "acknowledgement": "/centreon/api/latest/monitoring/metaservices/2/acknowledgements?limit=1", + "downtime": "/centreon/api/latest/monitoring/metaservices/2/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1716969848%7D,%22end_time%22:%7B%22%24gt%22:1716969848%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1716969848%7D%7D%7D%7D%5D%7D", + "check": null, + "forced_check": null, + "metrics": "/centreon/api/latest/monitoring/metaservices/2/metrics" }, - "sort_by": { - "last_status_change": "DESC" + "uris": { + "configuration": null, + "logs": null, + "reporting": null }, - "total": 5 + "externals": { + "action_url": "", + "notes": { + "label": "", + "url": "" + } + } + } + }, + { + "uuid": "m6", + "duration": "3M 3d", + "last_check": "14m 49s", + "extra": { + "open_tickets": { + "tickets": { + "id": 1, + "subject": "description", + "created_at": "2024-02-24T14:35:17+01:00" + } + } + }, + "short_type": "m", + "id": 6, + "type": "metaservice", + "name": "SA_Total_FW_Connexion", + "alias": null, + "fqdn": null, + "host_id": 1976, + "service_id": null, + "icon": null, + "monitoring_server_name": "Central", + "parent": null, + "status": { + "code": 0, + "name": "OK", + "severity_code": 5 + }, + "is_in_downtime": false, + "is_acknowledged": false, + "has_active_checks_enabled": true, + "has_passive_checks_enabled": false, + "last_status_change": "2024-02-24T14:35:17+01:00", + "tries": "1/2 (H)", + "information": "OK: SA FW Connect number: 100", + "performance_data": null, + "is_notification_enabled": false, + "severity": null, + "links": { + "endpoints": { + "details": "/centreon/api/latest/monitoring/resources/metaservices/6", + "timeline": "/centreon/api/latest/monitoring/metaservice/6/timeline", + "status_graph": "/centreon/api/latest/monitoring/metaservices/6/metrics/status", + "performance_graph": "/centreon/api/latest/monitoring/metaservices/6/metrics/performance", + "acknowledgement": "/centreon/api/latest/monitoring/metaservices/6/acknowledgements?limit=1", + "downtime": "/centreon/api/latest/monitoring/metaservices/6/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1716969848%7D,%22end_time%22:%7B%22%24gt%22:1716969848%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1716969848%7D%7D%7D%7D%5D%7D", + "check": null, + "forced_check": null, + "metrics": "/centreon/api/latest/monitoring/metaservices/6/metrics" + }, + "uris": { + "configuration": null, + "logs": null, + "reporting": null + }, + "externals": { + "action_url": "", + "notes": { + "label": "", + "url": "" + } + } + } } -} \ No newline at end of file + ], + "meta": { + "page": 1, + "limit": 30, + "search": { + "$and": [] + }, + "sort_by": { + "last_status_change": "DESC" + }, + "total": 5 + } +} diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/bamCondensed.json b/centreon/cypress/fixtures/Widgets/StatusGrid/bamCondensed.json new file mode 100644 index 0000000000..3e4e1d7dee --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/bamCondensed.json @@ -0,0 +1,18 @@ +{ + "ok":{ + "total":22 + }, + "warning":{ + "total":3 + }, + "critical":{ + "total":10 + }, + "unknown":{ + "total":1 + }, + "pending":{ + "total":4 + }, + "total":40 + } \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/booleanRuleDetails.json b/centreon/cypress/fixtures/Widgets/StatusGrid/booleanRuleDetails.json new file mode 100644 index 0000000000..e19f33f553 --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/booleanRuleDetails.json @@ -0,0 +1,11 @@ +{ + "id":1, + "name":"boolean 1", + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "is_impacting_when_expression_true":true, + "expression_status":false +} \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/businessActivities.json b/centreon/cypress/fixtures/Widgets/StatusGrid/businessActivities.json new file mode 100644 index 0000000000..6c78b51b39 --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/businessActivities.json @@ -0,0 +1,109 @@ +{ + "result":[ + { + "id":1, + "name":"ba1", + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "business_views":[ + { + "id":1, + "name":"bv1" + } + ] + }, + { + "id":2, + "name":"ba2", + "status":{ + "code":4, + "name":"PENDING", + "severity_code":4 + }, + "business_views":[ + { + "id":1, + "name":"bv1" + } + ] + }, + { + "id":3, + "name":"ba3", + "status":{ + "code":2, + "name":"Unknown", + "severity_code":3 + }, + "business_views":[ + { + "id":1, + "name":"bv1" + } + ] + }, + { + "id":4, + "name":"ba4", + "status":{ + "code":4, + "name":"Critical", + "severity_code":1 + }, + "business_views":[ + { + "id":1, + "name":"bv1" + } + ] + }, + { + "id":5, + "name":"ba5", + "status":{ + "code":4, + "name":"Critical", + "severity_code":1 + }, + "business_views":[ + { + "id":1, + "name":"bv1" + } + ] + } + ], + "meta":{ + "page":1, + "limit":100, + "search":{ + "$and":[ + { + "business_view.name":{ + "$in":[ + "bv1" + ] + } + }, + { + "status":{ + "$in":[ + "CRITICAL", + "WARNING", + "PENDING", + "OK", + "UNKNOWN" + ] + } + } + ] + }, + "sort_by":{ + "status":"DESC" + }, + "total":2 + } + } \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/criticalImpactBA.json b/centreon/cypress/fixtures/Widgets/StatusGrid/criticalImpactBA.json new file mode 100644 index 0000000000..65f54a5ada --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/criticalImpactBA.json @@ -0,0 +1,82 @@ +{ + "id":4, + "name":"ba4", + "status":{ + "name":"UNKNOWN", + "code":3, + "severity_code":3 + }, + "infrastructure_view":null, + "calculation_method":{ + "id":0, + "name":"Impact", + "warning_threshold":80, + "critical_threshold":70, + "is_percentage":true + }, + "indicators":[ + { + "id":10, + "type":"boolean-rule", + "name":"boolean 1", + "impact":{ + "warning":75, + "critical":100, + "unknown":5 + }, + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "resource":{ + "id":1, + "name":"boolean 1", + "parent_id":null, + "parent_name":null + } + }, + { + "id":9, + "type":"service", + "name":"Ping", + "impact":{ + "warning":12, + "critical":15, + "unknown":1 + }, + "status":{ + "code":0, + "name":"CRITICAL", + "severity_code":1 + }, + "resource":{ + "id":26, + "name":"Ping", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":4, + "type":"boolean-rule", + "name":"boolean 2", + "impact":{ + "warning":75, + "critical":100, + "unknown":5 + }, + "status":{ + "code":0, + "name":"CRITICAL", + "severity_code":1 + }, + "resource":{ + "id":1, + "name":"boolean 2", + "parent_id":null, + "parent_name":null + } + } + ] + } \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/criticalRatioBA.json b/centreon/cypress/fixtures/Widgets/StatusGrid/criticalRatioBA.json new file mode 100644 index 0000000000..75534c9fe0 --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/criticalRatioBA.json @@ -0,0 +1,70 @@ +{ + "id":3, + "name":"ba5", + "status":{ + "name":"CRITICAL", + "code":0, + "severity_code":1 + }, + "infrastructure_view":null, + "calculation_method":{ + "id":3, + "name":"Ratio", + "warning_threshold":75, + "critical_threshold":80, + "is_percentage":true + }, + "indicators":[ + { + "id":6, + "type":"service", + "name":"Ping", + "impact":null, + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "resource":{ + "id":26, + "name":"Ping", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":7, + "type":"service", + "name":"Load", + "impact":null, + "status":{ + "code":3, + "name":"UNKNOWN", + "severity_code":3 + }, + "resource":{ + "id":24, + "name":"Load", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":8, + "type":"business-activity", + "name":"ba1", + "impact":null, + "status":{ + "code":4, + "name":"WARNING", + "severity_code":1 + }, + "resource":{ + "id":5, + "name":"ba5", + "parent_id":null, + "parent_name":null + } + } + ] + } \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/impactBA.json b/centreon/cypress/fixtures/Widgets/StatusGrid/impactBA.json new file mode 100644 index 0000000000..a23476370c --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/impactBA.json @@ -0,0 +1,61 @@ +{ + "id":1, + "name":"ba4", + "status":{ + "name":"UNKNOWN", + "code":3, + "severity_code":3 + }, + "infrastructure_view":null, + "calculation_method":{ + "id":0, + "name":"Impact", + "warning_threshold":80, + "critical_threshold":70, + "is_percentage":true + }, + "indicators":[ + { + "id":10, + "type":"boolean-rule", + "name":"boolean 1", + "impact":{ + "warning":75, + "critical":100, + "unknown":5 + }, + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "resource":{ + "id":1, + "name":"boolean 1", + "parent_id":null, + "parent_name":null + } + }, + { + "id":9, + "type":"service", + "name":"Ping", + "impact":{ + "warning":12, + "critical":15, + "unknown":1 + }, + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "resource":{ + "id":26, + "name":"Ping", + "parent_id":14, + "parent_name":"Centreon-Server" + } + } + ] + } \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/indicators.json b/centreon/cypress/fixtures/Widgets/StatusGrid/indicators.json new file mode 100644 index 0000000000..5d45ab03dc --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/indicators.json @@ -0,0 +1,91 @@ +{ + "result":[ + { + "id":2, + "type":"service", + "name":"Memory", + "status":{ + "code":3, + "name":"UNKNOWN", + "severity_code":3 + }, + "business_activity":{ + "id":1, + "name":"ba1" + }, + "resource":{ + "id":25, + "name":"Memory", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":1, + "type":"service", + "name":"Ping", + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "business_activity":{ + "id":1, + "name":"ba1" + }, + "resource":{ + "id":26, + "name":"Ping", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":3, + "type":"boolean-rule", + "name":"boolean 1", + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "business_activity":{ + "id":1, + "name":"ba1" + }, + "resource":{ + "id":1 + } + } + ], + "meta":{ + "page":1, + "limit":100, + "search":{ + "$and":[ + { + "business_activity.name":{ + "$in":[ + "ba1" + ] + } + }, + { + "status":{ + "$in":[ + "CRITICAL", + "WARNING", + "PENDING", + "OK", + "UNKNOWN" + ] + } + } + ] + }, + "sort_by":{ + "status":"DESC" + }, + "total":5 + } + } \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/ratioBA.json b/centreon/cypress/fixtures/Widgets/StatusGrid/ratioBA.json new file mode 100644 index 0000000000..8de97961c4 --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/ratioBA.json @@ -0,0 +1,70 @@ +{ + "id":3, + "name":"ba3", + "status":{ + "name":"UNKNOWN", + "code":3, + "severity_code":3 + }, + "infrastructure_view":null, + "calculation_method":{ + "id":3, + "name":"Ratio", + "warning_threshold":75, + "critical_threshold":80, + "is_percentage":true + }, + "indicators":[ + { + "id":6, + "type":"service", + "name":"Ping", + "impact":null, + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "resource":{ + "id":26, + "name":"Ping", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":7, + "type":"service", + "name":"Load", + "impact":null, + "status":{ + "code":3, + "name":"UNKNOWN", + "severity_code":3 + }, + "resource":{ + "id":24, + "name":"Load", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":8, + "type":"business-activity", + "name":"ba1", + "impact":null, + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "resource":{ + "id":1, + "name":"ba1", + "parent_id":null, + "parent_name":null + } + } + ] + } \ No newline at end of file diff --git a/centreon/cypress/fixtures/Widgets/StatusGrid/worstStatusBA.json b/centreon/cypress/fixtures/Widgets/StatusGrid/worstStatusBA.json new file mode 100644 index 0000000000..f8b1674d69 --- /dev/null +++ b/centreon/cypress/fixtures/Widgets/StatusGrid/worstStatusBA.json @@ -0,0 +1,70 @@ +{ + "id":1, + "name":"ba1", + "status":{ + "name":"UNKNOWN", + "code":3, + "severity_code":3 + }, + "infrastructure_view":null, + "calculation_method":{ + "id":2, + "name":"Worst Status", + "warning_threshold":null, + "critical_threshold":null, + "is_percentage":false + }, + "indicators":[ + { + "id":1, + "type":"service", + "name":"Ping", + "impact":null, + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "resource":{ + "id":26, + "name":"Ping", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":2, + "type":"service", + "name":"Memory", + "impact":null, + "status":{ + "code":3, + "name":"UNKNOWN", + "severity_code":3 + }, + "resource":{ + "id":25, + "name":"Memory", + "parent_id":14, + "parent_name":"Centreon-Server" + } + }, + { + "id":5, + "type":"boolean-rule", + "name":"boolean 1", + "impact":null, + "status":{ + "code":0, + "name":"OK", + "severity_code":5 + }, + "resource":{ + "id":1, + "name":"boolean 1", + "parent_id":null, + "parent_name":null + } + } + ] + } \ No newline at end of file diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- clears filters and the search bar, and sends a listing request with empty search parameter when the clear button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- clears filters and the search bar, and sends a listing request with empty search parameter when the clear button is clicked.snap.png new file mode 100644 index 0000000000..545c912ec8 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- clears filters and the search bar, and sends a listing request with empty search parameter when the clear button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- displays the advanced filters component when the corresponding icon is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- displays the advanced filters component when the corresponding icon is clicked.snap.png new file mode 100644 index 0000000000..2f5da6e81c Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- displays the advanced filters component when the corresponding icon is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- displays the search bar component.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- displays the search bar component.snap.png new file mode 100644 index 0000000000..c4dc13f0ae Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- displays the search bar component.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- updates the search bar with the value from the filters.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- updates the search bar with the value from the filters.snap.png new file mode 100644 index 0000000000..b14b9ef07f Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Filters -- updates the search bar with the value from the filters.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Listing -- deletes an ACC when the Delete button is clicked and the confirmation button is triggered.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Listing -- deletes an ACC when the Delete button is clicked and the confirmation button is triggered.snap.png new file mode 100644 index 0000000000..d392087ae2 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Listing -- deletes an ACC when the Delete button is clicked and the confirmation button is triggered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Listing -- displays the first page of the ACC listing.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Listing -- displays the first page of the ACC listing.snap.png new file mode 100644 index 0000000000..6ef05a18c6 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Listing -- displays the first page of the ACC listing.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- API requests -- sends a Post request when the Modal is in Creation Mode and the Create Button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- API requests -- sends a Post request when the Modal is in Creation Mode and the Create Button is clicked.snap.png new file mode 100644 index 0000000000..b04e9a6209 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- API requests -- sends a Post request when the Modal is in Creation Mode and the Create Button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- API requests -- sends an Update request when the Modal is in Edition Mode and the Update Button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- API requests -- sends an Update request when the Modal is in Edition Mode and the Update Button is clicked.snap.png new file mode 100644 index 0000000000..bc8cb2b8ad Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- API requests -- sends an Update request when the Modal is in Edition Mode and the Update Button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that at least one poller is required.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that at least one poller is required.snap.png new file mode 100644 index 0000000000..3c6807d6a7 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that at least one poller is required.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that name length must be between 3 and 50 characters.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that name length must be between 3 and 50 characters.snap.png new file mode 100644 index 0000000000..272ff7be1f Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that name length must be between 3 and 50 characters.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that port field is required.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that port field is required.snap.png new file mode 100644 index 0000000000..0557d4da2c Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that port field is required.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that the port should be a valid integer.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that the port should be a valid integer.snap.png new file mode 100644 index 0000000000..ccbfd7dd42 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that the port should be a valid integer.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that the port should be between 0 and 65535.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that the port should be between 0 and 65535.snap.png new file mode 100644 index 0000000000..f339cb9961 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that the port should be between 0 and 65535.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter URL field is required.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter URL field is required.snap.png new file mode 100644 index 0000000000..d7135aeed9 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter URL field is required.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter name field is required.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter name field is required.snap.png new file mode 100644 index 0000000000..dfa8d51074 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter name field is required.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter name must be unique for its own ACC.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter name must be unique for its own ACC.snap.png new file mode 100644 index 0000000000..b7e66ab935 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter name must be unique for its own ACC.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter password field is not required in Edition Mode.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter password field is not required in Edition Mode.snap.png new file mode 100644 index 0000000000..125e04a80f Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter password field is not required in Edition Mode.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter password field is required in Creation Mode.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter password field is required in Creation Mode.snap.png new file mode 100644 index 0000000000..e31dcae582 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter password field is required in Creation Mode.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter username is not required Edition Mode.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter username is not required Edition Mode.snap.png new file mode 100644 index 0000000000..74291d7ce1 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter username is not required Edition Mode.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter username is required in Creation Mode.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter username is required in Creation Mode.snap.png new file mode 100644 index 0000000000..e31dcae582 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- Form validation -- validates that vCenter username is required in Creation Mode.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- adds a new parameter group when Add vCenter ESX button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- adds a new parameter group when Add vCenter ESX button is clicked.snap.png new file mode 100644 index 0000000000..211b436bb3 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- adds a new parameter group when Add vCenter ESX button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- disables the update button when no change has been made to the modal form.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- disables the update button when no change has been made to the modal form.snap.png new file mode 100644 index 0000000000..13a46ef2cd Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- disables the update button when no change has been made to the modal form.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- displays form fields with the selected ACC values when the Modal is opened in Edition Mode.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- displays form fields with the selected ACC values when the Modal is opened in Edition Mode.snap.png new file mode 100644 index 0000000000..8918e21471 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- displays form fields with the selected ACC values when the Modal is opened in Edition Mode.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- enables the create button when all mandatory fields are filled.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- enables the create button when all mandatory fields are filled.snap.png new file mode 100644 index 0000000000..fc74087c78 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Modal -- enables the create button when all mandatory fields are filled.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- displays listing, filters and action buttons.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- displays listing, filters and action buttons.snap.png new file mode 100644 index 0000000000..93a3085822 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- displays listing, filters and action buttons.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- opens the modal in Creation Mode when Add button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- opens the modal in Creation Mode when Add button is clicked.snap.png new file mode 100644 index 0000000000..6e3e5e6462 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- opens the modal in Creation Mode when Add button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- opens the modal in Edition Mode when a row of the listing is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- opens the modal in Edition Mode when a row of the listing is clicked.snap.png new file mode 100644 index 0000000000..80771bff67 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/Additional Connctor Configuration -- Page -- opens the modal in Edition Mode when a row of the listing is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Creation date column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Creation date column is clicked.snap.png new file mode 100644 index 0000000000..20d27c669c Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Creation date column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Creator column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Creator column is clicked.snap.png new file mode 100644 index 0000000000..845c95f5cf Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Creator column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Last update column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Last update column is clicked.snap.png new file mode 100644 index 0000000000..f4e73135f4 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Last update column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Name column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Name column is clicked.snap.png new file mode 100644 index 0000000000..223efca5a2 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Name column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Type column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Type column is clicked.snap.png new file mode 100644 index 0000000000..abbfdf1fef Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Type column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Updated by column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Updated by column is clicked.snap.png new file mode 100644 index 0000000000..2509b31d38 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/column sorting -- executes a listing request when the Updated by column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_0.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_0.snap.png new file mode 100644 index 0000000000..344ed7eb4e Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_0.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_1.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_1.snap.png new file mode 100644 index 0000000000..976a07e9bb Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_1.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_2.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_2.snap.png new file mode 100644 index 0000000000..303b41938b Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/invalide_url_2.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_0.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_0.snap.png new file mode 100644 index 0000000000..5cede655be Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_0.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_1.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_1.snap.png new file mode 100644 index 0000000000..428a94e204 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_1.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_2.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_2.snap.png new file mode 100644 index 0000000000..714043a53a Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/AdditionalConnectorConfiguration/Specs/ACC.cypress.spec.tsx/valide_url_2.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- confirms that the Close button triggers the display of a confirmation dialog if the user has made some changes to the form.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- confirms that the Close button triggers the display of a confirmation dialog if the user has made some changes to the form.snap.png index bc317afd05..6f4bbcbbf3 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- confirms that the Close button triggers the display of a confirmation dialog if the user has made some changes to the form.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- confirms that the Close button triggers the display of a confirmation dialog if the user has made some changes to the form.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- confirms that the Save button is correctly activated when all required fields are filled, and the form is error-free, allowing the user to save the form data.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- confirms that the Save button is correctly activated when all required fields are filled, and the form is error-free, allowing the user to save the form data.snap.png index 92157caf92..54faeecaaa 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- confirms that the Save button is correctly activated when all required fields are filled, and the form is error-free, allowing the user to save the form data.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- confirms that the Save button is correctly activated when all required fields are filled, and the form is error-free, allowing the user to save the form data.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the Email Body field with the default initial value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the Email Body field with the default initial value.snap.png index 52048b2ca1..b3cb688bfa 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the Email Body field with the default initial value.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the Email Body field with the default initial value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the Email Subject field with the default initial value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the Email Subject field with the default initial value.snap.png index a071b09c57..b3cb688bfa 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the Email Subject field with the default initial value.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the Email Subject field with the default initial value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the form.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the form.snap.png index c45ceab092..f15333bb52 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the form.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- displays the form.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- sends a request to add a new notification with the form values when the Confirm button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- sends a request to add a new notification with the form values when the Confirm button is clicked.snap.png index 4738383985..dea37414a4 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- sends a request to add a new notification with the form values when the Confirm button is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel -- sends a request to add a new notification with the form values when the Confirm button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel Business Views -- dispalys the businessViews field when the BAM module is installed.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel Business Views -- dispalys the businessViews field when the BAM module is installed.snap.png index 896412caa9..c9d4398a58 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel Business Views -- dispalys the businessViews field when the BAM module is installed.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelCreate.cypress.spec.tsx/Create Panel Business Views -- dispalys the businessViews field when the BAM module is installed.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Confirm Dialog -- confirms that the Confirm button triggers the sending of a PUT request.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Confirm Dialog -- confirms that the Confirm button triggers the sending of a PUT request.snap.png index 4824cda634..268fbbccbc 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Confirm Dialog -- confirms that the Confirm button triggers the sending of a PUT request.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Confirm Dialog -- confirms that the Confirm button triggers the sending of a PUT request.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Expand/Collapse button triggers the desired expansion or collapse of the panel, providing users with the ability to control its visibility and size.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Expand/Collapse button triggers the desired expansion or collapse of the panel, providing users with the ability to control its visibility and size.snap.png index f318564d37..df774db0a3 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Expand/Collapse button triggers the desired expansion or collapse of the panel, providing users with the ability to control its visibility and size.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Expand/Collapse button triggers the desired expansion or collapse of the panel, providing users with the ability to control its visibility and size.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Include Services checkbox controls the enabling and checking of all host group services checkboxes.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Include Services checkbox controls the enabling and checking of all host group services checkboxes.snap.png index eb560a8cd3..b29ba28381 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Include Services checkbox controls the enabling and checking of all host group services checkboxes.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Include Services checkbox controls the enabling and checking of all host group services checkboxes.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Message field is properly rendered with the edited notification message.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Message field is properly rendered with the edited notification message.snap.png index 12c7366c75..9a535e693d 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Message field is properly rendered with the edited notification message.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Message field is properly rendered with the edited notification message.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Save button responds to field changes correctly, becoming enabled when a modification occurs and the form is error-free.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Save button responds to field changes correctly, becoming enabled when a modification occurs and the form is error-free.snap.png index 69777cb261..9287f21f31 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Save button responds to field changes correctly, becoming enabled when a modification occurs and the form is error-free.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Save button responds to field changes correctly, becoming enabled when a modification occurs and the form is error-free.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Subject field is properly rendered with the edited notification subject.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Subject field is properly rendered with the edited notification subject.snap.png index a710a5963e..517b8c3f7b 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Subject field is properly rendered with the edited notification subject.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the Subject field is properly rendered with the edited notification subject.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the notification name is properly rendered with the edited value and supports the capability for users to modify the name by interacting with the Edit icon.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the notification name is properly rendered with the edited value and supports the capability for users to modify the name by interacting with the Edit icon.snap.png index 34c43471c8..4b372a2c4a 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the notification name is properly rendered with the edited value and supports the capability for users to modify the name by interacting with the Edit icon.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the notification name is properly rendered with the edited value and supports the capability for users to modify the name by interacting with the Edit icon.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the three icons for notification channels are appropriately presented, with the email icon initially selected and the other icons disabled.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the three icons for notification channels are appropriately presented, with the email icon initially selected and the other icons disabled.snap.png index 6c6b84f4bf..4e4e1ed158 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the three icons for notification channels are appropriately presented, with the email icon initially selected and the other icons disabled.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- confirms that the three icons for notification channels are appropriately presented, with the email icon initially selected and the other icons disabled.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays host group resources and events with the edited notification values.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays host group resources and events with the edited notification values.snap.png index 7be2527f44..2fac6c84c2 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays host group resources and events with the edited notification values.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays host group resources and events with the edited notification values.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays service groups and events fields with the edited notification values.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays service groups and events fields with the edited notification values.snap.png index e230842cac..0d8d38da76 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays service groups and events fields with the edited notification values.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays service groups and events fields with the edited notification values.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays the Contacts field with edited notification contacts.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays the Contacts field with edited notification contacts.snap.png index fa33ff3351..38d5f00abe 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays the Contacts field with edited notification contacts.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- displays the Contacts field with edited notification contacts.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the Include Services field presents the value of the edited notification.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the Include Services field presents the value of the edited notification.snap.png index 7be2527f44..2fac6c84c2 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the Include Services field presents the value of the edited notification.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the Include Services field presents the value of the edited notification.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the Save button's initial state is set to disabled.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the Save button's initial state is set to disabled.snap.png index 7be2527f44..0d8d38da76 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the Save button's initial state is set to disabled.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the Save button's initial state is set to disabled.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the form handles an empty name field correctly by showing an error message and disabling the Save button as a validation measure.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the form handles an empty name field correctly by showing an error message and disabling the Save button as a validation measure.snap.png index 342c93723f..c730cb9cbe 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the form handles an empty name field correctly by showing an error message and disabling the Save button as a validation measure.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the form handles an empty name field correctly by showing an error message and disabling the Save button as a validation measure.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the form handles an existing name field correctly by showing an error message and disabling the Save button as a validation measure.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the form handles an existing name field correctly by showing an error message and disabling the Save button as a validation measure.snap.png index 0ec2c7e09b..6328476b13 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the form handles an existing name field correctly by showing an error message and disabling the Save button as a validation measure.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the form handles an existing name field correctly by showing an error message and disabling the Save button as a validation measure.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the header section displays all the expected actions.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the header section displays all the expected actions.snap.png index 0b969555d1..0d8d38da76 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the header section displays all the expected actions.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that the header section displays all the expected actions.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that when the Host Groups field is empty, all event checkboxes are unchecked and the Include Services field is not visible.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that when the Host Groups field is empty, all event checkboxes are unchecked and the Include Services field is not visible.snap.png index 2f7e0e25ee..19dc865724 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that when the Host Groups field is empty, all event checkboxes are unchecked and the Include Services field is not visible.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that when the Host Groups field is empty, all event checkboxes are unchecked and the Include Services field is not visible.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that when the Service Groups field is empty, all associated events are disabled and unchecked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that when the Service Groups field is empty, all associated events are disabled and unchecked.snap.png index 8fd6701b6d..3dd57400c9 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that when the Service Groups field is empty, all associated events are disabled and unchecked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- ensures that when the Service Groups field is empty, all associated events are disabled and unchecked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when both resource fields are empty, the user interface responds by displaying an error message and disabling the Save button.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when both resource fields are empty, the user interface responds by displaying an error message and disabling the Save button.snap.png index 5dc302f748..bbd8dee13d 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when both resource fields are empty, the user interface responds by displaying an error message and disabling the Save button.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when both resource fields are empty, the user interface responds by displaying an error message and disabling the Save button.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Contacts field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Contacts field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png index 150277d335..1726e39f1e 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Contacts field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Contacts field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Message field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Message field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png index 16ab8aafc6..6710140f29 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Message field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Message field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Subject field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Subject field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png index d2d112bbc4..ab061247e8 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Subject field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Subject field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Time period field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Time period field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png new file mode 100644 index 0000000000..40f9294fc8 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel -- validates that when the Time period field is empty, the user interface responds by displaying an error message and disabling the Save button.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- displays Business Views and their events with the edited notification values.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- displays Business Views and their events with the edited notification values.snap.png index bb6548b059..df87428a70 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- displays Business Views and their events with the edited notification values.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- displays Business Views and their events with the edited notification values.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- ensures that when the BA field is empty, all associated events are disabled and unchecked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- ensures that when the BA field is empty, all associated events are disabled and unchecked.snap.png index d17022b789..7dd7968d17 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- ensures that when the BA field is empty, all associated events are disabled and unchecked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- ensures that when the BA field is empty, all associated events are disabled and unchecked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- validates that when all resource fields are empty, the user interface responds by displaying an error message and disabling the Save button.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- validates that when all resource fields are empty, the user interface responds by displaying an error message and disabling the Save button.snap.png index 814f8b5518..5127b5c473 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- validates that when all resource fields are empty, the user interface responds by displaying an error message and disabling the Save button.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Business Views -- validates that when all resource fields are empty, the user interface responds by displaying an error message and disabling the Save button.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Delete button -- displays a confirmation dialog containing the notification name upon clicking the Delete button.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Delete button -- displays a confirmation dialog containing the notification name upon clicking the Delete button.snap.png index e230842cac..e235ba491a 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Delete button -- displays a confirmation dialog containing the notification name upon clicking the Delete button.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Delete button -- displays a confirmation dialog containing the notification name upon clicking the Delete button.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Delete button -- displays a success message after successful deletion.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Delete button -- displays a success message after successful deletion.snap.png index ffec74da32..971041a190 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Delete button -- displays a success message after successful deletion.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/CloudNotificationsConfiguration/Panel/specs/PanelEdit.cypress.spec.tsx/Edit Panel Delete button -- displays a success message after successful deletion.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- deletes a selected option on multi autocomplete when the corresponding button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- deletes a selected option on multi autocomplete when the corresponding button is clicked.snap.png new file mode 100644 index 0000000000..48f6af2bed Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- deletes a selected option on multi autocomplete when the corresponding button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- disables the autocomplete when the does have the right to edit it.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- disables the autocomplete when the does have the right to edit it.snap.png new file mode 100644 index 0000000000..0851ef5f3f Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- disables the autocomplete when the does have the right to edit it.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays a single autocomplete and selects a value when an options is chosen.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays a single autocomplete and selects a value when an options is chosen.snap.png new file mode 100644 index 0000000000..df43cf64a1 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays a single autocomplete and selects a value when an options is chosen.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays the multi autocomplete and select values when options are chosen.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays the multi autocomplete and select values when options are chosen.snap.png new file mode 100644 index 0000000000..452fd4385a Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays the multi autocomplete and select values when options are chosen.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays the title in group mode when a prop is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays the title in group mode when a prop is set.snap.png new file mode 100644 index 0000000000..a01e13585d Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Autocomplete/ConnectedAutocomplete.cypress.spec.tsx/Widget connected autocomplete -- displays the title in group mode when a prop is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays default color when any color was previously selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays default color when any color was previously selected.snap.png new file mode 100644 index 0000000000..055800640e Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays default color when any color was previously selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays the color selector as disabled when user does not have the right to edit the field.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays the color selector as disabled when user does not have the right to edit the field.snap.png new file mode 100644 index 0000000000..055800640e Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays the color selector as disabled when user does not have the right to edit the field.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays the color selector in a group when a props is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays the color selector in a group when a props is set.snap.png new file mode 100644 index 0000000000..888a1cf172 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- displays the color selector in a group when a props is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- selects another color when a color is selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- selects another color when a color is selected.snap.png new file mode 100644 index 0000000000..e22cf0a008 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Color/ColorSelector.cypress.spec.tsx/Color selector -- selects another color when a color is selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- display the picker is disabled when the user cannot edit.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- display the picker is disabled when the user cannot edit.snap.png new file mode 100644 index 0000000000..5adae9cc3c Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- display the picker is disabled when the user cannot edit.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- displays a date time with a pre-selected date time.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- displays a date time with a pre-selected date time.snap.png new file mode 100644 index 0000000000..2c1754d4b6 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- displays a date time with a pre-selected date time.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- selects date time when the picker is opened and a date time is picked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- selects date time when the picker is opened and a date time is picked.snap.png new file mode 100644 index 0000000000..d8e5b7f417 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/DatePicker/DatePick.cypress.spec.tsx/DatePicker -- selects date time when the picker is opened and a date time is picked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- disables the metrics selector when resources are not correctly fullfilled.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- disables the metrics selector when resources are not correctly fullfilled.snap.png index b485a65a1e..f75c96d933 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- disables the metrics selector when resources are not correctly fullfilled.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- disables the metrics selector when resources are not correctly fullfilled.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- displays a message when there are too many metrics to retrieve.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- displays a message when there are too many metrics to retrieve.snap.png index c55302dd86..09ba72aaa6 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- displays a message when there are too many metrics to retrieve.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- displays a message when there are too many metrics to retrieve.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- displays the number of metric available.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- displays the number of metric available.snap.png index 977996e137..5712833008 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- displays the number of metric available.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Metric header -- displays the number of metric available.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Multiple metrics selection with several resources -- displays metrics with other units as disabled when the maximum of units are selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Multiple metrics selection with several resources -- displays metrics with other units as disabled when the maximum of units are selected.snap.png index c77f90b268..0cac4320a9 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Multiple metrics selection with several resources -- displays metrics with other units as disabled when the maximum of units are selected.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Multiple metrics selection with several resources -- displays metrics with other units as disabled when the maximum of units are selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- displays a warning message when a metric with several resources is selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- displays a warning message when a metric with several resources is selected.snap.png index bb38de4f92..9f4d4f15ae 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- displays a warning message when a metric with several resources is selected.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- displays a warning message when a metric with several resources is selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- displays the retrieved metrics.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- displays the retrieved metrics.snap.png index 563eec5403..7f3e0c3ad2 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- displays the retrieved metrics.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- displays the retrieved metrics.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- selects a metric when metrics are retrieved and a metric name is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- selects a metric when metrics are retrieved and a metric name is clicked.snap.png index bb38de4f92..9f4d4f15ae 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- selects a metric when metrics are retrieved and a metric name is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Metrics/Metrics.cypress.spec.tsx/Metrics -- Single metric selection with single resource -- selects a metric when metrics are retrieved and a metric name is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Resources/Resources.cypress.spec.tsx/Resources -- deletes a resource when the corresponding icon is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Resources/Resources.cypress.spec.tsx/Resources -- deletes a resource when the corresponding icon is clicked.snap.png new file mode 100644 index 0000000000..50980a0b2f Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Resources/Resources.cypress.spec.tsx/Resources -- deletes a resource when the corresponding icon is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- displays the autocomplete as disabled when the user cannot edit the field.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- displays the autocomplete as disabled when the user cannot edit the field.snap.png new file mode 100644 index 0000000000..4572dbf671 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- displays the autocomplete as disabled when the user cannot edit the field.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- displays the user timezone as pre-selected when any value was previously selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- displays the user timezone as pre-selected when any value was previously selected.snap.png new file mode 100644 index 0000000000..ffa2136d33 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- displays the user timezone as pre-selected when any value was previously selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- selects a new timezone when a time zone is selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- selects a new timezone when a time zone is selected.snap.png new file mode 100644 index 0000000000..a796c20add Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/AddEditWidget/WidgetProperties/Inputs/Timezone/Timezone.cypress.spec.tsx/Timezone -- selects a new timezone when a time zone is selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/Dashboard.cypress.spec.tsx/Dashboard -- Edit widget -- resizes the widget to its minimum size when the handle is dragged.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/Dashboard.cypress.spec.tsx/Dashboard -- Edit widget -- resizes the widget to its minimum size when the handle is dragged.snap.png new file mode 100644 index 0000000000..3f63865630 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Dashboards/SingleInstancePage/Dashboard/Dashboard.cypress.spec.tsx/Dashboard -- Edit widget -- resizes the widget to its minimum size when the handle is dragged.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- displays more criterias interface when the corresponding button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- displays more criterias interface when the corresponding button is clicked.snap.png deleted file mode 100644 index 818e6556de..0000000000 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- displays more criterias interface when the corresponding button is clicked.snap.png and /dev/null differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- displays the basic criterias interface.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- displays the basic criterias interface.snap.png deleted file mode 100644 index 8a96d83dac..0000000000 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- displays the basic criterias interface.snap.png and /dev/null differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- does not display the host select and host statuses when the view by host is enabled.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- does not display the host select and host statuses when the view by host is enabled.snap.png deleted file mode 100644 index f1b021b155..0000000000 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- does not display the host select and host statuses when the view by host is enabled.snap.png and /dev/null differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png deleted file mode 100644 index ac230ae57a..0000000000 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png and /dev/null differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- displays the criterias interface.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- displays the criterias interface.snap.png new file mode 100644 index 0000000000..55df46b2fa Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- displays the criterias interface.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png new file mode 100644 index 0000000000..61d2b3a24d Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Type criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Type criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Basic criterias interface when selecting Type criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Basic criterias interface when selecting Type criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png similarity index 100% rename from centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png rename to centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by All -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- displays the criterias interface.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- displays the criterias interface.snap.png new file mode 100644 index 0000000000..8889b549c3 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- displays the criterias interface.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png new file mode 100644 index 0000000000..d4f5f2eb6c Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png new file mode 100644 index 0000000000..9807ced1fa Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png new file mode 100644 index 0000000000..4478452835 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png new file mode 100644 index 0000000000..607bbd5917 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png new file mode 100644 index 0000000000..ddbc83a9d6 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png new file mode 100644 index 0000000000..9a775c697d Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png new file mode 100644 index 0000000000..a1d0f85701 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png new file mode 100644 index 0000000000..3bb68df3e3 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png new file mode 100644 index 0000000000..c13d307a5c Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By host -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- displays the criterias interface.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- displays the criterias interface.snap.png new file mode 100644 index 0000000000..55ea2a3153 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- displays the criterias interface.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png new file mode 100644 index 0000000000..9b67459aad Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Host criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png new file mode 100644 index 0000000000..c1a09690e8 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Host group criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png new file mode 100644 index 0000000000..b414a436f9 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Monitoring server criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png new file mode 100644 index 0000000000..8e1b7c5bb1 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Service criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png new file mode 100644 index 0000000000..48a55bb668 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Service group criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png new file mode 100644 index 0000000000..25f12013c5 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting State criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png new file mode 100644 index 0000000000..4680736cb3 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Basic criterias interface when selecting Status criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png new file mode 100644 index 0000000000..8a391dd7de Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Extended criterias interface when selecting Host category criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png new file mode 100644 index 0000000000..6746c79100 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Filter/Filter.cypress.spec.tsx/Criterias, view by By service -- synchronize the search bar with Extended criterias interface when selecting Host severity criteria value.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Graph/Performance/Graph/AddCommentForm/AddCommentForm.cypress.spec.tsx/Add comment form -- sends a comment request with the given date and the typed comment.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Graph/Performance/Graph/AddCommentForm/AddCommentForm.cypress.spec.tsx/Add comment form -- sends a comment request with the given date and the typed comment.snap.png index e8e1257908..0b712378a8 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Graph/Performance/Graph/AddCommentForm/AddCommentForm.cypress.spec.tsx/Add comment form -- sends a comment request with the given date and the typed comment.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Graph/Performance/Graph/AddCommentForm/AddCommentForm.cypress.spec.tsx/Add comment form -- sends a comment request with the given date and the typed comment.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays acknowledgement details when an acknowledged state chip is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays acknowledgement details when an acknowledged state chip is hovered.snap.png index cee7300085..ae470dd0e0 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays acknowledgement details when an acknowledged state chip is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays acknowledgement details when an acknowledged state chip is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding checks menu.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding checks menu.snap.png index 9c444e8dfa..541e8e79c7 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding checks menu.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding checks menu.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding fqdn menu.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding fqdn menu.snap.png index bec521c1df..f2a6189270 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding fqdn menu.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding fqdn menu.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding notes_url menu.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding notes_url menu.snap.png index 7b0c4d3202..61b116dcc3 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding notes_url menu.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding notes_url menu.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding severity menu.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding severity menu.snap.png index 8cb4f29488..185b2776d9 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding severity menu.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays additional columns when selected from the corresponding severity menu.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays downtime details when the downtime state chip is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays downtime details when the downtime state chip is hovered.snap.png index d74a9c5614..d022939f84 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays downtime details when the downtime state chip is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Display additional columns -- displays downtime details when the downtime state chip is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Listing request -- executes a listing request with a limit param when the rows per page value is changed.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Listing request -- executes a listing request with a limit param when the rows per page value is changed.snap.png index e4800e81ad..779e75dfe0 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Listing request -- executes a listing request with a limit param when the rows per page value is changed.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Listing request -- executes a listing request with a limit param when the rows per page value is changed.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Listing request -- executes a listing request with an updated page param when a change page action is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Listing request -- executes a listing request with an updated page param when a change page action is clicked.snap.png index e3df439ffe..8dbc3451cb 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Listing request -- executes a listing request with an updated page param when a change page action is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Listing request -- executes a listing request with an updated page param when a change page action is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Notification column -- displays notification column if the cloud notification feature is disabled.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Notification column -- displays notification column if the cloud notification feature is disabled.snap.png index f316c1dd8b..34fd92d5a3 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Notification column -- displays notification column if the cloud notification feature is disabled.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Notification column -- displays notification column if the cloud notification feature is disabled.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Notification column -- hides notification column if the cloud notification feature is enabled.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Notification column -- hides notification column if the cloud notification feature is enabled.snap.png index 039b4827bb..71aa45c9ba 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Notification column -- hides notification column if the cloud notification feature is enabled.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Notification column -- hides notification column if the cloud notification feature is enabled.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays a highlighted row when a resource is in a critical state.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays a highlighted row when a resource is in a critical state.snap.png index cef9d3b3c9..8e2fb1dce7 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays a highlighted row when a resource is in a critical state.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays a highlighted row when a resource is in a critical state.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays first part of information when multiple (split by ) are available.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays first part of information when multiple (split by ) are available.snap.png index f6dca348ae..ea0e770841 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays first part of information when multiple (split by ) are available.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays first part of information when multiple (split by ) are available.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays the listing in compact mode.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays the listing in compact mode.snap.png index f6dca348ae..ea0e770841 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays the listing in compact mode.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays the listing in compact mode.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays the listing in extended mode.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays the listing in extended mode.snap.png index aa08ccf437..bf8fc58ac5 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays the listing in extended mode.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- displays the listing in extended mode.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- reorders columns when a drag handle is focused and an arrow is pressed.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- reorders columns when a drag handle is focused and an arrow is pressed.snap.png index 4fc657fa9b..d872ecfee7 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- reorders columns when a drag handle is focused and an arrow is pressed.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing -- reorders columns when a drag handle is focused and an arrow is pressed.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- disables columns drag and drop feature.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- disables columns drag and drop feature.snap.png index 406c9fd482..704e08d4d7 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- disables columns drag and drop feature.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- disables columns drag and drop feature.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- displays the services when the Expand button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- displays the services when the Expand button is clicked.snap.png index edd3f0bf21..f32a68897e 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- displays the services when the Expand button is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- displays the services when the Expand button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- sends a request to retrieve all sevices and their parents.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- sends a request to retrieve all sevices and their parents.snap.png index 406c9fd482..704e08d4d7 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- sends a request to retrieve all sevices and their parents.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- sends a request to retrieve all sevices and their parents.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- sorts columnns by worst status and duration.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- sorts columnns by worst status and duration.snap.png index 406c9fd482..704e08d4d7 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- sorts columnns by worst status and duration.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- sorts columnns by worst status and duration.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- updates column names.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- updates column names.snap.png index 406c9fd482..704e08d4d7 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- updates column names.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Hosts -- updates column names.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- disables columns drag and drop feature.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- disables columns drag and drop feature.snap.png index 196a1448be..cc964d8530 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- disables columns drag and drop feature.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- disables columns drag and drop feature.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- sends a request with types service,metaservice.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- sends a request with types service,metaservice.snap.png index 196a1448be..cc964d8530 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- sends a request with types service,metaservice.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- sends a request with types service,metaservice.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- sorts columnns by worst status and duration.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- sorts columnns by worst status and duration.snap.png index 196a1448be..cc964d8530 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- sorts columnns by worst status and duration.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- sorts columnns by worst status and duration.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- updates column names.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- updates column names.snap.png index 196a1448be..cc964d8530 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- updates column names.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by Service -- updates column names.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- enables columns drag and drop feature.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- enables columns drag and drop feature.snap.png index 812c094287..473e09dd8c 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- enables columns drag and drop feature.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- enables columns drag and drop feature.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sends a request to get all resources.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sends a request to get all resources.snap.png index 812c094287..473e09dd8c 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sends a request to get all resources.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sends a request to get all resources.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sets the column names to the default ones.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sets the column names to the default ones.snap.png index 812c094287..473e09dd8c 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sets the column names to the default ones.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sets the column names to the default ones.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sorts columnns by newest duration.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sorts columnns by newest duration.snap.png index 812c094287..473e09dd8c 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sorts columnns by newest duration.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Resource Listing Visualization by all resources -- sorts columnns by newest duration.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Tree view Feature Flag -- hides the tree view icons if the feature is disabled.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Tree view Feature Flag -- hides the tree view icons if the feature is disabled.snap.png index ac42115d1c..44cc2a621e 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Tree view Feature Flag -- hides the tree view icons if the feature is disabled.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/Tree view Feature Flag -- hides the tree view icons if the feature is disabled.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Duration column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Duration column is clicked.snap.png index ae4169aa2e..5950f652e1 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Duration column is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Duration column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Last check column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Last check column is clicked.snap.png index 459aa0df0f..8dbc3451cb 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Last check column is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Last check column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Parent column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Parent column is clicked.snap.png index ce49479cc3..4e7ec2cf0d 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Parent column is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Parent column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Resource column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Resource column is clicked.snap.png index e645b1c65c..294f25768a 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Resource column is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Resource column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Status column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Status column is clicked.snap.png index 497156dc63..d0ab01079d 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Status column is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Status column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Tries column is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Tries column is clicked.snap.png index 2a2e858a53..7d09d56a5c 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Tries column is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/column sorting -- executes a listing request with sort_by param and stores the order parameter in the URL when Tries column is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/listing actions when the size is medium.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/listing actions when the size is medium.snap.png new file mode 100644 index 0000000000..4afed33e74 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/listing actions when the size is medium.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/listing actions when the size is small.snap.png b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/listing actions when the size is small.snap.png new file mode 100644 index 0000000000..eb9fdf63de Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/front_src/src/Resources/Listing/ResourceListing.cypress.spec.tsx/listing actions when the size is small.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the time in the corresponding timezone and time format when corresponding props are set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the time in the corresponding timezone and time format when corresponding props are set.snap.png new file mode 100644 index 0000000000..4115d436bc Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the time in the corresponding timezone and time format when corresponding props are set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with a custom background color and a description when corresponding props are set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with a custom background color and a description when corresponding props are set.snap.png new file mode 100644 index 0000000000..049fcd48a8 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with a custom background color and a description when corresponding props are set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with default properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with default properties.snap.png new file mode 100644 index 0000000000..fb600d0b78 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with default properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with small width.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with small width.snap.png new file mode 100644 index 0000000000..6fbc14f123 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- displays the widget with small width.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- does not display the date and timezone when corresponding props are set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- does not display the date and timezone when corresponding props are set.snap.png new file mode 100644 index 0000000000..637ff90be2 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Clock -- does not display the date and timezone when corresponding props are set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- displays days when the ends date is far away.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- displays days when the ends date is far away.snap.png new file mode 100644 index 0000000000..d7b9463e2e Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- displays days when the ends date is far away.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- displays the widget with default properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- displays the widget with default properties.snap.png new file mode 100644 index 0000000000..bbfe587992 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- displays the widget with default properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- does not display remaining time when the countdown is invalid.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- does not display remaining time when the countdown is invalid.snap.png new file mode 100644 index 0000000000..aa673930a7 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- does not display remaining time when the countdown is invalid.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- does not display the date and timezone when corresponding props are set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- does not display the date and timezone when corresponding props are set.snap.png new file mode 100644 index 0000000000..0fb09daa10 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-clock/src/spec/Clock.cypress.spec.tsx/Clock-Timer -- Timer -- does not display the date and timezone when corresponding props are set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays custom stacked bar chart when corresponding props are set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays custom stacked bar chart when corresponding props are set.snap.png new file mode 100644 index 0000000000..a0d42576cd Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays custom stacked bar chart when corresponding props are set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the bar chart when the corresponding prop is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the bar chart when the corresponding prop is set.snap.png new file mode 100644 index 0000000000..7d92bcfad6 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the bar chart when the corresponding prop is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the customised bar chart when corresponding props are set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the customised bar chart when corresponding props are set.snap.png new file mode 100644 index 0000000000..3c0117e6b5 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the customised bar chart when corresponding props are set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart when the widget has metrics.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart when the widget has metrics.snap.png index 0f0897970b..fd3ff3dde7 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart when the widget has metrics.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart when the widget has metrics.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a lot of custom style settings when corresponding props are set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a lot of custom style settings when corresponding props are set.snap.png index 5bf79dd4b6..b5358353c9 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a lot of custom style settings when corresponding props are set.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a lot of custom style settings when corresponding props are set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a natural curve when the corresponding prop is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a natural curve when the corresponding prop is set.snap.png index 947a32ef9f..e5fc15f1fc 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a natural curve when the corresponding prop is set.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a natural curve when the corresponding prop is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a step curve when the corresponding prop is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a step curve when the corresponding prop is set.snap.png index 93a1b27fe3..3b78fb6861 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a step curve when the corresponding prop is set.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with a step curve when the corresponding prop is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with customized critical threshold.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with customized critical threshold.snap.png index 7c97b71b5b..4e49709bce 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with customized critical threshold.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with customized critical threshold.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with customized warning threshold.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with customized warning threshold.snap.png index c634a47feb..763189f6de 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with customized warning threshold.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart with customized warning threshold.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart without thresholds when thresholds are disabled.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart without thresholds when thresholds are disabled.snap.png index 90a9017f91..836272663f 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart without thresholds when thresholds are disabled.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the line chart without thresholds when thresholds are disabled.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the stacked bar chart when the corresponding prop is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the stacked bar chart when the corresponding prop is set.snap.png new file mode 100644 index 0000000000..fce6398cb9 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-graph/src/Graph.cypress.spec.tsx/Graph Widget -- displays the stacked bar chart when the corresponding prop is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Limit -- changes the limit when a new limit is selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Limit -- changes the limit when a new limit is selected.snap.png index 12540a2ab4..9aeec43959 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Limit -- changes the limit when a new limit is selected.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Limit -- changes the limit when a new limit is selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Pagination -- changes the page when the page button is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Pagination -- changes the page when the page button is clicked.snap.png index 7b3de07d68..ac9272c4e1 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Pagination -- changes the page when the page button is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Pagination -- changes the page when the page button is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Sorting -- sorts the name column when the header is clicked.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Sorting -- sorts the name column when the header is clicked.snap.png index 132f55be93..b9b988ade8 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Sorting -- sorts the name column when the header is clicked.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- Sorting -- sorts the name column when the header is clicked.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays all statuses when the panel option is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays all statuses when the panel option is set.snap.png index 1bb957bda8..fef30f979e 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays all statuses when the panel option is set.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays all statuses when the panel option is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays only the host column when the panel option is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays only the host column when the panel option is set.snap.png index 6bd73f5b28..56a3ec61d4 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays only the host column when the panel option is set.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays only the host column when the panel option is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays only the service column when the panel option is set.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays only the service column when the panel option is set.snap.png index 88a8361e80..d9d6979db6 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays only the service column when the panel option is set.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays only the service column when the panel option is set.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays the group monitoring widget with default options and the host group resource type is selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays the group monitoring widget with default options and the host group resource type is selected.snap.png index a6d0262865..48837ec221 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays the group monitoring widget with default options and the host group resource type is selected.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays the group monitoring widget with default options and the host group resource type is selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays the group monitoring widget with default options and the service group resource type is selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays the group monitoring widget with default options and the service group resource type is selected.snap.png index f5878ecd72..b9a5e1fae3 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays the group monitoring widget with default options and the service group resource type is selected.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-groupmonitoring/src/GroupMonitoring.cypress.spec.tsx/Group Monitoring -- displays the group monitoring widget with default options and the service group resource type is selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays a confirmation modal when a close ticket button is clicked for a host.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays a confirmation modal when a close ticket button is clicked for a host.snap.png new file mode 100644 index 0000000000..8608868fb5 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays a confirmation modal when a close ticket button is clicked for a host.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays a confirmation modal when a close ticket button is clicked for a service.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays a confirmation modal when a close ticket button is clicked for a service.snap.png new file mode 100644 index 0000000000..ef52e726b3 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays a confirmation modal when a close ticket button is clicked for a service.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays tickets actions when openticket switch is enabled and a rule is selected.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays tickets actions when openticket switch is enabled and a rule is selected.snap.png new file mode 100644 index 0000000000..7651ede7d7 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays tickets actions when openticket switch is enabled and a rule is selected.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays tickets id,subject and open time when openticket switch is enabled, a rule is selected and display resources property is set to withTicket.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays tickets id,subject and open time when openticket switch is enabled, a rule is selected and display resources property is set to withTicket.snap.png new file mode 100644 index 0000000000..a8d0e12791 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/Open tickets -- displays tickets id,subject and open time when openticket switch is enabled, a rule is selected and display resources property is set to withTicket.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays acknowledge informations when the corresponding icon is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays acknowledge informations when the corresponding icon is hovered.snap.png index 18d878e447..3e16894a83 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays acknowledge informations when the corresponding icon is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays acknowledge informations when the corresponding icon is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays downtime informations when the corresponding icon is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays downtime informations when the corresponding icon is hovered.snap.png index 7df7bb9a87..55ce401b34 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays downtime informations when the corresponding icon is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays downtime informations when the corresponding icon is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays listing with columns from widget selected columns properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays listing with columns from widget selected columns properties.snap.png index 2799657920..5197022ae0 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays listing with columns from widget selected columns properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- displays listing with columns from widget selected columns properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with an status from widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with an status from widget properties.snap.png index 2799657920..5197022ae0 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with an status from widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with an status from widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with downtime state defined in the widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with downtime state defined in the widget properties.snap.png index 2799657920..5197022ae0 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with downtime state defined in the widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with downtime state defined in the widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with hostgroup_names filter defined in widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with hostgroup_names filter defined in widget properties.snap.png index 6a55a6fcf4..b6512d4912 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with hostgroup_names filter defined in widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with hostgroup_names filter defined in widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with limit from widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with limit from widget properties.snap.png index 8ac58ee6fd..c36ca663d6 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with limit from widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with limit from widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with resources type filter defined in widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with resources type filter defined in widget properties.snap.png index 8ac58ee6fd..c36ca663d6 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with resources type filter defined in widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with resources type filter defined in widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with sort_by param from widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with sort_by param from widget properties.snap.png index d7d636536b..069466fcf1 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with sort_by param from widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- executes a listing request with sort_by param from widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- retrieves resources.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- retrieves resources.snap.png index 2799657920..361526c83f 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- retrieves resources.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- retrieves resources.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- verify that acknowledge resources row are correctly displayed with the right background color.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- verify that acknowledge resources row are correctly displayed with the right background color.snap.png index 2799657920..5197022ae0 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- verify that acknowledge resources row are correctly displayed with the right background color.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- verify that acknowledge resources row are correctly displayed with the right background color.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- verify that downtime resources row are correctly displayed with the right background color.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- verify that downtime resources row are correctly displayed with the right background color.snap.png index 2799657920..5197022ae0 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- verify that downtime resources row are correctly displayed with the right background color.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by all -- verify that downtime resources row are correctly displayed with the right background color.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- displays listing with columns from widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- displays listing with columns from widget properties.snap.png index 14d7c7d1e3..06f5a5ab83 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- displays listing with columns from widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- displays listing with columns from widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- executes a listing request with limit from widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- executes a listing request with limit from widget properties.snap.png index 14d7c7d1e3..06f5a5ab83 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- executes a listing request with limit from widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- executes a listing request with limit from widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- retrieves resources.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- retrieves resources.snap.png index e5bd43e1e1..f008856d6d 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- retrieves resources.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by host -- retrieves resources.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- displays listing with columns from widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- displays listing with columns from widget properties.snap.png index fd504aabfd..51e96b3d88 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- displays listing with columns from widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- displays listing with columns from widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- executes a listing request with limit from widget properties.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- executes a listing request with limit from widget properties.snap.png index fd504aabfd..51e96b3d88 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- executes a listing request with limit from widget properties.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- executes a listing request with limit from widget properties.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- retrieves resources.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- retrieves resources.snap.png index fd504aabfd..51e96b3d88 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- retrieves resources.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-resourcestable/src/spec/ResourcesTable.cypress.spec.tsx/View by service -- retrieves resources.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/Condensed view -- With resources -- displays the tooltip when the pending card is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/Condensed view -- With resources -- displays the tooltip when the pending card is hovered.snap.png index 9981106441..3434c7497f 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/Condensed view -- With resources -- displays the tooltip when the pending card is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/Condensed view -- With resources -- displays the tooltip when the pending card is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/Link to resource status page -- displays a see more tile when not all resources are displayed.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/Link to resource status page -- displays a see more tile when not all resources are displayed.snap.png index 5328f2556a..80970df8c1 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/Link to resource status page -- displays a see more tile when not all resources are displayed.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/Link to resource status page -- displays a see more tile when not all resources are displayed.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- With Resources -- displays host informations when the mouse is over a tile.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- With Resources -- displays host informations when the mouse is over a tile.snap.png index fd1cf9705e..5a1dff01d3 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- With Resources -- displays host informations when the mouse is over a tile.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- With Resources -- displays host informations when the mouse is over a tile.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- With Resources -- displays tiles.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- With Resources -- displays tiles.snap.png index d5d2e5af74..ef51127a09 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- With Resources -- displays tiles.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- With Resources -- displays tiles.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- Without Resources -- displays tiles.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- Without Resources -- displays tiles.snap.png index d5d2e5af74..ef51127a09 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- Without Resources -- displays tiles.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by host -- Without Resources -- displays tiles.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a critical service tile is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a critical service tile is hovered.snap.png index 3c70e6eee7..345876073b 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a critical service tile is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a critical service tile is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a service in downtime tile is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a service in downtime tile is hovered.snap.png index 39e52d9dc6..784b3efe44 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a service in downtime tile is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a service in downtime tile is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a warning service tile is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a warning service tile is hovered.snap.png index 0ac71d3862..b376bc78a2 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a warning service tile is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when a warning service tile is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an acknowledged service tile is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an acknowledged service tile is hovered.snap.png index c59cfb120e..bf7d0b4cb5 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an acknowledged service tile is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an acknowledged service tile is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an ok service tile is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an ok service tile is hovered.snap.png index dc8eb9f8ce..0a45ed11a2 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an ok service tile is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an ok service tile is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an unknown service tile is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an unknown service tile is hovered.snap.png index 3970e35218..f500bdf579 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an unknown service tile is hovered.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays service informations when an unknown service tile is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays tiles.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays tiles.snap.png index 3352481a5c..9700b3cb51 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays tiles.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- With Resources -- displays tiles.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- Without Resources -- displays tiles.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- Without Resources -- displays tiles.snap.png index 3352481a5c..9700b3cb51 100644 Binary files a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- Without Resources -- displays tiles.snap.png and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGrid.cypress.spec.tsx/View by service -- Without Resources -- displays tiles.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Impact-critical displays business activity informations when the mouse is over a tile.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Impact-critical displays business activity informations when the mouse is over a tile.snap.png new file mode 100644 index 0000000000..cc43c781bf Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Impact-critical displays business activity informations when the mouse is over a tile.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Impact-ok displays business activity informations when the mouse is over a tile.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Impact-ok displays business activity informations when the mouse is over a tile.snap.png new file mode 100644 index 0000000000..9da95dc0fd Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Impact-ok displays business activity informations when the mouse is over a tile.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Ratio-critical displays business activity informations when the mouse is over a tile.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Ratio-critical displays business activity informations when the mouse is over a tile.snap.png new file mode 100644 index 0000000000..8b2ac32af2 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Ratio-critical displays business activity informations when the mouse is over a tile.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Ratio-ok displays business activity informations when the mouse is over a tile.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Ratio-ok displays business activity informations when the mouse is over a tile.snap.png new file mode 100644 index 0000000000..f3e2d264ec Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Ratio-ok displays business activity informations when the mouse is over a tile.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Worst Status-ok displays business activity informations when the mouse is over a tile.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Worst Status-ok displays business activity informations when the mouse is over a tile.snap.png new file mode 100644 index 0000000000..897cf3dbcf Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- Worst Status-ok displays business activity informations when the mouse is over a tile.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- displays tiles.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- displays tiles.snap.png new file mode 100644 index 0000000000..46728da50a Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Business activities -- displays tiles.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays status tiles.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays status tiles.snap.png new file mode 100644 index 0000000000..48420b8b31 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays status tiles.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the pending card is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the pending card is hovered.snap.png new file mode 100644 index 0000000000..66cd931a12 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the pending card is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the problem card is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the problem card is hovered.snap.png new file mode 100644 index 0000000000..e2225ae19f Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the problem card is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the success card is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the success card is hovered.snap.png new file mode 100644 index 0000000000..b75ed93df4 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- Business activities -- displays the tooltip when the success card is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays status tiles.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays status tiles.snap.png new file mode 100644 index 0000000000..bb46425634 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays status tiles.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the pending card is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the pending card is hovered.snap.png new file mode 100644 index 0000000000..96b7288e14 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the pending card is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the problem card is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the problem card is hovered.snap.png new file mode 100644 index 0000000000..b08c1d7b52 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the problem card is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the success card is hovered.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the success card is hovered.snap.png new file mode 100644 index 0000000000..ad04cdc260 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Condensed view -- KPIs -- displays the tooltip when the success card is hovered.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Indicators -- displays boolean rule informations when the mouse is over boolean rule tile.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Indicators -- displays boolean rule informations when the mouse is over boolean rule tile.snap.png new file mode 100644 index 0000000000..1c57a476c3 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Indicators -- displays boolean rule informations when the mouse is over boolean rule tile.snap.png differ diff --git a/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Indicators -- displays tiles.snap.png b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Indicators -- displays tiles.snap.png new file mode 100644 index 0000000000..d4f51f6681 Binary files /dev/null and b/centreon/cypress/visual-testing-snapshots/www/widgets/src/centreon-widget-statusgrid/src/spec/StatusGridWithBam.cypress.spec.tsx/Indicators -- displays tiles.snap.png differ diff --git a/centreon/doc/API/centreon-api.yaml b/centreon/doc/API/centreon-api.yaml index 1f6274c78a..1582b43084 100644 --- a/centreon/doc/API/centreon-api.yaml +++ b/centreon/doc/API/centreon-api.yaml @@ -3,13 +3,15 @@ info: title: Centreon Web RestAPI description: | # New features - + + + Added endpoint to deploy services in a host based on associated host template(s) # Updated features + Added host_category filter to /monitoring/hostgroups endpoint + Added new filters for the /monitoring/hosts/categories endpoint + Added new filters for the /monitoring/services/categories endpoint + Remove snmp_community property from the hosts and host templates listing endpoints + Added new filters to the /monitoring/servicegroups endpoint + + Added new filters for /monitoring/resources /monitoring/resources/hosts related to Open Tickets + + Added new key 'extra' that contains extra data from modules installed for resources endpoints + # Information All dates are in **ISO 8601** format @@ -27,8 +29,8 @@ info: url: 'http://www.apache.org/licenses/LICENSE-2.0.html' version: "24.04" externalDocs: - description: You can contact us on our community Slack - url: 'https://centreon.slack.com/messages/CCRGLQSE5' + description: You can contact us on our community platform The Watch + url: 'https://thewatch.centreon.com/' servers: - url: '{protocol}://{server}:{port}/centreon/api/{version}' variables: @@ -246,8 +248,14 @@ paths: $ref: '#/components/responses/Forbidden' '500': $ref: '#/components/responses/InternalServerError' - /configuration/broker/{brokerId}/outputs: - $ref: "./latest/onPremise/Configuration/Broker/AddBrokerOutput.yaml" + /configuration/additional-connector-configurations: + $ref: "./latest/onPremise/Configuration/AdditionalConnectorConfiguration/AddAndFindAccs.yaml" + /configuration/additional-connector-configurations/{acc_id}: + $ref: "./latest/onPremise/Configuration/AdditionalConnectorConfiguration/DeleteUpdateAndFindAcc.yaml" + /configuration/additional-connectors/pollers/{type}: + $ref: "./latest/onPremise/Configuration/AdditionalConnectorConfiguration/FindPollers.yaml" + /configuration/broker/{brokerId}/{tag}: + $ref: "./latest/onPremise/Configuration/Broker/AddBrokerInputOutput.yaml" /configuration/broker/{brokerId}/outputs/{outputId}/file: $ref: "./latest/onPremise/Configuration/Broker/UpdateStreamConnectorFile.yaml" /configuration/commands: @@ -390,6 +398,8 @@ paths: $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' + /configuration/hosts/{host_id}/services/deploy: + $ref: './latest/onPremise/Configuration/Service/DeployServices.yaml' /configuration/services/categories: get: tags: @@ -409,6 +419,8 @@ paths: * hostgroup.name * hostcategory.id * hostcategory.name + * servicegroup.id + * servicegroup.name responses: "200": description: "OK" @@ -1107,8 +1119,6 @@ paths: description: "Generation OK" '403': $ref: '#/components/responses/Forbidden' - '404': - $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' /configuration/monitoring-servers/reload: @@ -1391,57 +1401,7 @@ paths: '500': $ref: '#/components/responses/InternalServerError' /configuration/timeperiods: - get: - tags: - - Time period - summary: "Get all time periods" - description: | - Get list of all time periods - - The available parameters to **search** / **sort_by** are: - - * id - * name - * alias - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - result: - type: array - items: - $ref: '#/components/schemas/Configuration.TimePeriod' - meta: - $ref: '#/components/schemas/Meta' - '403': - $ref: '#/components/responses/Forbidden' - '500': - $ref: '#/components/responses/InternalServerError' - post: - tags: - - Time period - summary: "Create a new time period" - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Configuration.NewTimePeriod' - responses: - '201': - description: "Time period created" - '400': - $ref: '#/components/responses/BadRequest' - '403': - $ref: '#/components/responses/Forbidden' - '409': - $ref: '#/components/responses/Conflict' - '500': - $ref: '#/components/responses/InternalServerError' + $ref: './latest/onPremise/Configuration/TimePeriod/AddOneAndFindTimePeriods.yaml' /configuration/timeperiods/{id}: delete: tags: @@ -1998,9 +1958,9 @@ paths: '500': $ref: '#/components/responses/InternalServerError' /monitoring/hosts/status: - $ref: './latest/onPremise/Realtime/Resources/FindHostsStatus.yaml' + $ref: './latest/onPremise/Realtime/Hosts/FindHostsStatus.yaml' /monitoring/services/status: - $ref: './latest/onPremise/Realtime/Resources/FindServicesStatus.yaml' + $ref: './latest/onPremise/Realtime/Services/FindServicesStatus.yaml' /monitoring/services: get: tags: @@ -4647,78 +4607,7 @@ paths: '500': $ref: '#/components/responses/InternalServerError' /administration/vaults/configurations: - post: - tags: - - Administration - summary: "Create vault configuration" - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Administration.Vault.Configuration.Write' - responses: - '201': - description: "OK" - '400': - $ref: '#/components/responses/BadRequest' - '403': - $ref: '#/components/responses/Forbidden' - '404': - $ref: '#/components/responses/NotFound' - '500': - $ref: '#/components/responses/InternalServerError' - put: - tags: - - Administration - summary: "Update vault configuration" - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Administration.Vault.Configuration.Update' - responses: - '204': - description: "OK" - '400': - $ref: '#/components/responses/BadRequest' - '403': - $ref: '#/components/responses/Forbidden' - '404': - $ref: '#/components/responses/NotFound' - '500': - $ref: '#/components/responses/InternalServerError' - delete: - tags: - - Administration - summary: "Delete vault configuration" - responses: - '204': - description: "OK" - '403': - $ref: '#/components/responses/Forbidden' - '404': - $ref: '#/components/responses/NotFound' - '500': - $ref: '#/components/responses/InternalServerError' - get: - tags: - - Administration - summary: "Get vault configuration details" - responses: - '200': - description: "OK" - content: - application/json: - schema: - $ref: '#/components/schemas/Administration.Vault.Configuration.Read' - '403': - $ref: '#/components/responses/Forbidden' - '404': - $ref: '#/components/responses/NotFound' - '500': - $ref: '#/components/responses/InternalServerError' + $ref: "./latest/onPremise/Administration/Vault/VaultConfiguration.yaml" components: securitySchemes: Token: @@ -5120,24 +5009,6 @@ components: required: true schema: type: string - VaultId: - in: path - name: vault_id - description: "ID of vault provider" - required: true - schema: - type: integer - format: int64 - example: 1 - VaultConfigurationId: - in: path - name: vault_configuration_id - description: "ID of existing vault configuration" - required: true - schema: - type: integer - format: int64 - example: 1 HostCategoryId: in: path name: host_category_id @@ -7359,6 +7230,10 @@ components: type: string description: "URL for the icon" example: "/centreon/img/media/ppm/applications-monitoring-centreon-central-centreon-128-2.png" + extra: + type: array + items: + type: object Monitoring.ResourceLinks: type: object properties: @@ -8242,80 +8117,3 @@ components: type: string description: "Data on JSON Format" example: "{\"action\":\"getthumbprint\",\"data\":{\"thumbprint\":\"xxxx_xxxxxxxxx\"},\"message\":\"ok\"}" - Administration.Vault.Configuration.Write: - type: object - required: [name, address, port, root_path, role_id, secret_id] - description: "Vault configuration" - properties: - name: - type: string - description: "Vault configuration name" - example: "centreon_vault" - address: - type: string - description: "Vault URL or IP" - example: "127.0.0.1" - port: - type: integer - description: "Vault Port" - example: 8200 - root_path: - type: string - description: "Vault root storage path" - example: "centreon" - role_id: - type: string - description: "Vault role id" - secret_id: - type: string - description: "Vault secret id" - Administration.Vault.Configuration.Update: - type: object - required: [address, port, role_id, secret_id] - description: "Vault configuration" - properties: - address: - type: string - description: "Vault URL or IP" - example: "127.0.0.1" - port: - type: integer - description: "Vault Port" - example: 8200 - role_id: - type: string - description: "Vault role id" - secret_id: - type: string - description: "Vault secret id" - Administration.Vault.Configuration.Read: - type: object - description: "Vault configuration" - properties: - id: - type: integer - description: "Vault configuration id" - example: 1 - name: - type: string - description: "Vault configuration name" - example: "centreon_vault" - vault_id: - type: integer - description: "Vault provider id" - example: 1 - address: - type: string - description: "Vault URL or IP" - example: "127.0.0.1" - port: - type: integer - description: "Vault Port" - example: 8200 - root_path: - type: string - description: "Vault root storage path" - example: "centreon" - role_id: - type: string - description: "Vault role ID" diff --git a/centreon/doc/API/centreon-cloud-api.yaml b/centreon/doc/API/centreon-cloud-api.yaml index 767d890a7e..2778770725 100644 --- a/centreon/doc/API/centreon-cloud-api.yaml +++ b/centreon/doc/API/centreon-cloud-api.yaml @@ -3,7 +3,7 @@ info: title: Centreon Web RestAPI for Cloud description: | # New features - + + + Added endpoint to deploy services in a host based on associated host template(s) # Updated features + + @@ -21,10 +21,9 @@ info: license: name: Apache 2.0 url: 'http://www.apache.org/licenses/LICENSE-2.0.html' - version: "24.04" externalDocs: - description: You can contact us on our community Slack - url: 'https://centreon.slack.com/messages/CCRGLQSE5' + description: You can contact us on our community platform The Watch + url: 'https://thewatch.centreon.com/' servers: - url: '{protocol}://{server}:{port}/centreon/api/{version}' variables: @@ -70,6 +69,8 @@ paths: $ref: './latest/Cloud/Configuration/HostTemplate/AddAndFindHostTemplates.yaml' /configuration/hosts/templates/{host_template_id}: $ref: './latest/Cloud/Configuration/HostTemplate/PartialUpdateHostTemplate.yaml' + /configuration/hosts/{host_id}/services/deploy: + $ref: './latest/Cloud/Configuration/Service/DeployServices.yaml' /configuration/services: $ref: "./latest/Cloud/Configuration/Service/AddAndFindServices.yaml" /configuration/services/{service_id}: diff --git a/centreon/doc/API/centreon-logo.png b/centreon/doc/API/centreon-logo.png old mode 100755 new mode 100644 index 5458fb678d..a34220331f Binary files a/centreon/doc/API/centreon-logo.png and b/centreon/doc/API/centreon-logo.png differ diff --git a/centreon/doc/API/latest/Cloud/Configuration/Service/DeployServices.yaml b/centreon/doc/API/latest/Cloud/Configuration/Service/DeployServices.yaml new file mode 100644 index 0000000000..e01f11b208 --- /dev/null +++ b/centreon/doc/API/latest/Cloud/Configuration/Service/DeployServices.yaml @@ -0,0 +1,29 @@ +post: + tags: + - Service + summary: "Add services to a host based on associated host template" + description: | + Add services to a host based on associated host templates + responses: + '201': + description: "Objects created" + content: + application/json: + schema: + type: object + properties: + services: + type: array + items: + $ref: 'Schema/DeployServiceResponse.yaml' + '204': + $ref: '../../../Common/Response/NoContent.yaml' + '401': + $ref: '../../../Common/Response/Unauthorized.yaml' + '403': + $ref: '../../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../../Common/Response/NotFound.yaml' + '500': + $ref: '../../../Common/Response/InternalServerError.yaml' + diff --git a/centreon/doc/API/latest/Cloud/Configuration/Service/Schema/DeployServiceResponse.yaml b/centreon/doc/API/latest/Cloud/Configuration/Service/Schema/DeployServiceResponse.yaml new file mode 100644 index 0000000000..7176505264 --- /dev/null +++ b/centreon/doc/API/latest/Cloud/Configuration/Service/Schema/DeployServiceResponse.yaml @@ -0,0 +1,78 @@ +type: object +allOf: + - properties: + id: + type: integer + description: "Service ID." + example: 1 + name: + type: string + description: "Service name." + example: "generic-service" + host_id: + type: integer + description: "ID of the host linked to this service." + example: 1 + geo_coords: + type: string + description: "Geographic coordinates of the service" + example: "48.10,12.5" + service_template_id: + type: integer + description: "Template ID of the service template." + minimum: 1 + nullable: true + example: null + check_timeperiod_id: + type: integer + description: "Time period ID of the check command." + minimum: 1 + nullable: true + example: null + max_check_attempts: + type: integer + description: "Define the number of times that the monitoring engine will retry the service check command if it returns any non-OK state." + nullable: true + normal_check_interval: + type: integer + description: | + Define the number of 'time units' between regularly scheduled checks of the service. + + With the default time unit of 60s, this number will mean multiples of 1 minute. + nullable: true + retry_check_interval: + type: integer + description: | + Define the number of "time units" to wait before scheduling a re-check for this service after a non-OK state was detected. + + With the default time unit of 60s, this number will mean multiples of 1 minute. + + Once the service has been retried max_check_attempts times without a change in its status, + it will revert to being scheduled at its "normal" check interval rate. + nullable: true + note: + type: string + description: "Define an optional note." + nullable: true + maxLength: 65535 + note_url: + type: string + description: "Define an optional URL that can be used to provide more information about the service." + maxLength: 65535 + nullable: true + action_url: + type: string + description: "Define an optional URL that can be used to specify actions to be performed on the service." + nullable: true + maxLength: 65535 + icon_id: + type: integer + description: "Define the image ID that should be associated with this service." + minimum: 1 + nullable: true + example: null + severity_id: + type: integer + description: "Severity ID." + minimum: 1 + nullable: true diff --git a/centreon/doc/API/latest/Common/Response/UnprocessableContent.yaml b/centreon/doc/API/latest/Common/Response/UnprocessableContent.yaml new file mode 100644 index 0000000000..e2e5132f3a --- /dev/null +++ b/centreon/doc/API/latest/Common/Response/UnprocessableContent.yaml @@ -0,0 +1,16 @@ +description: | + Unprocessable Content + + The server understands the content type of the request entity, and the syntax of the request entity is correct, but it was unable to process the contained instructions. +content: + application/json: + schema: + type: object + properties: + code: + type: integer + format: int64 + example: 422 + message: + type: string + example: "id: This value should be of type integer\n" diff --git a/centreon/doc/API/latest/onPremise/Administration/Vault/Schema/GetVaultConfiguration.yaml b/centreon/doc/API/latest/onPremise/Administration/Vault/Schema/GetVaultConfiguration.yaml new file mode 100644 index 0000000000..4e2477e754 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Administration/Vault/Schema/GetVaultConfiguration.yaml @@ -0,0 +1,26 @@ +type: object +description: "Vault configuration" +properties: + id: + type: integer + description: "Vault configuration id" + example: 1 + vault_id: + type: integer + description: "Vault provider id" + example: 1 + address: + type: string + description: "Vault URL or IP" + example: "127.0.0.1" + port: + type: integer + description: "Vault Port" + example: 8200 + root_path: + type: string + description: "Vault root storage path" + example: "centreon" + role_id: + type: string + description: "Vault role ID" diff --git a/centreon/doc/API/latest/onPremise/Administration/Vault/Schema/UpdateVaultConfiguration.yaml b/centreon/doc/API/latest/onPremise/Administration/Vault/Schema/UpdateVaultConfiguration.yaml new file mode 100644 index 0000000000..4f1e2f9b84 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Administration/Vault/Schema/UpdateVaultConfiguration.yaml @@ -0,0 +1,22 @@ +type: object +required: [address, port, root_path, role_id, secret_id] +description: "Vault configuration" +properties: + address: + type: string + description: "Vault URL or IP" + example: "127.0.0.1" + port: + type: integer + description: "Vault Port" + example: 8200 + root_path: + type: string + description: "Vault root storage path" + example: "centreon" + role_id: + type: string + description: "Vault role id" + secret_id: + type: string + description: "Vault secret id" diff --git a/centreon/doc/API/latest/onPremise/Administration/Vault/VaultConfiguration.yaml b/centreon/doc/API/latest/onPremise/Administration/Vault/VaultConfiguration.yaml new file mode 100644 index 0000000000..03cdab2857 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Administration/Vault/VaultConfiguration.yaml @@ -0,0 +1,51 @@ +put: + tags: + - Administration + summary: "Update or create vault configuration" + requestBody: + required: true + content: + application/json: + schema: + $ref: './Schema/UpdateVaultConfiguration.yaml' + responses: + '204': + description: "OK" + '400': + $ref: '../../Common/Response/BadRequest.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' +delete: + tags: + - Administration + summary: "Delete vault configuration" + responses: + '204': + description: "OK" + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' +get: + tags: + - Administration + summary: "Get vault configuration details" + responses: + '200': + description: "OK" + content: + application/json: + schema: + $ref: './Schema/GetVaultConfiguration.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Common/Response/UnprocessableContent.yaml b/centreon/doc/API/latest/onPremise/Common/Response/UnprocessableContent.yaml new file mode 100644 index 0000000000..8493d94c06 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Common/Response/UnprocessableContent.yaml @@ -0,0 +1 @@ +$ref: "../../../Common/Response/UnprocessableContent.yaml" diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/AddAndFindAccs.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/AddAndFindAccs.yaml new file mode 100644 index 0000000000..de89ff526b --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/AddAndFindAccs.yaml @@ -0,0 +1,64 @@ +post: + tags: + - Additional Connector Configuration + summary: "Add an Additional Connector Configuration (ACC)" + description: "Add an Additional Connector Configuration (ACC)" + requestBody: + required: true + content: + application/json: + schema: + $ref: 'Schema/AddAccRequest.yaml' + responses: + '201': + description: "Object created" + content: + application/json: + schema: + $ref: 'Schema/AddAccResponse.yaml' + '400': + $ref: '../../Common/Response/BadRequest.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '409': + $ref: '../../Common/Response/Conflict.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' +get: + tags: + - Additional Connector Configuration + summary: "List Additional Connector Configurations (ACC)" + description: | + Return all ACCs. + + The available parameters to **search** / **sort_by** are: + + * name + * type + * poller.id + * poller.name + parameters: + - $ref: '../../Common/QueryParameter/Limit.yaml' + - $ref: '../../Common/QueryParameter/Page.yaml' + - $ref: '../../Common/QueryParameter/Search.yaml' + - $ref: '../../Common/QueryParameter/SortBy.yaml' + responses: + '200': + description: "OK" + content: + application/json: + schema: + type: object + properties: + result: + type: array + items: + $ref: 'Schema/FindAccsResponse.yaml' + meta: + $ref: '../../Common/Schema/Meta.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/DeleteUpdateAndFindAcc.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/DeleteUpdateAndFindAcc.yaml new file mode 100644 index 0000000000..97f21a56ee --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/DeleteUpdateAndFindAcc.yaml @@ -0,0 +1,62 @@ +delete: + tags: + - Additional Connector Configuration + summary: "Delete an Additional Connector Configuration (ACC)" + description: "Delete an Additional Connector Configuration (ACC)" + parameters: + - $ref: 'QueryParameter/AccId.yaml' + responses: + '204': + $ref: '../../Common/Response/NoContent.yaml' + '400': + $ref: '../../Common/Response/BadRequest.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' +get: + tags: + - Additional Connector Configuration + summary: "Find an Additional Connector Configuration (ACC)" + description: "Find an Additional Connector Configuration (ACC)" + parameters: + - $ref: 'QueryParameter/AccId.yaml' + responses: + '200': + description: "OK" + content: + application/json: + schema: + $ref: 'Schema/FindAccResponse.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' +put: + tags: + - Additional Connector Configuration + summary: "Update an Additional Connector Configuration (ACC)" + description: "Update an Additional Connector Configuration (ACC)" + parameters: + - $ref: 'QueryParameter/AccId.yaml' + requestBody: + required: true + content: + application/json: + schema: + $ref: 'Schema/UpdateAccRequest.yaml' + responses: + '204': + $ref: '../../Common/Response/NoContent.yaml' + '400': + $ref: '../../Common/Response/BadRequest.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/FindPollers.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/FindPollers.yaml new file mode 100644 index 0000000000..ddc9022e89 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/FindPollers.yaml @@ -0,0 +1,40 @@ +get: + tags: + - Additional Connector Configuration + summary: "Find available pollers for an ACC type" + description: "Find available pollers for an ACC type" + parameters: + - in: path + name: type + required: true + description: | + Available Additional Connector Configuration types: + - vmware_v6 + schema: + type: integer + minimum: 1 + example: 1 + - $ref: '../../Common/QueryParameter/Limit.yaml' + - $ref: '../../Common/QueryParameter/Page.yaml' + - $ref: '../../Common/QueryParameter/Search.yaml' + - $ref: '../../Common/QueryParameter/SortBy.yaml' + responses: + '200': + description: "OK" + content: + application/json: + schema: + type: object + properties: + result: + type: array + items: + $ref: 'Schema/FindPollersResponse.yaml' + meta: + $ref: '../../Common/Schema/Meta.yaml' + '400': + $ref: '../../Common/Response/BadRequest.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/QueryParameter/AccId.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/QueryParameter/AccId.yaml new file mode 100644 index 0000000000..be64eed8bb --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/QueryParameter/AccId.yaml @@ -0,0 +1,8 @@ +in: path +name: acc_id +required: true +description: "Additional Connector Configuration ID" +schema: + type: integer + minimum: 1 + example: 1 diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/AddAccRequest.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/AddAccRequest.yaml new file mode 100644 index 0000000000..c631f9d196 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/AddAccRequest.yaml @@ -0,0 +1,39 @@ +type: object +required: ["name", "type", "pollers", "parameters"] +properties: + name: + type: string + description: "ACC name" + example: "my-acc-name" + description: + type: string + description: "A short ACC description" + example: "some description" + type: + type: string + description: | + Type of ACC + + Supported ACC types: + * vmware_v6 + example: vmware_v6 + pollers: + type: array + items: + type: integer + description: Poller ID(s) associated with the ACC + example: [1, 12] + parameters: + type: object + description: | + Configuration parameters, varies depending on the ACC type. + example: + port: 4242 + vcenters: [ + { + "name": "my-vcenter", + "url": "http://10.10.10.10/sdk", + "username": "admin", + "password": "my-pwd" + } + ] diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/AddAccResponse.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/AddAccResponse.yaml new file mode 100644 index 0000000000..654cc65219 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/AddAccResponse.yaml @@ -0,0 +1,61 @@ +type: object +properties: + id: + type: integer + example: 4 + name: + type: string + description: "ACC name" + example: "my-acc-name" + description: + type: string + description: "A short ACC description" + example: "some description" + type: + type: string + description: | + Type of ACC + + Supported ACC types: + * vmware_v6 + example: vmware_v6 + pollers: + type: array + items: + type: object + properties: + id: + type: integer + description: "Poller ID" + example: 1 + name: + type: string + description: "Poller name" + example: "my-poller-name" + description: Poller(s) associated with the ACC + parameters: + type: object + description: | + Configuration parameters, varies depending on the ACC type. + Credential values are not readable and will always be null. + example: + port: 4242 + vcenters: [ + { + "name": "my-vcenter", + "url": "http://10.10.10.10/sdk", + "username": null, + "password": null + } + ] + created_by: + type: object + nullable: true + properties: + id: { type: integer, description: "Creation contact ID", example: 1 } + name: { type: string, description: "Creation contact name", example: "admin" } + created_at: + type: string + format: date-time + nullable: true + description: "Creation date (ISO8601)" diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindAccResponse.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindAccResponse.yaml new file mode 100644 index 0000000000..cf3fe91484 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindAccResponse.yaml @@ -0,0 +1,72 @@ +type: object +properties: + id: + type: integer + example: 4 + name: + type: string + description: "ACC name" + example: "my-acc-name" + description: + type: string + description: "A short ACC description" + example: "some description" + type: + type: string + description: | + Type of ACC + + Supported ACC types: + * vmware_v6 + example: vmware_v6 + pollers: + type: array + items: + type: object + properties: + id: + type: integer + description: "Poller ID" + example: 1 + name: + type: string + description: "Poller name" + example: "my-poller-name" + description: Poller(s) associated with the ACC + parameters: + type: object + description: | + Configuration parameters, varies depending on the ACC type. + Credential values are not readable and will always be null. + example: + port: 4242 + vcenters: [ + { + "name": "my-vcenter", + "url": "http://10.10.10.10/sdk", + "username": null, + "password": null + } + ] + created_by: + type: object + nullable: true + properties: + id: { type: integer, description: "Creation contact ID", example: 1 } + name: { type: string, description: "Creation contact name", example: "admin" } + created_at: + type: string + format: date-time + nullable: true + description: "Creation date (ISO8601)" + updated_by: + type: object + nullable: true + properties: + id: { type: integer, description: "Update contact ID", example: 1 } + name: { type: string, description: "Update contact name", example: "admin" } + updated_at: + type: string + format: date-time + nullable: true + description: "Update date (ISO8601)" diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindAccsResponse.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindAccsResponse.yaml new file mode 100644 index 0000000000..3543a29039 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindAccsResponse.yaml @@ -0,0 +1,43 @@ +type: object +properties: + id: + type: integer + example: 4 + name: + type: string + description: "ACC name" + example: "my-acc-name" + description: + type: string + description: "A short ACC description" + example: "some description" + type: + type: string + description: | + Type of ACC + + Supported ACC types: + * vmware_v6 + example: vmware_v6 + created_by: + type: object + nullable: true + properties: + id: { type: integer, description: "Creation contact ID", example: 1 } + name: { type: string, description: "Creation contact name", example: "admin" } + created_at: + type: string + format: date-time + nullable: true + description: "Creation date (ISO8601)" + updated_by: + type: object + nullable: true + properties: + id: { type: integer, description: "Update contact ID", example: 1 } + name: { type: string, description: "Update contact name", example: "admin" } + updated_at: + type: string + format: date-time + nullable: true + description: "Update date (ISO8601)" diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindPollersResponse.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindPollersResponse.yaml new file mode 100644 index 0000000000..7213239557 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/FindPollersResponse.yaml @@ -0,0 +1,9 @@ +type: object +properties: + id: + type: integer + example: 4 + name: + type: string + description: "Poller name" + example: "my-poller-name" diff --git a/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/UpdateAccRequest.yaml b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/UpdateAccRequest.yaml new file mode 100644 index 0000000000..3b8aa2f748 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/AdditionalConnectorConfiguration/Schema/UpdateAccRequest.yaml @@ -0,0 +1,47 @@ +type: object +required: ["name", "type", "pollers", "parameters"] +properties: + name: + type: string + description: "ACC name" + example: "my-acc-name" + description: + type: string + description: "A short ACC description" + example: "some description" + type: + type: string + description: | + Type of ACC + + Supported ACC types: + * vmware_v6 + example: vmware_v6 + pollers: + type: array + items: + type: integer + description: Poller ID(s) associated with the ACC + example: [1, 12] + parameters: + type: object + description: | + Configuration parameters, varies depending on the ACC type. + If credential(s) do not change, replace value(s) by null. + example: + port: 4242 + vcenters: [ + { + "name": "my-vcenter B", + "url": "http://10.10.10.10/sdk", + "username": null, + "password": null + }, + { + "name": "my-vcenter B", + "url": "http://10.10.10.10/sdk", + "username": "admin", + "password": "my-pwd B" + } + + ] diff --git a/centreon/doc/API/latest/onPremise/Configuration/Broker/AddBrokerInputOutput.yaml b/centreon/doc/API/latest/onPremise/Configuration/Broker/AddBrokerInputOutput.yaml new file mode 100644 index 0000000000..b737b840fb --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/Broker/AddBrokerInputOutput.yaml @@ -0,0 +1,37 @@ +post: + tags: + - Broker + summary: "Add a Broker input/output" + description: "Add a Broker input/output configuration" + parameters: + - $ref: 'QueryParameter/BrokerId.yaml' + - in: path + name: tag + description: "The configuration tag" + required: true + schema: + type: string + enum: [inputs, outputs] + requestBody: + required: true + content: + application/json: + schema: + $ref: 'Schema/AddBrokerInputOutputRequest.yaml' + responses: + '201': + description: "Object created" + content: + application/json: + schema: + $ref: 'Schema/AddBrokerInputOutputResponse.yaml' + '400': + $ref: '../../Common/Response/BadRequest.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '409': + $ref: '../../Common/Response/Conflict.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Configuration/Broker/AddBrokerOutput.yaml b/centreon/doc/API/latest/onPremise/Configuration/Broker/AddBrokerOutput.yaml deleted file mode 100644 index aa06d4c674..0000000000 --- a/centreon/doc/API/latest/onPremise/Configuration/Broker/AddBrokerOutput.yaml +++ /dev/null @@ -1,31 +0,0 @@ -post: - tags: - - Broker - summary: "Add a broker output" - description: "Add a broker output configuration" - parameters: - - $ref: 'QueryParameter/BrokerId.yaml' - requestBody: - required: true - content: - application/json: - schema: - $ref: 'Schema/AddBrokerOutputRequest.yaml' - responses: - '201': - description: "Object created" - content: - application/json: - schema: - type: object - $ref: 'Schema/AddBrokerOutputResponse.yaml' - '400': - $ref: '../../Common/Response/BadRequest.yaml' - '403': - $ref: '../../Common/Response/Forbidden.yaml' - '404': - $ref: '../../Common/Response/NotFound.yaml' - '409': - $ref: '../../Common/Response/Conflict.yaml' - '500': - $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerInputOutputRequest.yaml b/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerInputOutputRequest.yaml new file mode 100644 index 0000000000..7661f7c421 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerInputOutputRequest.yaml @@ -0,0 +1,60 @@ +type: object +required: ["name", "type", "parameters"] +properties: + name: + type: string + description: "input/output name" + example: "central-broker-master-unified-sql" + type: + type: integer + description: | + Input/Output type ID + + Must be one of the following for outputs: + * 3 - IPv4 (ipv4) + * 10 - IPv6 (ipv6) + * 11 - File (file) + * 13 - RRD file generator (rrd) + * 14 - Perfdata Generator (Centreon Storage) - DEPRECATED (storage) + * 16 - Broker SQL database - DEPRECATED (sql) + * 28 - Database configuration reader (db_cfg_reader) + * 29 - Database configuration writer (db_cfg_writer) + * 30 - Storage - Graphite (graphite) + * 31 - Storage - InfluxDB (influxdb) + * 33 - Stream connector (lua) + * 34 - Unified SQL (unified_sql) + * 35 - BBDO Server (bbdo_server) + * 36 - BBDO Client (bbdo_client) + + Must be one of the following for inputs: + * 3 - IPv4 (ipv4) + * 10 - IPv6 (ipv6) + * 11 - File (file) + * 35 - BBDO Server (bbdo_server) + * 36 - BBDO Client (bbdo_client) + example: 33 + parameters: + type: object + description: | + Output parameters specific to the output type. + + For multiselect fields the property name is a combination of + the group field name and the sub field name as "{fieldName}_{subfieldName}" (ex: "filters_category") + + All fields must be provided, but can be null/empty if they are optional. + + example: + path: "some/test/path" + filters_category: ["storage", "neb"] + lua_parameter: [ + { + "type": "string", + "name": "my-lua-param-1", + "value": "azerty" + }, + { + "type": "string", + "name": "my-lua-param-2", + "value": "qwerty" + } + ] diff --git a/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerInputOutputResponse.yaml b/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerInputOutputResponse.yaml new file mode 100644 index 0000000000..ade0baca2a --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerInputOutputResponse.yaml @@ -0,0 +1,44 @@ +type: object +properties: + brokerId: + type: integer + description: "Broker configuration ID" + example: 1 + name: + type: string + description: "input/output name" + example: "central-broker-master-unified-sql" + type: + type: object + description: "input/output type" + properties: + id: + type: integer + description: "input/output type ID" + example: 33 + name: + type: string + description: "input/output type name" + example: "lua" + parameters: + type: object + description: | + Input/Output parameters specific to its type. + + For multiselect fields, the property name is a combination of the group field name and the sub field name (ex: "filters_category") + + example: + path: "some/test/path" + filters_category: ["storage", "neb"] + lua_parameter: [ + { + "type": "string", + "name": "my-lua-param-1", + "value": "azerty" + }, + { + "type": "string", + "name": "my-lua-param-2", + "value": "qwerty" + } + ] diff --git a/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerOutputRequest.yaml b/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerOutputRequest.yaml deleted file mode 100644 index f125e3ec00..0000000000 --- a/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerOutputRequest.yaml +++ /dev/null @@ -1,55 +0,0 @@ -type: object -required: ["name", "typeId", "parameters"] -properties: - name: - type: string - description: "output name" - example: "central-broker-master-unified-sql" - type: - type: integer - description: | - Output type ID - - Must be one of the following: - * 3 - IPv4 (ipv4) - * 10 - IPv6 (ipv6) - * 11 - File (file) - * 13 - RRD file generator (rrd) - * 14 - Perfdata Generator (Centreon Storage) - DEPRECATED (storage) - * 16 - Broker SQL database - DEPRECATED (sql) - * 28 - Database configuration reader (db_cfg_reader) - * 29 - Database configuration writer (db_cfg_writer) - * 30 - Storage - Graphite (graphite) - * 31 - Storage - InfluxDB (influxdb) - * 33 - Stream connector (lua) - * 34 - Unified SQL (unified_sql) - * 35 - BBDO Server (bbdo_server) - * 36 - BBDO Client (bbdo_client) - example: "33" - parameters: - type: object - description: | - Output parameters specific to the output type. - - For multiselect fields the property name is a combination of - the group field name and the sub field name as "{fieldName}_{subfieldName}" (ex: "filters_category") - - All fields must be provided, but can be null/empty if they are optional. - - example: | - { - "path": "some/test/path", - "filters.category": ["storage", "neb"], - "lua_parameter": [ - { - "type": "string", - "name": "my-lua-param-1", - "value": "azerty" - }, - { - "type": "string", - "name": "my-lua-param-2", - "value": "qwerty" - } - ] - } diff --git a/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerOutputResponse.yaml b/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerOutputResponse.yaml deleted file mode 100644 index c2075614cd..0000000000 --- a/centreon/doc/API/latest/onPremise/Configuration/Broker/Schema/AddBrokerOutputResponse.yaml +++ /dev/null @@ -1,46 +0,0 @@ -type: object -properties: - brokerId: - type: integer - description: "Broker configuration ID" - example: 1 - name: - type: string - description: "output name" - example: "central-broker-master-unified-sql" - type: - type: object - description: "output type" - properties: - id: - type: integer - description: "output type ID" - example: 33 - name: - type: string - description: "output type name" - example: "lua" - parameters: - type: object - description: | - Output parameters specific to the output type. - - For multiselect fields, the property name is a combination of the group field name and the sub field name (ex: "filters.category") - - example: | - { - "path": "some/test/path", - "filters.category": ["storage", "neb"], - "lua_parameter": [ - { - "type": "string", - "name": "my-lua-param-1", - "value": "azerty" - }, - { - "type": "string", - "name": "my-lua-param-2", - "value": "qwerty" - } - ] - } diff --git a/centreon/doc/API/latest/onPremise/Configuration/Service/DeployServices.yaml b/centreon/doc/API/latest/onPremise/Configuration/Service/DeployServices.yaml new file mode 100644 index 0000000000..1953a37e77 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/Service/DeployServices.yaml @@ -0,0 +1,28 @@ +post: + tags: + - Service + summary: "Add services to a host based on associated host template" + description: | + Add services to a host based on associated host template + responses: + '201': + description: "Objects created" + content: + application/json: + schema: + type: object + properties: + services: + type: array + items: + $ref: 'Schema/DeployServiceResponse.yaml' + '204': + $ref: '../../Common/Response/NoContent.yaml' + '401': + $ref: '../../Common/Response/Unauthorized.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '404': + $ref: '../../Common/Response/NotFound.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Configuration/Service/Schema/DeployServiceResponse.yaml b/centreon/doc/API/latest/onPremise/Configuration/Service/Schema/DeployServiceResponse.yaml new file mode 100644 index 0000000000..d8e092ab6f --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/Service/Schema/DeployServiceResponse.yaml @@ -0,0 +1,260 @@ +type: object +allOf: + - properties: + id: + type: integer + description: "Service ID." + example: 1 + name: + type: string + description: "Service name." + example: "generic-service" + host_id: + type: integer + description: "ID of the host linked to this service." + example: 1 + geo_coords: + type: string + description: "Geographic coordinates of the service" + example: "48.10,12.5" + comment: + type: string + description: "Service comment." + nullable: true + service_template_id: + type: integer + description: "Template ID of the service template." + minimum: 1 + nullable: true + example: null + check_command_id: + type: integer + description: "Check command ID." + minimum: 1 + nullable: true + example: null + check_command_args: + type: array + items: + type: string + description: "Arguments of the check command." + example: ["80", "90"] + check_timeperiod_id: + type: integer + description: "Time period ID of the check command." + minimum: 1 + nullable: true + example: null + max_check_attempts: + type: integer + description: "Define the number of times that the monitoring engine will retry the service check command if it returns any non-OK state." + nullable: true + normal_check_interval: + type: integer + description: | + Define the number of 'time units' between regularly scheduled checks of the service. + + With the default time unit of 60s, this number will mean multiples of 1 minute. + nullable: true + retry_check_interval: + type: integer + description: | + Define the number of "time units" to wait before scheduling a re-check for this service after a non-OK state was detected. + + With the default time unit of 60s, this number will mean multiples of 1 minute. + + Once the service has been retried max_check_attempts times without a change in its status, + it will revert to being scheduled at its "normal" check interval rate. + nullable: true + active_check_enabled: + type: integer + description: | + Indicates whether active checks are enabled or not + + * `0` - STATUS_DISABLED + * `1` - STATUS_ENABLED + * `2` - STATUS_DEFAULT (inheritance of its parent's value. If there is no parent, the values used will be that of Centreon Engine) + example: 2 + passive_check_enabled: + type: integer + description: | + Indicates whether passive checks are enabled or not + + * `0` - STATUS_DISABLED + * `1` - STATUS_ENABLED + * `2` - STATUS_DEFAULT (inheritance of its parent's value. If there is no parent, the values used will be that of Centreon Engine) + example: 2 + volatility_enabled: + type: integer + description: | + Indicates whether the service is "volatile" or not + + * `0` - STATUS_DISABLED + * `1` - STATUS_ENABLED + * `2` - STATUS_DEFAULT (inheritance of its parent's value. If there is no parent, the values used will be that of Centreon Engine) + example: 2 + notification_enabled: + type: integer + description: | + Specify whether notifications are enabled or not + + * `0` - STATUS_DISABLED + * `1` - STATUS_ENABLED + * `2` - STATUS_DEFAULT (inheritance of its parent's value. If there is no parent, the values used will be that of Centreon Engine) + example: 2 + is_contact_additive_inheritance: + type: boolean + description: | + Only used when notification inheritance for hosts and services is set to vertical inheritance only. + + When enabled, the contactgroup definition will not override the definitions on template levels, it will be appended instead. + is_contact_group_additive_inheritance: + type: boolean + description: | + Only used when notification inheritance for hosts and services is set to vertical inheritance only. + + When enabled, the contact definition will not override the definitions on template levels, it will be appended instead. + notification_interval: + type: integer + nullable: true + description: | + Define the number of "time units" to wait before re-notifying a contact that this service is still down or unreachable. + + With the default time unit of 60s, this number will mean multiples of 1 minute. + + A value of 0 disables re-notifications of contacts about alerts for this service - only one alert notification will be sent out. + notification_timeperiod_id: + type: integer + description: "Notification timeperiod ID." + minimum: 1 + nullable: true + example: 1 + notification_type: + type: integer + description: | + Define the states of the service for which notifications should be sent out. + + The value is the sum of all the values of the selected options. + + * `0` - NONE + * `1` - WARNING + * `2` - UNKNOWN + * `4` - CRITICAL + * `8` - RECOVERY + * `16` - FLAPPING + * `32` - DOWNTIME_SCHEDULED + * NULL - (inheritance of its parent's value. If there is no parent, + the value will be assumed to be: WARNING|UNKNOWN|CRITICAL|RECOVERY|FLAPPING|DOWNTIME_SCHEDULED) + + example: A value equal to 5 corresponds to the selected options WARNING and CRITICAL + example: 5 + first_notification_delay: + type: integer + nullable: true + description: | + Define the number of "time units" to wait before sending out the first problem notification when this service enters a non-OK state. + + With the default time unit of 60s, this number will mean multiples of 1 minute. + recovery_notification_delay: + type: integer + nullable: true + description: | + Define the number of "time units" to wait before sending out the recovery notification when this service enters an OK state. + + With the default time unit of 60s, this number will mean multiples of 1 minute. + acknowledgement_timeout: + type: integer + description: "Specify a duration of acknowledgement for this service." + nullable: true + freshness_checked: + type: integer + description: | + Indicates whether freshness is checked or not + + * `0` - STATUS_DISABLED + * `1` - STATUS_ENABLED + * `2` - STATUS_DEFAULT (inheritance of its parent's value. If there is no parent, the values used will be that of Centreon Engine) + example: 2 + freshness_threshold: + type: integer + description: "Specify the freshness threshold (in seconds) for this service." + nullable: true + flap_detection_enabled: + type: integer + description: | + Indicates whether the flap detection is enabled or not + + * `0` - STATUS_DISABLED + * `1` - STATUS_ENABLED + * `2` - STATUS_DEFAULT (inheritance of its parent's value. If there is no parent, the values used will be that of Centreon Engine) + example: 2 + low_flap_threshold: + type: integer + description: "Specify the low state change threshold used in flap detection for this service." + nullable: true + high_flap_threshold: + type: integer + description: "Specify the high state change threshold used in flap detection for this service." + nullable: true + event_handler_enabled: + type: integer + description: | + Indicates whether the event handler is enabled or not + + * `0` - STATUS_DISABLED + * `1` - STATUS_ENABLED + * `2` - STATUS_DEFAULT (inheritance of its parent's value. If there is no parent, the values used will be that of Centreon Engine) + example: 2 + event_handler_command_id: + type: integer + description: "Event handler command ID." + minimum: 1 + nullable: true + example: 1 + event_handler_command_args: + type: array + items: + type: string + description: "Command arguments of the event handler." + example: [ "80", "90" ] + graph_template_id: + type: integer + description: "ID of the default graph template that will be used for this service." + minimum: 1 + nullable: true + example: null + note: + type: string + description: "Define an optional note." + nullable: true + maxLength: 65535 + note_url: + type: string + description: "Define an optional URL that can be used to provide more information about the service." + maxLength: 65535 + nullable: true + action_url: + type: string + description: "Define an optional URL that can be used to specify actions to be performed on the service." + nullable: true + maxLength: 65535 + icon_id: + type: integer + description: "Define the image ID that should be associated with this service." + minimum: 1 + nullable: true + example: null + icon_alternative: + type: string + description: "Define an optional string that is used as an alternative description for the icon." + nullable: true + maxLength: 200 + severity_id: + type: integer + description: "Severity ID." + minimum: 1 + nullable: true + is_activated: + type: boolean + description: "Indicates whether the service is activated or not" + example: true diff --git a/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/AddOneAndFindTimePeriods.yaml b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/AddOneAndFindTimePeriods.yaml new file mode 100644 index 0000000000..0242bc7cc1 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/AddOneAndFindTimePeriods.yaml @@ -0,0 +1,56 @@ +get: + tags: + - Time period + summary: "Get all time periods" + description: | + Get list of all time periods + + The available parameters to **search** / **sort_by** are: + + * id + * name + * alias + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + result: + type: array + items: + $ref: 'Schema/FindTimePeriodResponse.yaml' + meta: + $ref: '../../Common/Schema/Meta.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' +post: + tags: + - Time period + summary: "Create a new time period" + requestBody: + required: true + content: + application/json: + schema: + $ref: 'Schema/AddTimePeriodRequest.yaml' + responses: + '201': + description: "Time period created" + content: + application/json: + schema: + type: object + $ref: 'Schema/FindTimePeriodResponse.yaml' + '422': + $ref: '../../Common/Response/UnprocessableContent.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '409': + $ref: '../../Common/Response/Conflict.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/AddTimePeriodRequest.yaml b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/AddTimePeriodRequest.yaml new file mode 100644 index 0000000000..87aa8809f7 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/AddTimePeriodRequest.yaml @@ -0,0 +1,24 @@ +type: object +properties: + name: + type: string + description: "Time period name." + example: "24x7" + alias: + type: string + description: "Time period alias." + example: "Always" + days: + type: array + items: + $ref: "Day.yaml" + templates: + type: array + items: + type: integer + description: "Template ID." + example: 1 + exceptions: + type: array + items: + $ref: "ExtraTimePeriod.yaml" diff --git a/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/Day.yaml b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/Day.yaml new file mode 100644 index 0000000000..155879628b --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/Day.yaml @@ -0,0 +1,12 @@ +type: object +properties: + day: + type: integer + description: Number of the day (1=monday) + example: 1 + minimum: 1 + maximum: 7 + time_range: + type: string + description: "Time range for the day" + example: "00:00-06:00,07:00-08:00" diff --git a/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/ExtraTimePeriod.yaml b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/ExtraTimePeriod.yaml new file mode 100644 index 0000000000..0ac9bda638 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/ExtraTimePeriod.yaml @@ -0,0 +1,18 @@ +type: object +properties: + day_range: + type: string + description: | + Directives, including weekdays, days of the month, and calendar dates + + * Calendar date (2008-01-01) + * Specific month date (January 1st) + * Generic month date (Day 15) + * Offset weekday of specific month (2nd Tuesday in December) + * Offset weekday (3rd Monday) + * Normal weekday (Tuesday) + example: "monday 1" + time_range: + type: string + description: "Time range for the day" + example: "00:00-06:00,07:00-08:00" diff --git a/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/FindTimePeriodResponse.yaml b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/FindTimePeriodResponse.yaml new file mode 100644 index 0000000000..7094f7e061 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Configuration/TimePeriod/Schema/FindTimePeriodResponse.yaml @@ -0,0 +1,44 @@ +type: object +properties: + id: + type: integer + description: "Time period ID" + example: 1 + name: + type: string + description: "Name of the time period" + example: 24x7 + alias: + type: string + description: "Alias of the time period" + example: Always + days: + type: array + items: + $ref: "Day.yaml" + templates: + type: array + description: "IDs of the time periods used as a template" + items: + type: object + properties: + id: + type: integer + description: "ID of the time periods used as a template" + example: 1 + alias: + type: string + description: "Alias of the time period" + example: "Always" + exceptions: + type: array + description: "List of exceptions to the standard schedule" + items: + allOf: + - type: object + properties: + id: + type: integer + description: "ID of the extra period." + example: 1 + - $ref: "ExtraTimePeriod.yaml" diff --git a/centreon/doc/API/latest/onPremise/Configuration/Users/Schema/CurrentParameters.Get.yaml b/centreon/doc/API/latest/onPremise/Configuration/Users/Schema/CurrentParameters.Get.yaml index f566a589a1..d6250385e6 100644 --- a/centreon/doc/API/latest/onPremise/Configuration/Users/Schema/CurrentParameters.Get.yaml +++ b/centreon/doc/API/latest/onPremise/Configuration/Users/Schema/CurrentParameters.Get.yaml @@ -36,6 +36,11 @@ properties: description: If the current user is an administrator example: true + can_manage_api_tokens: + type: boolean + description: If the current user has ACL action "Manage API Tokens" + example: true + use_deprecated_pages: type: boolean description: Indicates if user wants to use deprecated monitoring pages diff --git a/centreon/doc/API/latest/onPremise/Configuration/Users/Users.yaml b/centreon/doc/API/latest/onPremise/Configuration/Users/Users.yaml index f1fbb64c48..8a2c69c2f6 100644 --- a/centreon/doc/API/latest/onPremise/Configuration/Users/Users.yaml +++ b/centreon/doc/API/latest/onPremise/Configuration/Users/Users.yaml @@ -11,6 +11,7 @@ get: * alias * name * email + * is_admin responses: '200': description: OK diff --git a/centreon/doc/API/latest/onPremise/Realtime/Hosts/FindHostsStatus.yaml b/centreon/doc/API/latest/onPremise/Realtime/Hosts/FindHostsStatus.yaml new file mode 100644 index 0000000000..a3ef2c95af --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Realtime/Hosts/FindHostsStatus.yaml @@ -0,0 +1,32 @@ +get: + tags: + - Host + summary: "Count hosts by status" + description: | + Count hosts by their status (UP/DOWN/UNREACHABLE/PENDING) + + The available parameters to **search** / **sort_by** are: + + * name + * status + * service.name + * service.id + * host_category.name + * host_category.id + * host_group.name + * host_group.id + * service_group.name + * service_group.id + * service_category.name + * service_category.id + responses: + '200': + description: "OK" + content: + application/json: + schema: + $ref: 'Schema/HostsStatus.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Realtime/Hosts/Schema/HostsStatus.yaml b/centreon/doc/API/latest/onPremise/Realtime/Hosts/Schema/HostsStatus.yaml new file mode 100644 index 0000000000..2baf0754ad --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Realtime/Hosts/Schema/HostsStatus.yaml @@ -0,0 +1,24 @@ +type: object +properties: + up: + type: object + properties: + total: + type: integer + down: + type: object + properties: + total: + type: integer + unreachable: + type: object + properties: + total: + type: integer + pending: + type: object + properties: + total: + type: integer + total: + type: integer diff --git a/centreon/doc/API/latest/onPremise/Realtime/Resources/FindHostsStatus.yaml b/centreon/doc/API/latest/onPremise/Realtime/Resources/FindHostsStatus.yaml deleted file mode 100644 index ca53ef0543..0000000000 --- a/centreon/doc/API/latest/onPremise/Realtime/Resources/FindHostsStatus.yaml +++ /dev/null @@ -1,25 +0,0 @@ -get: - tags: - - Resource - summary: "Count hosts by status" - description: | - Count hosts by their status (UP/DOWN/UNREACHABLE/PENDING) - - The available parameters to **search** / **sort_by** are: - - * name - - parameters: - - $ref: 'QueryParameter/FilterHostgroupName.yaml' - - $ref: 'QueryParameter/FilterHostCategoryName.yaml' - responses: - '200': - description: "OK" - content: - application/json: - schema: - $ref: 'Schema/HostsStatus.yaml' - '403': - $ref: '../../Common/Response/Forbidden.yaml' - '500': - $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Realtime/Resources/FindServicesStatus.yaml b/centreon/doc/API/latest/onPremise/Realtime/Resources/FindServicesStatus.yaml deleted file mode 100644 index c0237e781e..0000000000 --- a/centreon/doc/API/latest/onPremise/Realtime/Resources/FindServicesStatus.yaml +++ /dev/null @@ -1,27 +0,0 @@ -get: - tags: - - Resource - summary: "Count hosts by status" - description: | - Count hosts by their status (UP/DOWN/UNREACHABLE/PENDING) - - The available parameters to **search** / **sort_by** are: - - * name - - parameters: - - $ref: 'QueryParameter/FilterHostgroupName.yaml' - - $ref: 'QueryParameter/FilterHostCategoryName.yaml' - - $ref: 'QueryParameter/FilterServicegroupName.yaml' - - $ref: 'QueryParameter/FilterServiceCategoryName.yaml' - responses: - '200': - description: "OK" - content: - application/json: - schema: - $ref: 'Schema/ServicesStatus.yaml' - '403': - $ref: '../../Common/Response/Forbidden.yaml' - '500': - $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/HostsStatus.yaml b/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/HostsStatus.yaml deleted file mode 100644 index b13e6be701..0000000000 --- a/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/HostsStatus.yaml +++ /dev/null @@ -1,24 +0,0 @@ -type: object -properties: - up: - type: object - properties: - total: - type: int - down: - type: object - properties: - total: - type: int - unreachable: - type: object - properties: - total: - type: int - pending: - type: object - properties: - total: - type: int - total: - type: int \ No newline at end of file diff --git a/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/ResourcesByParent.yaml b/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/ResourcesByParent.yaml index 15c8250eb7..1c720cce8d 100644 --- a/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/ResourcesByParent.yaml +++ b/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/ResourcesByParent.yaml @@ -5,6 +5,10 @@ allOf: type: string description: "Parent Resource name" example: "Central" + extra: + type: array + items: + type: object children: type: object properties: @@ -51,6 +55,10 @@ allOf: format: int32 description: "ID of the service behind the resource" example: 12 + extra: + type: array + items: + type: object parent: type: object properties: @@ -59,4 +67,8 @@ allOf: format: int32 description: "ID of the parent" example: 12 + extra: + type: array + items: + type: object diff --git a/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/ServicesStatus.yaml b/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/ServicesStatus.yaml deleted file mode 100644 index 0797e1a8df..0000000000 --- a/centreon/doc/API/latest/onPremise/Realtime/Resources/Schema/ServicesStatus.yaml +++ /dev/null @@ -1,29 +0,0 @@ -type: object -properties: - critical: - type: object - properties: - total: - type: int - unknown: - type: object - properties: - total: - type: int - ok: - type: object - properties: - total: - type: int - down: - type: object - properties: - total: - type: int - pending: - type: object - properties: - total: - type: int - total: - type: int \ No newline at end of file diff --git a/centreon/doc/API/latest/onPremise/Realtime/Services/FindServicesStatus.yaml b/centreon/doc/API/latest/onPremise/Realtime/Services/FindServicesStatus.yaml new file mode 100644 index 0000000000..378af684a7 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Realtime/Services/FindServicesStatus.yaml @@ -0,0 +1,32 @@ +get: + tags: + - Service + summary: "Count services by status" + description: | + Count services by their status (OK/WARNING/CRITICAL/UNKNOWN/PENDING) + + The available parameters to **search** / **sort_by** are: + + * name + * status + * host.name + * host.id + * host_category.name + * host_category.id + * host_group.name + * host_group.id + * service_group.name + * service_group.id + * service_category.name + * service_category.id + responses: + '200': + description: "OK" + content: + application/json: + schema: + $ref: 'Schema/ServicesStatus.yaml' + '403': + $ref: '../../Common/Response/Forbidden.yaml' + '500': + $ref: '../../Common/Response/InternalServerError.yaml' diff --git a/centreon/doc/API/latest/onPremise/Realtime/Services/Schema/ServicesStatus.yaml b/centreon/doc/API/latest/onPremise/Realtime/Services/Schema/ServicesStatus.yaml new file mode 100644 index 0000000000..194ff62199 --- /dev/null +++ b/centreon/doc/API/latest/onPremise/Realtime/Services/Schema/ServicesStatus.yaml @@ -0,0 +1,29 @@ +type: object +properties: + critical: + type: object + properties: + total: + type: integer + unknown: + type: object + properties: + total: + type: integer + ok: + type: object + properties: + total: + type: integer + down: + type: object + properties: + total: + type: integer + pending: + type: object + properties: + total: + type: integer + total: + type: integer diff --git a/centreon/features/KnowledgeBase.feature b/centreon/features/KnowledgeBase.feature index 39c1564897..182c314036 100644 --- a/centreon/features/KnowledgeBase.feature +++ b/centreon/features/KnowledgeBase.feature @@ -1,3 +1,4 @@ +@system Feature: Knowledge Base As a Centreon user I want to link my hosts and services supervised to wiki s procedures diff --git a/centreon/features/Ldap.feature b/centreon/features/Ldap.feature index 523d050a20..0b880d26cb 100644 --- a/centreon/features/Ldap.feature +++ b/centreon/features/Ldap.feature @@ -1,5 +1,4 @@ -#features/Ldap.feature - +@system Feature: LDAP As a company administrator I want my users to access Centreon using LDAP credentials diff --git a/centreon/features/LdapManualImport.feature b/centreon/features/LdapManualImport.feature index 5db661ca4d..b5c8d56821 100644 --- a/centreon/features/LdapManualImport.feature +++ b/centreon/features/LdapManualImport.feature @@ -1,3 +1,4 @@ +@system Feature: LDAPManualImport As a company administrator I want to import manually users diff --git a/centreon/features/Partitioning.feature b/centreon/features/Partitioning.feature index 658f3d07bb..65c8e36270 100644 --- a/centreon/features/Partitioning.feature +++ b/centreon/features/Partitioning.feature @@ -1,3 +1,4 @@ +@system Feature: Database partitioning As a Centreon user I want to clean database tables quickly diff --git a/centreon/features/bootstrap/DowntimeRecurrentContext.php b/centreon/features/bootstrap/DowntimeRecurrentContext.php index 950987b5f9..a37eb3e111 100644 --- a/centreon/features/bootstrap/DowntimeRecurrentContext.php +++ b/centreon/features/bootstrap/DowntimeRecurrentContext.php @@ -1,11 +1,11 @@ 'host', 'alias' => 'host', - 'address' => 'host2@localhost', + 'address' => '1.2.3.4', 'check_command' => 'check_centreon_dummy', 'location' => 'Europe/Paris' ); diff --git a/centreon/features/bootstrap/EscalationConfigurationContext.php b/centreon/features/bootstrap/EscalationConfigurationContext.php index e98433959b..342dcdf68a 100644 --- a/centreon/features/bootstrap/EscalationConfigurationContext.php +++ b/centreon/features/bootstrap/EscalationConfigurationContext.php @@ -1,11 +1,11 @@ 'hostName', 'alias' => 'hostAlias', - 'address' => 'host@localhost' + 'address' => '1.2.3.4' ); protected $metaService1 = array( diff --git a/centreon/features/bootstrap/HostCategoryConfigurationContext.php b/centreon/features/bootstrap/HostCategoryConfigurationContext.php index c25e31e814..475f38b381 100644 --- a/centreon/features/bootstrap/HostCategoryConfigurationContext.php +++ b/centreon/features/bootstrap/HostCategoryConfigurationContext.php @@ -1,8 +1,8 @@ 'host1Name', 'alias' => 'host1Alias', - 'address' => 'host1@localhost' + 'address' => '1.2.3.4' ); protected $host2 = array( 'name' => 'host2Name', 'alias' => 'host2Alias', - 'address' => 'host2@localhost' + 'address' => '2.3.4.5' ); protected $hostTemplate1 = array( diff --git a/centreon/features/bootstrap/HostConfigurationContext.php b/centreon/features/bootstrap/HostConfigurationContext.php index 7f70ebbf67..d2e5121437 100644 --- a/centreon/features/bootstrap/HostConfigurationContext.php +++ b/centreon/features/bootstrap/HostConfigurationContext.php @@ -15,13 +15,13 @@ class HostConfigurationContext extends CentreonContext protected $host2 = array( 'name' => 'hostName2', 'alias' => 'hostAlias2', - 'address' => 'host2@localhost' + 'address' => '2.3.4.5' ); protected $host3 = array( 'name' => 'hostName3', 'alias' => 'hostAlias3', - 'address' => 'host3@localhost' + 'address' => '3.4.5.6' ); protected $hostGroup1 = array( @@ -60,7 +60,7 @@ class HostConfigurationContext extends CentreonContext protected $initialProperties = array( 'name' => 'hostName', 'alias' => 'hostAlias', - 'address' => 'host@localhost', + 'address' => '1.2.3.4', 'snmp_community' => 'hostSnmpCommunity', 'snmp_version' => '1', 'location' => 'America/Caracas', @@ -68,7 +68,7 @@ class HostConfigurationContext extends CentreonContext 'generic-host' ), 'check_command' => 'check_http', - 'command_arguments' => 'hostCommandArgument', + 'command_arguments' => '!hostCommandArgument', 'check_period' => 'workhours', 'max_check_attempts' => 34, 'normal_check_interval' => 5, @@ -100,7 +100,7 @@ class HostConfigurationContext extends CentreonContext 'high_flap_threshold' => 85, 'event_handler_enabled' => 2, 'event_handler' => 'check_https', - 'event_handler_arguments' => 'event_handler_arguments', + 'event_handler_arguments' => '!event_handler_arguments', 'url' => 'hostMassiveChangeUrl', 'notes' => 'hostMassiveChangeNotes', 'action_url' => 'hostMassiveChangeActionUrl', @@ -114,7 +114,7 @@ class HostConfigurationContext extends CentreonContext protected $duplicatedProperties = array( 'name' => 'hostName_1', 'alias' => 'hostAlias', - 'address' => 'host@localhost', + 'address' => '1.2.3.4', 'snmp_community' => self::PASSWORD_REPLACEMENT_VALUE, 'snmp_version' => '1', 'location' => 'America/Caracas', @@ -122,7 +122,7 @@ class HostConfigurationContext extends CentreonContext 'generic-host' ), 'check_command' => 'check_http', - 'command_arguments' => 'hostCommandArgument', + 'command_arguments' => '!hostCommandArgument', 'check_period' => 'workhours', 'max_check_attempts' => 34, 'normal_check_interval' => 5, @@ -154,7 +154,7 @@ class HostConfigurationContext extends CentreonContext 'high_flap_threshold' => 85, 'event_handler_enabled' => 2, 'event_handler' => 'check_https', - 'event_handler_arguments' => 'event_handler_arguments', + 'event_handler_arguments' => '!event_handler_arguments', 'url' => 'hostMassiveChangeUrl', 'notes' => 'hostMassiveChangeNotes', 'action_url' => 'hostMassiveChangeActionUrl', @@ -168,7 +168,7 @@ class HostConfigurationContext extends CentreonContext protected $updatedProperties = array( 'name' => 'hostNameChanged', 'alias' => 'hostAliasChanged', - 'address' => 'hostChanged@localhost', + 'address' => '4.3.2.1', 'snmp_community' => self::PASSWORD_REPLACEMENT_VALUE, 'snmp_version' => '3', 'macros' => array( @@ -179,7 +179,7 @@ class HostConfigurationContext extends CentreonContext 'hostTemplateName' ), 'check_command' => 'check_https', - 'command_arguments' => 'hostCommandArgumentChanged', + 'command_arguments' => '!hostCommandArgumentChanged', 'check_period' => 'none', 'max_check_attempts' => 43, 'normal_check_interval' => 4, @@ -211,7 +211,7 @@ class HostConfigurationContext extends CentreonContext 'high_flap_threshold' => 51, 'event_handler_enabled' => 1, 'event_handler' => 'check_http', - 'event_handler_arguments' => 'eventHandlerArgumentsChanged', + 'event_handler_arguments' => '!eventHandlerArgumentsChanged', 'url' => 'hostMassiveChangeUrlChanged', 'notes' => 'hostMassiveChangeNotesChanged', 'action_url' => 'hostMassiveChangeActionUrlChanged', diff --git a/centreon/features/bootstrap/HostDependencyConfigurationContext.php b/centreon/features/bootstrap/HostDependencyConfigurationContext.php index 6119f7b5f2..8079894e0b 100644 --- a/centreon/features/bootstrap/HostDependencyConfigurationContext.php +++ b/centreon/features/bootstrap/HostDependencyConfigurationContext.php @@ -1,9 +1,9 @@ 'host1Name', 'alias' => 'host1Alias', - 'address' => 'host1@localhost' + 'address' => '1.2.3.4' ); protected $host2 = array( 'name' => 'host2Name', 'alias' => 'host2Alias', - 'address' => 'host2@localhost' + 'address' => '2.3.4.5' ); protected $host3 = array( 'name' => 'host3Name', 'alias' => 'host3Alias', - 'address' => 'host3@localhost' + 'address' => '3.4.5.6' ); protected $initialProperties = array( diff --git a/centreon/features/bootstrap/HostGroupConfigurationContext.php b/centreon/features/bootstrap/HostGroupConfigurationContext.php index 104e000b84..0a57c5e9ba 100644 --- a/centreon/features/bootstrap/HostGroupConfigurationContext.php +++ b/centreon/features/bootstrap/HostGroupConfigurationContext.php @@ -1,9 +1,9 @@ 'host1Name', 'alias' => 'host1Alias', - 'address' => 'host1@localhost' + 'address' => '1.2.3.4' ); protected $host2 = array( 'name' => 'host2Name', 'alias' => 'host2Alias', - 'address' => 'host2@localhost' + 'address' => '2.3.4.5' ); protected $initialProperties = array( diff --git a/centreon/features/bootstrap/MassiveChangeHostsContext.php b/centreon/features/bootstrap/MassiveChangeHostsContext.php index 553b56e884..feecfed3a9 100644 --- a/centreon/features/bootstrap/MassiveChangeHostsContext.php +++ b/centreon/features/bootstrap/MassiveChangeHostsContext.php @@ -15,19 +15,19 @@ class MassiveChangeHostsContext extends CentreonContext protected $host1 = array( 'name' => 'host1Name', 'alias' => 'host1Alias', - 'address' => 'host1@localhost' + 'address' => '1.2.3.4' ); protected $host2 = array( 'name' => 'host2Name', 'alias' => 'host2Alias', - 'address' => 'host2@localhost' + 'address' => '2.3.4.5' ); protected $host3 = array( 'name' => 'host3Name', 'alias' => 'host3Alias', - 'address' => 'host3@localhost' + 'address' => '3.4.5.6' ); protected $hostGroup = array( @@ -59,7 +59,7 @@ class MassiveChangeHostsContext extends CentreonContext 'generic-host' ), 'service_linked_to_template' => 0, - 'command_arguments' => 'hostCommandArgument', + 'command_arguments' => '!hostCommandArgument', 'macros' => array( 'HOSTMACRONAME' => '22' ), @@ -103,7 +103,7 @@ class MassiveChangeHostsContext extends CentreonContext 'high_flap_threshold' => 85, 'event_handler_enabled' => 2, 'event_handler' => 'check_https', - 'event_handler_arguments' => 'event_handler_arguments', + 'event_handler_arguments' => '!event_handler_arguments', 'url' => 'hostMassiveChangeUrl', 'notes' => 'hostMassiveChangeNotes', 'action_url' => 'hostMassiveChangeActionUrl', @@ -117,7 +117,7 @@ class MassiveChangeHostsContext extends CentreonContext protected $updatedHost1 = array( 'name' => 'host1Name', 'alias' => 'host1Alias', - 'address' => 'host1@localhost', + 'address' => '1.2.3.4', 'snmp_community' => 'snmp', 'snmp_version' => '2c', 'monitored_from' => 'Central', @@ -127,7 +127,7 @@ class MassiveChangeHostsContext extends CentreonContext ), 'service_linked_to_template' => 0, 'check_command' => 'check_http', - 'command_arguments' => 'hostCommandArgument', + 'command_arguments' => '!hostCommandArgument', 'macros' => array( 'HOSTMACRONAME' => '22' ), @@ -162,7 +162,7 @@ class MassiveChangeHostsContext extends CentreonContext 'high_flap_threshold' => 85, 'event_handler_enabled' => 2, 'event_handler' => 'check_https', - 'event_handler_arguments' => 'event_handler_arguments', + 'event_handler_arguments' => '!event_handler_arguments', 'url' => 'hostMassiveChangeUrl', 'notes' => 'hostMassiveChangeNotes', 'action_url' => 'hostMassiveChangeActionUrl', @@ -176,7 +176,7 @@ class MassiveChangeHostsContext extends CentreonContext protected $updatedHost2 = array( 'name' => 'host2Name', 'alias' => 'host2Alias', - 'address' => 'host2@localhost', + 'address' => '2.3.4.5', 'snmp_community' => 'snmp', 'snmp_version' => '2c', 'monitored_from' => 'Central', @@ -186,7 +186,7 @@ class MassiveChangeHostsContext extends CentreonContext ), 'service_linked_to_template' => 0, 'check_command' => 'check_http', - 'command_arguments' => 'hostCommandArgument', + 'command_arguments' => '!hostCommandArgument', 'macros' => array( 'HOSTMACRONAME' => '22' ), @@ -221,7 +221,7 @@ class MassiveChangeHostsContext extends CentreonContext 'high_flap_threshold' => 85, 'event_handler_enabled' => 2, 'event_handler' => 'check_https', - 'event_handler_arguments' => 'event_handler_arguments', + 'event_handler_arguments' => '!event_handler_arguments', 'url' => 'hostMassiveChangeUrl', 'notes' => 'hostMassiveChangeNotes', 'action_url' => 'hostMassiveChangeActionUrl', diff --git a/centreon/features/bootstrap/MassiveChangeServicesContext.php b/centreon/features/bootstrap/MassiveChangeServicesContext.php index 7a16400ff4..b6e8fb6da1 100644 --- a/centreon/features/bootstrap/MassiveChangeServicesContext.php +++ b/centreon/features/bootstrap/MassiveChangeServicesContext.php @@ -1,14 +1,14 @@ 'host1Name', 'alias' => 'host1Alias', - 'address' => 'host1@localhost' + 'address' => '1.2.3.4' ); protected $host2 = array( 'name' => 'host2Name', 'alias' => 'host2Alias', - 'address' => 'host2@localhost' + 'address' => '2.3.4.5' ); protected $host3 = array( 'name' => 'host3Name', 'alias' => 'host3Alias', - 'address' => 'host3@localhost' + 'address' => '3.4.5.6' ); protected $service1 = array( diff --git a/centreon/features/bootstrap/ServiceConfigurationContext.php b/centreon/features/bootstrap/ServiceConfigurationContext.php index be61f6a181..aff926c57c 100644 --- a/centreon/features/bootstrap/ServiceConfigurationContext.php +++ b/centreon/features/bootstrap/ServiceConfigurationContext.php @@ -1,10 +1,10 @@ 'hostName', 'alias' => 'hostAlias', - 'address' => 'host@localhost' + 'address' => '1.2.3.4' ); protected $serviceCategory1 = array( diff --git a/centreon/features/bootstrap/ServiceDependencyConfigurationContext.php b/centreon/features/bootstrap/ServiceDependencyConfigurationContext.php index b784b08f49..6525d550b9 100644 --- a/centreon/features/bootstrap/ServiceDependencyConfigurationContext.php +++ b/centreon/features/bootstrap/ServiceDependencyConfigurationContext.php @@ -1,9 +1,9 @@ 'hostName', 'alias' => 'hostAlias', - 'address' => 'host@localhost' + 'address' => '1.2.3.4' ); protected $initialProperties = array( diff --git a/centreon/features/bootstrap/ServiceTemplateConfigurationContext.php b/centreon/features/bootstrap/ServiceTemplateConfigurationContext.php index 0d0a962518..ee41cc8481 100644 --- a/centreon/features/bootstrap/ServiceTemplateConfigurationContext.php +++ b/centreon/features/bootstrap/ServiceTemplateConfigurationContext.php @@ -1,10 +1,10 @@ 'hostName', 'alias' => 'hostAlias', - 'address' => 'host@localhost' + 'address' => '1.2.3.4' ); protected $serviceCategory1 = array( diff --git a/centreon/features/bootstrap/TrapsSNMPConfigurationContext.php b/centreon/features/bootstrap/TrapsSNMPConfigurationContext.php index 083792e95c..051f481340 100644 --- a/centreon/features/bootstrap/TrapsSNMPConfigurationContext.php +++ b/centreon/features/bootstrap/TrapsSNMPConfigurationContext.php @@ -1,14 +1,14 @@ currentPage->setProperties(array( 'name' => 'hostName', 'alias' => 'hostName', - 'address' => 'host@localhost' + 'address' => '1.2.3.4' )); $this->currentPage->save(); $this->currentPage = new CommandConfigurationPage($this); @@ -200,7 +200,7 @@ public function iModifySomePropertiesOfAnExistingSNMPTrapDefinition() $this->currentPage->setProperties(array( 'name' => 'hostName', 'alias' => 'hostName', - 'address' => 'host@localhost' + 'address' => '1.2.3.4' )); $this->currentPage->save(); $this->currentPage = new CommandConfigurationPage($this); @@ -291,7 +291,7 @@ public function iHaveDuplicatedOneExistingSNMPTrapDefinition() $this->currentPage->setProperties(array( 'name' => 'hostName', 'alias' => 'hostName', - 'address' => 'host@localhost' + 'address' => '1.2.3.4' )); $this->currentPage->save(); $this->currentPage = new CommandConfigurationPage($this); diff --git a/centreon/lang/de_DE.UTF-8/LC_MESSAGES/messages.po b/centreon/lang/de_DE.UTF-8/LC_MESSAGES/messages.po index 6624019985..6dd99e9a74 100644 --- a/centreon/lang/de_DE.UTF-8/LC_MESSAGES/messages.po +++ b/centreon/lang/de_DE.UTF-8/LC_MESSAGES/messages.po @@ -16596,7 +16596,7 @@ msgstr "Erweiterter Modus" # msgid "The resource access rule was successfully deleted" # msgstr "" -# msgid "Error while adding a broker output" +# msgid "Error while adding a Broker input/output" # msgstr "" # msgid "You are not allowed to edit a broker configuration" @@ -16605,7 +16605,7 @@ msgstr "Erweiterter Modus" # msgid "Broker configuration #%d not found" # msgstr "" -# msgid "Missing output parameter: %s" +# msgid "Missing input/output parameter: %s" # msgstr "" # msgid "Parameter '%s' (%s) is invalid" @@ -16614,7 +16614,7 @@ msgstr "Erweiterter Modus" # msgid "Parameter '%s' of type %s is invalid" # msgstr "" -# msgid "Output #%d not found for broker configuration #%d" +# msgid "Input/Output #%d not found for Broker configuration #%d" # msgstr "" # msgid "Displays a detailed view of the current status for selected resources as a chart." @@ -16745,7 +16745,7 @@ msgstr "Erweiterter Modus" # msgid "All resources selected" # msgstr "" -# msgid "Error while updating a broker output" +# msgid "Error while updating a Broker input/output" # msgstr "" # msgid "Action not permitted for output of type '%s'" @@ -17007,3 +17007,326 @@ msgstr "Erweiterter Modus" # msgid "Tooltip" # msgstr "" + +# msgid "Add filter" +# msgstr "" + +# msgid "Add resource dataset" +# msgstr "" + +# msgid "Line" +# msgstr "" + +# msgid "Bar" +# msgstr "" + +# msgid "Stacked bar" +# msgstr "" + +# msgid "Orientation" +# msgstr "" + +# msgid "Bar radius" +# msgstr "" + +# msgid "Bar background opacity" +# msgstr "" + +# msgid "Check command sent!" +# msgstr "" + +# msgid "Forced check command sent!" +# msgstr "" + +# msgid "Open ticket" +# msgstr "Ouvrir un ticket" + +# msgid "Open ticket for host" +# msgstr "" + +# msgid "Open ticket for service" +# msgstr "" + +# msgid "Host severities" +# msgstr "" + +# msgid "Service severities" +# msgstr "" + +# msgid "Select service severities" +# msgstr "" + +# msgid "Select host severities" +# msgstr "" + +# msgid "Enable Open Tickets" +# msgstr "" + +# msgid "Ticket provider" +# msgstr "" + +# msgid "Select a provider" +# msgstr "" + +# msgid "Display resources" +# msgstr "" + +# msgid "Resources linked to a ticket" +# msgstr "" + +# msgid "Resources with no ticket" +# msgstr "" + +# msgid "Hide services with Down host" +# msgstr "" + +# msgstr "hide services with Unreachable host" +# msgstr "" + +# msgstr "Ticket ID" +# msgstr "" + +# msgstr "Ticket subject" +# msgstr "" + +# msgstr "Opened on" +# msgstr "" + + +# msgid "Create a ticket" +# msgstr "" + +# msgid "Rule (ticket provider)" +# msgstr "" + +# msgid "Select rule (ticket provider)" +# msgstr "" + +# msgid "Display resources with these status types" +# msgstr "" + +# msgid "All KPIs on this Business Activity are working fine." +# msgstr "" + +# msgid "are working fine." +# msgstr "" + +# msgid "See more information in the geoview" +# msgstr "" + +# msgid "Calculation method" +# msgstr "" + +# msgid "State information" +# msgstr "" + +# msgid "Warning threshold" +# msgstr "" + +# msgid "Critical threshold" +# msgstr "" + +# msgid "Click here for details" +# msgstr "" + +# msgid "Expression in" +# msgstr "" + +# msgid "Impact applied when:" +# msgstr "" + +# msgid "true" +# msgstr "" + +# msgid "false" +# msgstr "" + +# msgid "No KPI found" +# msgstr "" + +# msgid "No Business Activity found" +# msgstr "" + +# msgid "business activity" +# msgstr "" + +# msgid "Health" +# msgstr "" + +# msgid "Critical KPIs" +# msgstr "" + +# msgid "Additional connector configurations" +# msgstr "" + +# msgid "Types" +# msgstr "" + +# msgid "Updated by" +# msgstr "" + +# msgid "Edit connector configuration" +# msgstr "" + +# msgid "More filters" +# msgstr "" + +# msgid "Pollers" +# msgstr "" + +# msgid "Delete additional connector configuration" +# msgstr "" + +# msgid "The {{name}} additional connector configuration will be permanently deleted." +# msgstr "" + +# msgid "The corresponding connectors will not work anymore." +# msgstr "" + +# msgid "Additional connector configuration deleted" +# msgstr "" + +# msgid "Additional connector configuration duplicated" +# msgstr "" + +# msgid "Additional connector configuration created" +# msgstr "" + +# msgid "Additional connector configuration updated" +# msgstr "" + +# msgid "Duplicate connector configuration" +# msgstr "" + +# msgid "The name can be at most 50 characters long" +# msgstr "" + +# msgid "The name should be at least 3 characters long" +# msgstr "" + +# msgid "Create additional connector configuration" +# msgstr "" + +# msgid "Update additional connector configuration" +# msgstr "" + +# msgid "Select poller(s)" +# msgstr "" + +# msgid "Password" +# msgstr "" + +# msgid "Add parameter" +# msgstr "" + +# msgid "Url" +# msgstr "" + +# msgid "Username" +# msgstr "" + +# msgid "Add vCenter/ESX" +# msgstr "" + +# msgid "Remove vCenter/ESX" +# msgstr "" + +# msgid "At least one poller is required" +# msgstr "" + +# msgid "At least one vCenter is required" +# msgstr "" + +# msgid "Please enter a valid URL or IP address" +# msgstr "" + +# msgid "Invalid port number" +# msgstr "" + +# msgid "The name of the vCenter should be unique" +# msgstr "" + +# msgid "vCenter name" +# msgstr "" + +# msgid "Do you want to quit without saving the changes?" +# msgstr "" + +# msgid "Your form has unsaved changes" +# msgstr "" + + +# msgid "Error while adding an additional connector configuration" +# msgstr "" + +# msgid "You are not allowed to access additional connector configurations" +# msgstr "" + +# msgid "An additional connector configuration configuration of type '%s' is already associated with poller ID(s) '%s'" +# msgstr "" + +# msgid "Duplicates not allowed for property '%s'" +# msgstr "" + +# msgid "'%s' must contain at least one element" +# msgstr "" + +# msgid "Error while retrieving an additional connector configuration" +# msgstr "" + +# msgid "The additional connector configuration name '%s' already exists" +# msgstr "" + +# msgid "Error while deleting an additional connector configuration" +# msgstr "" + +# msgid "You don't have sufficient permissions for this action" +# msgstr "" + +# msgid "Error while searching for additional connector configurations" +# msgstr "" + +# msgid "Error while searching for available pollers for type '%s'" +# msgstr "" + +# msgid "Select time zone" +# msgstr "" + +# msgid "Select time format" +# msgstr "" + +# msgid "12 hours" +# msgstr "" + +# msgid "24 hours" +# msgstr "" + +# msgid "Ends at" +# msgstr "" + +# msgid "Time zone" +# msgstr "" + +# msgid "Date format" +# msgstr "" + +# msgid "Time format" +# msgstr "" + +# msgid "Countdown" +# msgstr "" + +# msgid "Timer" +# msgstr "" + +# msgid "Show time zone" +# msgstr "" + +# msgid "Show date" +# msgstr "" + +# msgid "Error while updating an additional connector configuration" +# msgstr "" + +# msgid "Changing type of an existing additional connector configuration is not allowed" +# msgstr "" diff --git a/centreon/lang/es_ES.UTF-8/LC_MESSAGES/messages.po b/centreon/lang/es_ES.UTF-8/LC_MESSAGES/messages.po index 90d73af2a1..f0ec63746e 100644 --- a/centreon/lang/es_ES.UTF-8/LC_MESSAGES/messages.po +++ b/centreon/lang/es_ES.UTF-8/LC_MESSAGES/messages.po @@ -16933,7 +16933,7 @@ msgstr "Modo avanzado" # msgid "The resource access rule was successfully deleted" # msgstr "" -# msgid "Error while adding a broker output" +# msgid "Error while adding a Broker input/output" # msgstr "" # msgid "You are not allowed to edit a broker configuration" @@ -16942,7 +16942,7 @@ msgstr "Modo avanzado" # msgid "Broker configuration #%d not found" # msgstr "" -# msgid "Missing output parameter: %s" +# msgid "Missing input/output parameter: %s" # msgstr "" # msgid "Parameter '%s' (%s) is invalid" @@ -16951,7 +16951,7 @@ msgstr "Modo avanzado" # msgid "Parameter '%s' of type %s is invalid" # msgstr "" -# msgid "Output #%d not found for broker configuration #%d" +# msgid "Input/Output #%d not found for Broker configuration #%d" # msgstr "" # msgid "Displays a detailed view of the current status for selected resources as a chart." @@ -17079,7 +17079,7 @@ msgstr "Modo avanzado" # msgid "All resources selected" # msgstr "" -# msgid "Error while updating a broker output" +# msgid "Error while updating a Broker input/output" # msgstr "" # msgid "Action not permitted for output of type '%s'" @@ -17341,3 +17341,325 @@ msgstr "Modo avanzado" # msgid "Tooltip" # msgstr "" + +# msgid "Add filter" +# msgstr "" + +# msgid "Add resource dataset" +# msgstr "" + +# msgid "Line" +# msgstr "" + +# msgid "Bar" +# msgstr "" + +# msgid "Stacked bar" +# msgstr "" + +# msgid "Orientation" +# msgstr "" + +# msgid "Bar radius" +# msgstr "" + +# msgid "Bar background opacity" +# msgstr "" + +# msgid "Check command sent!" +# msgstr "" + +# msgid "Forced check command sent!" +# msgstr "" + +# msgid "Open ticket" +# msgstr "" + +# msgid "Open ticket for host" +# msgstr "" + +# msgid "Open ticket for service" +# msgstr "" + +# msgid "Host severities" +# msgstr "" + +# msgid "Service severities" +# msgstr "" + +# msgid "Select service severities" +# msgstr "" + +# msgid "Select host severities" +# msgstr "" + +# msgid "Enable Open Tickets" +# msgstr "" + +# msgid "Ticket provider" +# msgstr "" + +# msgid "Select a provider" +# msgstr "" + +# msgid "Display resources" +# msgstr "" + +# msgid "Resources linked to a ticket" +# msgstr "" + +# msgid "Resources with no ticket" +# msgstr "" + +# msgid "Hide services with Down host" +# msgstr "" + +# msgstr "hide services with Unreachable host" +# msgstr "" + +# msgstr "Ticket ID" +# msgstr "" + +# msgstr "Ticket subject" +# msgstr "" + +# msgstr "Opened on" +# msgstr "" + +# msgid "Create a ticket" +# msgstr "" + +# msgid "Rule (ticket provider)" +# msgstr "" + +# msgid "Select rule (ticket provider)" +# msgstr "" + +# msgid "Display resources with these status types" +# msgstr "" + +# msgid "All KPIs on this Business Activity are working fine." +# msgstr "" + +# msgid "are working fine." +# msgstr "" + +# msgid "See more information in the geoview" +# msgstr "" + +# msgid "Calculation method" +# msgstr "" + +# msgid "State information" +# msgstr "" + +# msgid "Warning threshold" +# msgstr "" + +# msgid "Critical threshold" +# msgstr "" + +# msgid "Expression in" +# msgstr "" + +# msgid "Impact applied when:" +# msgstr "" + +# msgid "true" +# msgstr "" + +# msgid "false" +# msgstr "" + +# msgid "Click here for details" +# msgstr "" + +# msgid "No KPI found" +# msgstr "" + +# msgid "No Business Activity found" +# msgstr "" + +# msgid "business activity" +# msgstr "" + +# msgid "Health" +# msgstr "" + +# msgid "Critical KPIs" +# msgstr "" + +# msgid "Additional connector configurations" +# msgstr "" + +# msgid "Types" +# msgstr "" + +# msgid "Updated by" +# msgstr "" + +# msgid "Edit connector configuration" +# msgstr "" + +# msgid "More filters" +# msgstr "" + +# msgid "Pollers" +# msgstr "" + +# msgid "Delete additional connector configuration" +# msgstr "" + +# msgid "The {{name}} additional connector configuration will be permanently deleted." +# msgstr "" + +# msgid "The corresponding connectors will not work anymore." +# msgstr "" + +# msgid "Additional connector configuration deleted" +# msgstr "" + +# msgid "Additional connector configuration duplicated" +# msgstr "" + +# msgid "Additional connector configuration created" +# msgstr "" + +# msgid "Additional connector configuration updated" +# msgstr "" + +# msgid "Duplicate connector configuration" +# msgstr "" + +# msgid "The name can be at most 50 characters long" +# msgstr "" + +# msgid "The name should be at least 3 characters long" +# msgstr "" + +# msgid "Create additional connector configuration" +# msgstr "" + +# msgid "Update additional connector configuration" +# msgstr "" + +# msgid "Select poller(s)" +# msgstr "" + +# msgid "Password" +# msgstr "" + +# msgid "Add parameter" +# msgstr "" + +# msgid "Url" +# msgstr "" + +# msgid "Username" +# msgstr "" + +# msgid "Add vCenter/ESX" +# msgstr "" + +# msgid "Remove vCenter/ESX" +# msgstr "" + +# msgid "At least one poller is required" +# msgstr "" + +# msgid "At least one vCenter is required" +# msgstr "" + +# msgid "Please enter a valid URL or IP address" +# msgstr "" + +# msgid "Invalid port number" +# msgstr "" + +# msgid "The name of the vCenter should be unique" +# msgstr "" + +# msgid "vCenter name" +# msgstr "" + +# msgid "Do you want to quit without saving the changes?" +# msgstr "" + +# msgid "Your form has unsaved changes" +# msgstr "" + + +# msgid "Error while adding an additional connector configuration" +# msgstr "" + +# msgid "You are not allowed to access additional connector configurations" +# msgstr "" + +# msgid "An additional connector configuration configuration of type '%s' is already associated with poller ID(s) '%s'" +# msgstr "" + +# msgid "Duplicates not allowed for property '%s'" +# msgstr "" + +# msgid "'%s' must contain at least one element" +# msgstr "" + +# msgid "Error while retrieving an additional connector configuration" +# msgstr "" + +# msgid "The additional connector configuration name '%s' already exists" +# msgstr "" + +# msgid "Error while deleting an additional connector configuration" +# msgstr "" + +# msgid "You don't have sufficient permissions for this action" +# msgstr "" + +# msgid "Error while searching for additional connector configurations" +# msgstr "" + +# msgid "Error while searching for available pollers for type '%s'" +# msgstr "" + +# msgid "Select time zone" +# msgstr "" + +# msgid "Select time format" +# msgstr "" + +# msgid "12 hours" +# msgstr "" + +# msgid "24 hours" +# msgstr "" + +# msgid "Ends at" +# msgstr "" + +# msgid "Time zone" +# msgstr "" + +# msgid "Date format" +# msgstr "" + +# msgid "Time format" +# msgstr "" + +# msgid "Countdown" +# msgstr "" + +# msgid "Timer" +# msgstr "" + +# msgid "Show time zone" +# msgstr "" + +# msgid "Show date" +# msgstr "" + +# msgid "Error while updating an additional connector configuration" +# msgstr "" + +# msgid "Changing type of an existing additional connector configuration is not allowed" +# msgstr "" diff --git a/centreon/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po b/centreon/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po index cfb847263d..7461b259c6 100644 --- a/centreon/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po +++ b/centreon/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po @@ -2684,6 +2684,9 @@ msgstr "Mot de passe de l'utilisateur de la base de données" msgid "Confirm user password" msgstr "Confirmer le mot de passe de l'utilisateur" +msgid "Use a vault to store sensitive data" +msgstr "Utiliser un coffre fort pour stocker les données sensibles" + #: centreon-web/www/install/steps/functions.php:140 msgid "File not found" msgstr "Fichier non trouvé" @@ -17921,10 +17924,10 @@ msgid "Show thresholds" msgstr "Afficher les seuils" msgid "Custom" -msgstr "Personnalisé" +msgstr "Personnalisée" -msgid "Thresholds are automatically hidden as soon as you select 2 metric units." -msgstr "Les seuils sont automatiquement masqués dès que vous sélectionnez 2 unités métriques." +msgid "Thresholds are automatically hidden when you select several metrics with different units." +msgstr "Les seuils sont automatiquement masqués lorsque vous sélectionnez des métriques aux unités différentes." msgid "Show description" msgstr "Afficher la description" @@ -17957,7 +17960,7 @@ msgid "Your widget has been created successfully!" msgstr "Votre widget a été créé avec succès !" msgid "Value settings" -msgstr "Paramètres de valeur" +msgstr "Paramètres des valeurs" msgid "By turning off this option, all the links included in the widget will be opened in the same tab." msgstr "En désactivant cette option, tous les liens inclus dans le widget seront ouverts dans le même onglet." @@ -18005,7 +18008,7 @@ msgid "Widget type" msgstr "Type de widget" msgid "Display as" -msgstr "Afficher en tant que" +msgstr "Afficher sous forme de" msgid "Text" msgstr "Texte" @@ -18016,8 +18019,8 @@ msgstr "Jauge" msgid "Bar chart" msgstr "Diagramme à barres" -msgid "The default value is the value defined for the first metric used." -msgstr "La valeur par défaut est la valeur définie pour la première métrique utilisée." +msgid "The default value is the value defined for the first selected metric." +msgstr "La valeur par défaut est la valeur définie pour la première métrique sélectionnée." msgid "Raw value" msgstr "Valeur brute" @@ -18170,8 +18173,8 @@ msgstr "Seuils" msgid "Value format" msgstr "Format de la valeur" -msgid "Time period" -msgstr "Période temporelle" +msgid "Time range" +msgstr "Plage temporelle" msgid "Last hour" msgstr "La dernière heure" @@ -18771,8 +18774,8 @@ msgstr "La règle d'accès aux ressouces a été supprimée avec succès" msgid "Error while retrieving the number of services by status" msgstr "Erreur lors de la récupération du nombre de services par statut" -msgid "Error while adding a broker output" -msgstr "Erreur lors de l'ajout d'une sortie Centreon Broker" +msgid "Error while adding a Broker input/output" +msgstr "Erreur lors de l'ajout d'une entrée/sortie Centreon Broker" msgid "You are not allowed to edit a broker configuration" msgstr "Vous n'êtes pas autorisé à éditer une configuration Broker" @@ -18780,8 +18783,8 @@ msgstr "Vous n'êtes pas autorisé à éditer une configuration Broker" msgid "Broker configuration #%d not found" msgstr "Configuration Broker #%d introuvable" -msgid "Missing output parameter: %s" -msgstr "Paramètre de sortie manquant: %s" +msgid "Missing input/output parameter: %s" +msgstr "Paramètre d'entrée/sortie manquant : %s" msgid "Parameter '%s' (%s) is invalid" msgstr "Le paramètre '%s' (%s) est invalide" @@ -18789,8 +18792,8 @@ msgstr "Le paramètre '%s' (%s) est invalide" msgid "Parameter '%s' of type %s is invalid" msgstr "Le paramètre '%s' de type %s est invalide" -msgid "Output #%d not found for broker configuration #%d" -msgstr "Sortie #%d introuvable pour la configuration Broker #%d" +msgid "Input/Output #%d not found for Broker configuration #%d" +msgstr "Entrée/sortie #%d introuvable pour la configuration Broker #%d" msgid "Display resources with this unit" msgstr "Afficher les ressources avec cette unité" @@ -18852,8 +18855,8 @@ msgstr "Toutes les ressources" msgid "All resources selected" msgstr "Toutes les ressources sont sélectionnées" -msgid "Error while updating a broker output" -msgstr "Erreur lors de la mise à jour d'une sortie Centreon Broker" +msgid "Error while updating a Broker input/output" +msgstr "Erreur lors de la mise à jour d'une entrée/sortie Centreon Broker" msgid "Action not permitted for output of type '%s'" msgstr "Action non autorisée pour une sortie de type '%s'" @@ -18960,8 +18963,8 @@ msgstr "Type de courbe" msgid "Linear" msgstr "Linéaire" -msgid "Natural" -msgstr "Naturel" +msgid "Smooth" +msgstr "Arrondie" msgid "Error while partially updating the token" msgstr "Erreur lors de la mise à jour partielle du jeton" @@ -18978,23 +18981,26 @@ msgstr "Impossible de migrer les mots de passe" msgid "No vault configured" msgstr "Aucun coffre configuré" -msgid "Value sorting" +msgid "You are not allowed to access hosts in the real time context" +msgstr "Vous n'êtes pas autorisé à accéder aux hôtes dans le cadre du temps réel" + +msgid "You are not allowed to access services in the real time context" +msgstr "Vous n'êtes pas autorisé à accéder aux services dans le cadre du temps réel" + +msgid "Value sort order" msgstr "Tri des valeurs" msgid "By name" msgstr "Par nom" -msgid "Tooltip display" -msgstr "Affichage de l'infobulle" - msgid "All" -msgstr "Tout" +msgstr "Toutes" -msgid "Single" -msgstr "Unique" +msgid "Only one" +msgstr "Une seule" msgid "Hidden" -msgstr "Masqué" +msgstr "Masquées" msgid "Hide" msgstr "Masquer" @@ -19005,8 +19011,8 @@ msgstr "Largeur de la ligne" msgid "Auto" msgstr "Auto" -msgid "Show area" -msgstr "Afficher l'aire" +msgid "Area" +msgstr "Aire" msgid "Show" msgstr "Afficher" @@ -19014,14 +19020,14 @@ msgstr "Afficher" msgid "Display curve points" msgstr "Afficher les points de la courbe" -msgid "Show axis border" -msgstr "Afficher la bordure de l'axe" +msgid "Show axis borders" +msgstr "Afficher les bordures de l'axe" -msgid "Y-axis tick label rotation" -msgstr "Rotation de l'étiquette de l'axe Y" +msgid "Y-axis label rotation" +msgstr "Rotation des étiquettes de l'axe Y" -msgid "The Auto value corresponds to the value defined in the Curves configuration in Centreon." -msgstr "La valeur Auto correspond à la valeur définie dans la configuration des courbes dans Centreon." +msgid "Auto: Default value defined for the corresponding curve template (Monitoring > Performances > Curves)." +msgstr "Auto : Valeur par défaut définie dans le modèle de courbe correspondant (Supervision > Informations de performance > Courbes)." msgid "Position" msgstr "Position" @@ -19044,11 +19050,11 @@ msgstr "Centré sur zéro" msgid "Solid" msgstr "Uni" -msgid "Dashed" -msgstr "Tiret" +msgid "Dashes" +msgstr "Tirets" -msgid "Dotted" -msgstr "Pointillé" +msgid "Dots" +msgstr "Pointillés" msgid "Graph style" msgstr "Style de graphe" @@ -19056,8 +19062,8 @@ msgstr "Style de graphe" msgid "Display type" msgstr "Type d'affichage" -msgid "Display settings" -msgstr "Afichage des paramètres" +msgid "Graph settings" +msgstr "Paramètres de graphe" msgid "Fill opacity" msgstr "Opacité du remplissage" @@ -19071,8 +19077,11 @@ msgstr "Largeur du tiret" msgid "Space" msgstr "Espacement" -msgid "Show grid lines" -msgstr "Affichage de la grille" +msgid "Show gridlines" +msgstr "Afficher le quadrillage" + +msgid "Gridline type" +msgstr "Type de quadrillage" msgid "Horizontal" msgstr "Horizontal" @@ -19095,8 +19104,318 @@ msgstr "Gauche" msgid "Right" msgstr "Droite" -msgid "Axis" -msgstr "Axe" +msgid "Axes" +msgstr "Axes" + +msgid "Tooltips" +msgstr "Infobulles" + +msgid "Unable to retrieve credentials ['%s'] from vault" +msgstr "Impossible de récupérer les informations d'identification ['%s'] du coffre" + +msgid "Unknown provider type: %s" +msgstr "Type de fournisseur inconnu : %s" + +msgid "Add filter" +msgstr "Ajouter un filtre" + +msgid "Add resource dataset" +msgstr "Ajouter un jeu de données de ressources" + +msgid "Bar" +msgstr "Barre" + +msgid "Stacked bar" +msgstr "Barre empilée" + +msgid "Orientation" +msgstr "Orientation" + +msgid "Bar radius" +msgstr "Radius de la barre" + +msgid "Bar opacity" +msgstr "Opacité de la barre" + +msgid "Check command sent!" +msgstr "Commande de vérification envoyée !" + +msgid "Forced check command sent!" +msgstr "Commande de vérification forcée envoyée !" + +msgid "Open ticket" +msgstr "Ouvrir un ticket" + +msgid "Open ticket for host" +msgstr "Ouvrir un ticket pour l'hôte" + +msgid "Open ticket for service" +msgstr "Ouvrir un ticket pour le service" + +msgid "Host severities" +msgstr "Sévérités des hôtes" + +msgid "Service severities" +msgstr "Sévérités des services" + +msgid "Select service severities" +msgstr "Sélectionner les sévérités des services" + +msgid "Select host severities" +msgstr "Sélectionner les sévérités des hôtes" + +msgid "Enable Open Tickets" +msgstr "Activer Open Tickets" + +msgid "Ticket provider" +msgstr "Fournisseur de tickets" + +msgid "Select a provider" +msgstr "Sélectionner un fournisseur" + +msgid "Display resources" +msgstr "Afficher les ressources" + +msgid "Resources linked to a ticket" +msgstr "Ressources liées à un ticket" + +msgid "Resources with no ticket" +msgstr "Ressources sans ticket" + +msgid "Hide services with Down host" +msgstr "Masquer les services dont l'hôte est Indisponible" + +msgid "Hide services with Unreachable host" +msgstr "Masquer les services dont l'hôte est Injoignable" + +msgid "Ticket ID" +msgstr "ID du ticket" + +msgid "Ticket subject" +msgstr "Sujet du ticket" + +msgid "Opened on" +msgstr "Date d'ouverture" + +msgid "Create a ticket" +msgstr "Créer un ticket" + +msgid "Rule (ticket provider)" +msgstr "Règle (fournisseur de tickets)" + +msgid "Select rule (ticket provider)" +msgstr "Sélectionner la règle (fournisseur de tickets)" + +msgid "Display resources with these status types" +msgstr "Afficher les ressources avec ces types de statuts" + +msgid "All KPIs on this Business Activity are working fine." +msgstr "Tous les KPI de cette activité métier fonctionnent correctement." + +msgid "See more information in the geoview" +msgstr "Voir plus d'informations dans la vue géographique" + +msgid "Calculation method" +msgstr "Méthode de calcul" + +msgid "State information" +msgstr "Information de l'état" + +msgid "Warning threshold" +msgstr "Seuil d'alerte" + +msgid "Critical threshold" +msgstr "Seuil critique" + +msgid "Click here for details" +msgstr "Cliquez ici pour les détails" + +msgid "Expression in" +msgstr "Expression en" + +msgid "Impact applied when:" +msgstr "Impact appliqué quand :" + +msgid "true" +msgstr "vrai" + +msgid "false" +msgstr "faux" + +msgid "No KPI found" +msgstr "Aucun KPI trouvé" + +msgid "No Business Activity found" +msgstr "Aucune activité métier trouvée" + +msgid "business activity" +msgstr "activité métier" + +msgid "Health" +msgstr "Santé" + +msgid "Critical KPIs" +msgstr "Indicateurs critiques" + +msgid "Additional connector configurations" +msgstr "Configuration supplémentaire de connecteurs" + +msgid "Types" +msgstr "Types" + +msgid "Updated by" +msgstr "Mis à jour par" + +msgid "Edit connector configuration" +msgstr "Modifier la configuration de connecteur" + +msgid "More filters" +msgstr "Plus de filtres" + +msgid "Delete additional connector configuration" +msgstr "Supprimer la configuration supplémentaire de connecteur" + +msgid "The {{name}} additional connector configuration will be permanently deleted." +msgstr "La configuration supplémentaire de connecteur {{name}} sera définitivement supprimée." + +msgid "The corresponding connectors will not work anymore." +msgstr "Les connecteurs correspondants ne fonctionneront plus." + +msgid "Additional connector configuration deleted" +msgstr "Configuration supplémentaire de connecteur supprimée" + +msgid "Additional connector configuration duplicated" +msgstr "Configuration supplémentaire de connecteur dupliquée" + +msgid "Additional connector configuration created" +msgstr "Configuration supplémentaire de connecteur créée" + +msgid "Additional connector configuration updated" +msgstr "Configuration supplémentaire de connecteur mise à jour" + +msgid "Duplicate connector configuration" +msgstr "Dupliquer la configuration de connecteur" + +msgid "The name can be at most 50 characters long" +msgstr "Le nom peut comporter au maximum 50 caractères" + +msgid "The name should be at least 3 characters long" +msgstr "Le nom doit comporter au moins 3 caractères" + +msgid "Create additional connector configuration" +msgstr "Créer une configuration supplémentaire de connecteur" + +msgid "Update additional connector configuration" +msgstr "Mettre à jour la configuration supplémentaire de connecteur" + +msgid "Select poller(s)" +msgstr "Sélectionner le(s) collecteur(s)" + +msgid "Add parameter" +msgstr "Ajouter un paramètre" + +msgid "Add vCenter/ESX" +msgstr "Ajouter vCenter/ESX" + +msgid "Remove vCenter/ESX" +msgstr "Supprimer vCenter/ESX" + +msgid "At least one poller is required" +msgstr "Au moins un collecteur est requis" + +msgid "At least one vCenter is required" +msgstr "Au moins un vCenter est requis" + +msgid "Please enter a valid URL or IP address" +msgstr "Entrez une URL ou une adresse IP valide" + +msgid "Invalid port number" +msgstr "Numéro de port invalide" + +msgid "The name of the vCenter should be unique" +msgstr "Le nom du vCenter doit être unique" + +msgid "vCenter name" +msgstr "Nom du vCenter" + +msgid "Do you want to quit without saving the changes?" +msgstr "Voulez-vous quitter sans enregistrer les modifications ?" + + +msgid "Error while adding an additional connector configuration" +msgstr "Erreur lors de l'ajout d'une configuration additionnelle de connecteur" + +msgid "You are not allowed to access additional connector configurations" +msgstr "Vous n'êtes pas autorisé à accéder aux configurations additionnelles de connecteurs" + +msgid "An additional connector configuration of type %s is already associated with poller ID(s) '%s'" +msgstr "Une configuration additionnelle de connecteur de type %s est déjà associée au(x) ID(s) de collecteur(s) '%s'" + +msgid "Duplicates not allowed for property '%s'" +msgstr "Doublons non autorisés pour la propriété '%'" + +msgid "'%s' must contain at least one element" +msgstr "'%s' doit contenir au moins un élément" + +msgid "Error while retrieving an additional connector configuration" +msgstr "Erreur durant la récupération d'une configuration additionnelle de connecteur" + +msgid "The additional connector configuration name '%s' already exists" +msgstr "Le nom de configuration additionnelle de connecteur '%s' existe déjà" + +msgid "Error while deleting an additional connector configuration" +msgstr "Erreur lors de la suppression d'une configuration additionelle de connecteur" + +msgid "You don't have sufficient permissions for this action" +msgstr "Vous ne disposez pas de droits suffisants pour cette action" + +msgid "Error while searching for additional connector configurations" +msgstr "Erreur lors de la recherche de configurations additionnelles de connecteurs" + +msgid "Error while searching for available pollers for type '%s'" +msgstr "Erreur lors de la recherche de collecteurs disponibles pour le type '%s'" + +msgid "Error while updating an additional connector configuration" +msgstr "Erreur lors de la mise à jour d'une configuration additionnelle de connecteur" + +msgid "Changing type of an existing additional connector configuration is not allowed" +msgstr "Changer le type d'une configuration additionnelle de connecteur existante n'est pas autorisé" + +msgid "Select time zone" +msgstr "Sélectionner un fuseau horaire" + +msgid "Select time format" +msgstr "Sélectionner un format d'heure" + +msgid "12 hours" +msgstr "12 heures" + +msgid "24 hours" +msgstr "24 heures" + +msgid "Ends at" +msgstr "Se termine à" + +msgid "Time zone" +msgstr "Fuseau horaire" + +msgid "Date format" +msgstr "Format de date" + +msgid "Time format" +msgstr "Format d'heure" + +msgid "Countdown" +msgstr "Compte à rebours" + +msgid "Timer" +msgstr "Minuteur" + +msgid "Show time zone" +msgstr "Afficher le fuseau horaire" + +msgid "Show date" +msgstr "Afficher la date" -msgid "Tooltip" -msgstr "Infobulle" +msgid "The ticket will be closed for the selected ticket provider" +msgstr "Le ticket sera fermé pour le fournisseur de tickets sélectionné" diff --git a/centreon/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po b/centreon/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po index e1316c1e78..2aa77d9d3d 100644 --- a/centreon/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po +++ b/centreon/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po @@ -17468,7 +17468,7 @@ msgstr "" # msgid "The resource access rule was successfully deleted" # msgstr "" -# msgid "Error while adding a broker output" +# msgid "Error while adding a Broker input/output" # msgstr "" # msgid "You are not allowed to edit a broker configuration" @@ -17477,7 +17477,7 @@ msgstr "" # msgid "Broker configuration #%d not found" # msgstr "" -# msgid "Missing output parameter: %s" +# msgid "Missing input/output parameter: %s" # msgstr "" # msgid "Parameter '%s' (%s) is invalid" @@ -17486,7 +17486,7 @@ msgstr "" # msgid "Parameter '%s' of type %s is invalid" # msgstr "" -# msgid "Output #%d not found for broker configuration #%d" +# msgid "Input/Output #%d not found for Broker configuration #%d" # msgstr "" # msgid "Rules are used to allow users to access resources." @@ -17546,7 +17546,7 @@ msgstr "" # msgid "All resources selected" # msgstr "" -# msgid "Error while updating a broker output" +# msgid "Error while updating a Broker input/output" # msgstr "" # msgid "Action not permitted for output of type '%s'" @@ -17809,3 +17809,325 @@ msgstr "" # msgid "Tooltip" # msgstr "" + +# msgid "Add filter" +# msgstr "" + +# msgid "Add resource dataset" +# msgstr "" + +# msgid "Line" +# msgstr "" + +# msgid "Bar" +# msgstr "" + +# msgid "Stacked bar" +# msgstr "" + +# msgid "Orientation" +# msgstr "" + +# msgid "Bar radius" +# msgstr "" + +# msgid "Bar background opacity" +# msgstr "" + +# msgid "Check command sent!" +# msgstr "" + +# msgid "Forced check command sent!" +# msgstr "" + +# msgid "Open ticket" +# msgstr "" + +# msgid "Open ticket for host" +# msgstr "" + +# msgid "Open ticket for service" +# msgstr "" + +# msgid "Host severities" +# msgstr "" + +# msgid "Service severities" +# msgstr "" + +# msgid "Select service severities" +# msgstr "" + +# msgid "Select host severities" +# msgstr "" + +# msgid "Enable Open Tickets" +# msgstr "" + +# msgid "Ticket provider" +# msgstr "" + +# msgid "Select a provider" +# msgstr "" + +# msgid "Display resources" +# msgstr "" + +# msgid "Resources linked to a ticket" +# msgstr "" + +# msgid "Resources with no ticket" +# msgstr "" + +# msgid "Hide services with Down host" +# msgstr "" + +# msgstr "hide services with Unreachable host" +# msgstr "" + +# msgstr "Ticket ID" +# msgstr "" + +# msgstr "Ticket subject" +# msgstr "" + +# msgstr "Opened on" +# msgstr "" + +# msgid "Create a ticket" +# msgstr "" + +# msgid "Rule (ticket provider)" +# msgstr "" + +# msgid "Select rule (ticket provider)" +# msgstr "" + +# msgid "Display resources with these status types" +# msgstr "" + +# msgid "All KPIs on this Business Activity are working fine." +# msgstr "" + +# msgid "are working fine." +# msgstr "" + +# msgid "See more information in the geoview" +# msgstr "" + +# msgid "Calculation method" +# msgstr "" + +# msgid "State information" +# msgstr "" + +# msgid "Warning threshold" +# msgstr "" + +# msgid "Critical threshold" +# msgstr "" + +# msgid "Expression in" +# msgstr "" + +# msgid "Impact applied when:" +# msgstr "" + +# msgid "true" +# msgstr "" + +# msgid "false" +# msgstr "" + +# msgid "Click here for details" +# msgstr "" + +# msgid "No KPI found" +# msgstr "" + +# msgid "No Business Activity found" +# msgstr "" + +# msgid "business activity" +# msgstr "" + +# msgid "Health" +# msgstr "" + +# msgid "Critical KPIs" +# msgstr "" + +# msgid "Additional connector configurations" +# msgstr "" + +# msgid "Types" +# msgstr "" + +# msgid "Updated by" +# msgstr "" + +# msgid "Edit connector configuration" +# msgstr "" + +# msgid "More filters" +# msgstr "" + +# msgid "Pollers" +# msgstr "" + +# msgid "Delete additional connector configuration" +# msgstr "" + +# msgid "The {{name}} additional connector configuration will be permanently deleted." +# msgstr "" + +# msgid "The corresponding connectors will not work anymore." +# msgstr "" + +# msgid "Additional connector configuration deleted" +# msgstr "" + +# msgid "Additional connector configuration duplicated" +# msgstr "" + +# msgid "Additional connector configuration created" +# msgstr "" + +# msgid "Additional connector configuration updated" +# msgstr "" + +# msgid "Duplicate connector configuration" +# msgstr "" + +# msgid "The name can be at most 50 characters long" +# msgstr "" + +# msgid "The name should be at least 3 characters long" +# msgstr "" + +# msgid "Create additional connector configuration" +# msgstr "" + +# msgid "Update additional connector configuration" +# msgstr "" + +# msgid "Select poller(s)" +# msgstr "" + +# msgid "Password" +# msgstr "" + +# msgid "Add parameter" +# msgstr "" + +# msgid "Url" +# msgstr "" + +# msgid "Username" +# msgstr "" + +# msgid "Add vCenter/ESX" +# msgstr "" + +# msgid "Remove vCenter/ESX" +# msgstr "" + +# msgid "At least one poller is required" +# msgstr "" + +# msgid "At least one vCenter is required" +# msgstr "" + +# msgid "Please enter a valid URL or IP address" +# msgstr "" + +# msgid "Invalid port number" +# msgstr "" + +# msgid "The name of the vCenter should be unique" +# msgstr "" + +# msgid "vCenter name" +# msgstr "" + +# msgid "Do you want to quit without saving the changes?" +# msgstr "" + +# msgid "Your form has unsaved changes" +# msgstr "" + + +# msgid "Error while adding an additional connector configuration" +# msgstr "" + +# msgid "You are not allowed to access additional connector configurations" +# msgstr "" + +# msgid "An additional connector configuration configuration of type '%s' is already associated with poller ID(s) '%s'" +# msgstr "" + +# msgid "Duplicates not allowed for property '%s'" +# msgstr "" + +# msgid "'%s' must contain at least one element" +# msgstr "" + +# msgid "Error while retrieving an additional connector configuration" +# msgstr "" + +# msgid "The additional connector configuration name '%s' already exists" +# msgstr "" + +# msgid "Error while deleting an additional connector configuration" +# msgstr "" + +# msgid "You don't have sufficient permissions for this action" +# msgstr "" + +# msgid "Error while searching for additional connector configurations" +# msgstr "" + +# msgid "Error while searching for available pollers for type '%s'" +# msgstr "" + +# msgid "Select time zone" +# msgstr "" + +# msgid "Select time format" +# msgstr "" + +# msgid "12 hours" +# msgstr "" + +# msgid "24 hours" +# msgstr "" + +# msgid "Ends at" +# msgstr "" + +# msgid "Time zone" +# msgstr "" + +# msgid "Date format" +# msgstr "" + +# msgid "Time format" +# msgstr "" + +# msgid "Countdown" +# msgstr "" + +# msgid "Timer" +# msgstr "" + +# msgid "Show time zone" +# msgstr "" + +# msgid "Show date" +# msgstr "" + +# msgid "Error while updating an additional connector configuration" +# msgstr "" + +# msgid "Changing type of an existing additional connector configuration is not allowed" +# msgstr "" diff --git a/centreon/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po b/centreon/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po index cf6151a72c..0cee342f99 100644 --- a/centreon/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po +++ b/centreon/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po @@ -17432,7 +17432,7 @@ msgstr "Você não salvou as alterações, deseja continuar?" # msgid "You are not allowed to access the Resources Status page" -# msgid "Error while adding a broker output" +# msgid "Error while adding a Broker input/output" # msgstr "" # msgid "You are not allowed to edit a broker configuration" @@ -17441,7 +17441,7 @@ msgstr "Você não salvou as alterações, deseja continuar?" # msgid "Broker configuration #%d not found" # msgstr "" -# msgid "Missing output parameter: %s" +# msgid "Missing input/output parameter: %s" # msgstr "" # msgid "Parameter '%s' (%s) is invalid" @@ -17450,7 +17450,7 @@ msgstr "Você não salvou as alterações, deseja continuar?" # msgid "Parameter '%s' of type %s is invalid" # msgstr "" -# msgid "Output #%d not found for broker configuration #%d" +# msgid "Input/Output #%d not found for Broker configuration #%d" # msgstr "" # msgid "Delete rule" @@ -17527,7 +17527,7 @@ msgstr "Você não salvou as alterações, deseja continuar?" # msgid "All resources selected" # msgstr "" -# msgid "Error while updating a broker output" +# msgid "Error while updating a Broker input/output" # msgstr "" # msgid "Action not permitted for output of type '%s'" @@ -17789,3 +17789,325 @@ msgstr "Você não salvou as alterações, deseja continuar?" # msgid "Tooltip" # msgstr "" + +# msgid "Add filter" +# msgstr "" + +# msgid "Add resource dataset" +# msgstr "" + +# msgid "Line" +# msgstr "" + +# msgid "Bar" +# msgstr "" + +# msgid "Stacked bar" +# msgstr "" + +# msgid "Orientation" +# msgstr "" + +# msgid "Bar radius" +# msgstr "" + +# msgid "Bar background opacity" +# msgstr "" + +# msgid "Check command sent!" +# msgstr "" + +# msgid "Forced check command sent!" +# msgstr "" + +# msgid "Open ticket" +# msgstr "" + +# msgid "Open ticket for host" +# msgstr "" + +# msgid "Open ticket for service" +# msgstr "" + +# msgid "Host severities" +# msgstr "" + +# msgid "Service severities" +# msgstr "" + +# msgid "Select service severities" +# msgstr "" + +# msgid "Select host severities" +# msgstr "" + +# msgid "Enable Open Tickets" +# msgstr "" + +# msgid "Ticket provider" +# msgstr "" + +# msgid "Select a provider" +# msgstr "" + +# msgid "Display resources" +# msgstr "" + +# msgid "Resources linked to a ticket" +# msgstr "" + +# msgid "Resources with no ticket" +# msgstr "" + +# msgid "Hide services with Down host" +# msgstr "" + +# msgstr "hide services with Unreachable host" +# msgstr "" + +# msgstr "Ticket ID" +# msgstr "" + +# msgstr "Ticket subject" +# msgstr "" + +# msgstr "Opened on" +# msgstr "" + +# msgid "Create a ticket" +# msgstr "" + +# msgid "Rule (ticket provider)" +# msgstr "" + +# msgid "Select rule (ticket provider)" +# msgstr "" + +# msgid "Display resources with these status types" +# msgstr "" + +# msgid "All KPIs on this Business Activity are working fine." +# msgstr "" + +# msgid "are working fine." +# msgstr "" + +# msgid "See more information in the geoview" +# msgstr "" + +# msgid "Calculation method" +# msgstr "" + +# msgid "State information" +# msgstr "" + +# msgid "Warning threshold" +# msgstr "" + +# msgid "Critical threshold" +# msgstr "" + +# msgid "Expression in" +# msgstr "" + +# msgid "Impact applied when:" +# msgstr "" + +# msgid "true" +# msgstr "" + +# msgid "false" +# msgstr "" + +# msgid "Click here for details" +# msgstr "" + +# msgid "No KPI found" +# msgstr "" + +# msgid "No Business Activity found" +# msgstr "" + +# msgid "business activity" +# msgstr "" + +# msgid "Health" +# msgstr "" + +# msgid "Critical KPIs" +# msgstr "" + +# msgid "Additional connector configurations" +# msgstr "" + +# msgid "Types" +# msgstr "" + +# msgid "Updated by" +# msgstr "" + +# msgid "Edit connector configuration" +# msgstr "" + +# msgid "More filters" +# msgstr "" + +# msgid "Pollers" +# msgstr "" + +# msgid "Delete additional connector configuration" +# msgstr "" + +# msgid "The {{name}} additional connector configuration will be permanently deleted." +# msgstr "" + +# msgid "The corresponding connectors will not work anymore." +# msgstr "" + +# msgid "Additional connector configuration deleted" +# msgstr "" + +# msgid "Additional connector configuration duplicated" +# msgstr "" + +# msgid "Additional connector configuration created" +# msgstr "" + +# msgid "Additional connector configuration updated" +# msgstr "" + +# msgid "Duplicate connector configuration" +# msgstr "" + +# msgid "The name can be at most 50 characters long" +# msgstr "" + +# msgid "The name should be at least 3 characters long" +# msgstr "" + +# msgid "Create additional connector configuration" +# msgstr "" + +# msgid "Update additional connector configuration" +# msgstr "" + +# msgid "Select poller(s)" +# msgstr "" + +# msgid "Password" +# msgstr "" + +# msgid "Add parameter" +# msgstr "" + +# msgid "Url" +# msgstr "" + +# msgid "Username" +# msgstr "" + +# msgid "Add vCenter/ESX" +# msgstr "" + +# msgid "Remove vCenter/ESX" +# msgstr "" + +# msgid "At least one poller is required" +# msgstr "" + +# msgid "At least one vCenter is required" +# msgstr "" + +# msgid "Please enter a valid URL or IP address" +# msgstr "" + +# msgid "Invalid port number" +# msgstr "" + +# msgid "The name of the vCenter should be unique" +# msgstr "" + +# msgid "vCenter name" +# msgstr "" + +# msgid "Do you want to quit without saving the changes?" +# msgstr "" + +# msgid "Your form has unsaved changes" +# msgstr "" + + +# msgid "Error while adding an additional connector configuration" +# msgstr "" + +# msgid "You are not allowed to access additional connector configurations" +# msgstr "" + +# msgid "An additional connector configuration configuration of type '%s' is already associated with poller ID(s) '%s'" +# msgstr "" + +# msgid "Duplicates not allowed for property '%s'" +# msgstr "" + +# msgid "'%s' must contain at least one element" +# msgstr "" + +# msgid "Error while retrieving an additional connector configuration" +# msgstr "" + +# msgid "The additional connector configuration name '%s' already exists" +# msgstr "" + +# msgid "Error while deleting an additional connector configuration" +# msgstr "" + +# msgid "You don't have sufficient permissions for this action" +# msgstr "" + +# msgid "Error while searching for additional connector configurations" +# msgstr "" + +# msgid "Error while searching for available pollers for type '%s'" +# msgstr "" + +# msgid "Select time zone" +# msgstr "" + +# msgid "Select time format" +# msgstr "" + +# msgid "12 hours" +# msgstr "" + +# msgid "24 hours" +# msgstr "" + +# msgid "Ends at" +# msgstr "" + +# msgid "Time zone" +# msgstr "" + +# msgid "Date format" +# msgstr "" + +# msgid "Time format" +# msgstr "" + +# msgid "Countdown" +# msgstr "" + +# msgid "Timer" +# msgstr "" + +# msgid "Show time zone" +# msgstr "" + +# msgid "Show date" +# msgstr "" + +# msgid "Error while updating an additional connector configuration" +# msgstr "" + +# msgid "Changing type of an existing additional connector configuration is not allowed" +# msgstr "" diff --git a/centreon/lighthouse/package-lock.json b/centreon/lighthouse/package-lock.json index cbb59269e8..5418d71583 100644 --- a/centreon/lighthouse/package-lock.json +++ b/centreon/lighthouse/package-lock.json @@ -7,283 +7,18 @@ "": { "name": "centreon-lighthouse-report", "version": "22.4.0", - "dependencies": { - "node-fetch": "^3.3.2" - }, - "devDependencies": { - "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.35", - "lighthouse": "^10.0.0", - "open": "^8.4.0", - "pptr-testing-library": "^0.7.0", - "puppeteer": "^19.7.0" - } - }, - "../node_modules/.pnpm/@swc+cli@0.1.62_@swc+core@1.3.58/node_modules/@swc/cli": { - "version": "0.1.62", - "dev": true, - "license": "MIT", - "dependencies": { - "@mole-inc/bin-wrapper": "^8.0.1", - "commander": "^7.1.0", - "fast-glob": "^3.2.5", - "semver": "^7.3.8", - "slash": "3.0.0", - "source-map": "^0.7.3" - }, - "bin": { - "spack": "bin/spack.js", - "swc": "bin/swc.js", - "swcx": "bin/swcx.js" - }, - "devDependencies": { - "@swc/cli": "^0.1.43", - "@swc/core": "^1.2.66", - "@swc/jest": "^0.1.2", - "@types/jest": "^26.0.23", - "@types/node": "^12.19.16", - "@types/semver": "^7.3.13", - "chokidar": "^3.5.1", - "deepmerge": "^4.2.2", - "jest": "^27.0.3", - "nano-staged": "^0.4.5", - "prettier": "^2.5.1", - "simple-git-hooks": "^2.7.0", - "ts-jest": "^27.0.4", - "typescript": "~4.3.2" - }, - "engines": { - "node": ">= 12.13" - }, - "peerDependencies": { - "@swc/core": "^1.2.66", - "chokidar": "^3.5.1" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "../node_modules/.pnpm/@swc+core@1.3.58/node_modules/@swc/core": { - "version": "1.3.58", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "devDependencies": { - "@babel/compat-data": "^7.17.0", - "@babel/core": "^7.13.16", - "@babel/generator": "^7.18.13", - "@babel/plugin-proposal-class-properties": "^7.13.0", - "@babel/plugin-proposal-decorators": "^7.13.15", - "@babel/plugin-proposal-object-rest-spread": "^7.13.8", - "@babel/preset-env": "^7.13.15", - "@babel/preset-react": "^7.13.13", - "@babel/preset-typescript": "^7.13.0", - "@babel/types": "^7.14.0", - "@napi-rs/cli": "^2.14.1", - "@swc/core": "=1.2.220", - "@swc/helpers": "^0.5.0", - "@swc/plugin-jest": "latest", - "@taplo/cli": "^0.3.2", - "@types/jest": "^28.1.4", - "@types/node": "^14.14.41", - "@types/terser": "^3.12.0", - "acorn": "^8.6.0", - "acorn-jsx": "^5.3.2", - "axios": "^0.21.1", - "babel-plugin-transform-node-env-inline": "^0.4.3", - "benchmark": "^2.1.4", - "bootstrap": "^5.2.1", - "class-validator": "^0.13.1", - "core-js": "^2.6.11", - "core-js-compat": "^3.21.1", - "cross-env": "^7.0.3", - "cspell": "^5.12.3", - "expect": "^27.4.2", - "glob": "^8.0.3", - "husky": "^7.0.2", - "jest": "^28.1.2", - "js-beautify": "^1.14.3", - "lint-staged": "^12.3.6", - "lodash": "^4.17.21", - "mocha": "^9.1.3", - "npm-run-all": "^4.1.5", - "prettier": "^2.6.2", - "progress": "^2.0.3", - "prop-types": "^15.7.2", - "react": "^17.0.2", - "reflect-metadata": "^0.1.13", - "regenerator-runtime": "^0.13.9", - "source-map": "^0.7.3", - "source-map-support": "^0.5.19", - "sourcemap-validator": "^2.1.0", - "swc-plugin-coverage-instrument": "^0.0.12", - "terser": "^5.7.1", - "ts-node": "^10.5.0", - "typescript": "^4.5.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.58", - "@swc/core-darwin-x64": "1.3.58", - "@swc/core-linux-arm-gnueabihf": "1.3.58", - "@swc/core-linux-arm64-gnu": "1.3.58", - "@swc/core-linux-arm64-musl": "1.3.58", - "@swc/core-linux-x64-gnu": "1.3.58", - "@swc/core-linux-x64-musl": "1.3.58", - "@swc/core-win32-arm64-msvc": "1.3.58", - "@swc/core-win32-ia32-msvc": "1.3.58", - "@swc/core-win32-x64-msvc": "1.3.58" - }, - "peerDependencies": { - "@swc/helpers": "^0.5.0" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "../node_modules/.pnpm/lighthouse@10.2.0/node_modules/lighthouse": { - "version": "10.2.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@sentry/node": "^6.17.4", - "axe-core": "4.7.0", - "chrome-launcher": "^0.15.2", - "configstore": "^5.0.1", - "csp_evaluator": "1.1.1", - "devtools-protocol": "0.0.1130274", - "enquirer": "^2.3.6", - "http-link-header": "^1.1.1", - "intl-messageformat": "^4.4.0", - "jpeg-js": "^0.4.4", - "js-library-detector": "^6.6.0", - "lighthouse-logger": "^1.3.0", - "lighthouse-stack-packs": "1.10.0", - "lodash": "^4.17.21", - "lookup-closest-locale": "6.2.0", - "metaviewport-parser": "0.3.0", - "open": "^8.4.0", - "parse-cache-control": "1.0.1", - "ps-list": "^8.0.0", - "puppeteer-core": "^20.1.0", - "robots-parser": "^3.0.0", - "semver": "^5.3.0", - "speedline-core": "^1.4.3", - "third-party-web": "^0.20.2", - "ws": "^7.0.0", - "yargs": "^17.3.1", - "yargs-parser": "^21.0.0" - }, - "bin": { - "chrome-debug": "core/scripts/manual-chrome-launcher.js", - "lighthouse": "cli/index.js", - "smokehouse": "cli/test/smokehouse/frontends/smokehouse-bin.js" - }, "devDependencies": { - "@build-tracker/cli": "^1.0.0-beta.15", - "@esbuild-kit/esm-loader": "^2.1.1", - "@jest/fake-timers": "^28.1.0", - "@rollup/plugin-alias": "^3.1.2", - "@rollup/plugin-commonjs": "^20.0.0", - "@rollup/plugin-dynamic-import-vars": "^1.1.1", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.4", - "@rollup/plugin-typescript": "^8.2.5", - "@stadtlandnetz/rollup-plugin-postprocess": "^1.1.0", - "@testing-library/preact": "^3.1.1", - "@testing-library/preact-hooks": "^1.1.0", - "@types/archiver": "^2.1.2", - "@types/chrome": "^0.0.154", - "@types/configstore": "^4.0.0", - "@types/cpy": "^5.1.0", - "@types/debug": "^4.1.7", - "@types/eslint": "^8.2.1", - "@types/estree": "^0.0.50", - "@types/gh-pages": "^2.0.0", - "@types/google.analytics": "0.0.39", - "@types/jpeg-js": "^0.3.7", - "@types/jsdom": "^16.2.13", - "@types/lodash": "^4.14.178", - "@types/mocha": "^9.0.0", - "@types/node": "*", - "@types/pako": "^1.0.1", - "@types/resize-observer-browser": "^0.1.1", - "@types/semver": "^5.5.0", - "@types/tabulator-tables": "^4.9.1", - "@types/ws": "^7.0.0", - "@types/yargs": "^17.0.8", - "@types/yargs-parser": "^20.2.1", - "@typescript-eslint/eslint-plugin": "^5.48.0", - "@typescript-eslint/parser": "^5.48.0", - "acorn": "^8.5.0", - "angular": "^1.7.4", - "archiver": "^3.0.0", - "c8": "^7.11.3", - "chalk": "^2.4.1", - "chrome-devtools-frontend": "1.0.1070764", - "concurrently": "^6.4.0", - "conventional-changelog-cli": "^2.1.1", - "cpy": "^8.1.2", - "cross-env": "^7.0.2", - "csv-validator": "^0.0.3", - "es-main": "^1.0.2", - "eslint": "^8.4.1", - "eslint-config-google": "^0.14.0", - "eslint-formatter-codeframe": "^7.32.1", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-local-rules": "1.1.0", - "event-target-shim": "^6.0.2", - "expect": "^28.1.0", - "firebase": "^9.0.2", - "gh-pages": "^2.0.1", - "glob": "^7.1.3", - "idb-keyval": "2.2.0", - "intl-messageformat-parser": "^1.8.1", - "jest-mock": "^27.3.0", - "jest-snapshot": "^28.1.0", - "jsdom": "^12.2.0", - "lighthouse-plugin-publisher-ads": "1.5.7-beta", - "lighthouse-plugin-soft-navigation": "^1.0.1", - "magic-string": "^0.25.7", - "mime-types": "^2.1.30", - "mocha": "^10.0.0", - "node-fetch": "^2.6.1", - "npm-run-posix-or-windows": "^2.0.2", - "pako": "^2.0.3", - "preact": "^10.7.2", - "pretty-json-stringify": "^0.0.2", - "puppeteer": "^20.1.0", - "resolve": "^1.20.0", - "rollup": "^2.52.7", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-polyfill-node": "^0.12.0", - "rollup-plugin-replace": "^2.2.0", - "rollup-plugin-shim": "^1.0.0", - "rollup-plugin-terser": "^7.0.2", - "tabulator-tables": "^4.9.3", - "terser": "^5.3.8", - "testdouble": "^3.16.8", - "typed-query-selector": "^2.6.1", - "typescript": "^5.0.4", - "wait-for-expect": "^3.0.2", - "webtreemap-cdt": "^3.2.1" - }, - "engines": { - "node": ">=16.16" + "@swc/cli": "^0.4.0", + "@swc/core": "^1.6.6", + "lighthouse": "^12.1.0", + "open": "^10.1.0", + "pptr-testing-library": "^0.8.0", + "puppeteer": "^22.12.1" } }, "../node_modules/.pnpm/node-fetch@3.3.2/node_modules/node-fetch": { "version": "3.3.2", + "extraneous": true, "license": "MIT", "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -316,42 +51,6 @@ "url": "https://opencollective.com/node-fetch" } }, - "../node_modules/.pnpm/open@8.4.2/node_modules/open": { - "version": "8.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "devDependencies": { - "@types/node": "^15.0.0", - "ava": "^3.15.0", - "tsd": "^0.14.0", - "xo": "^0.39.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../node_modules/.pnpm/puppeteer@19.11.1/node_modules/puppeteer": { - "version": "19.11.1", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@puppeteer/browsers": "0.5.0", - "cosmiconfig": "8.1.3", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.11.1" - } - }, "node_modules/@babel/code-frame": { "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", @@ -537,6 +236,85 @@ "node": ">=6.9.0" } }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", + "integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==", + "dev": true, + "dependencies": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/ecma402-abstract/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz", + "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==", + "dev": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/fast-memoize/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz", + "integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-skeleton-parser": "1.8.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz", + "integrity": "sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", + "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==", + "dev": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/intl-localematcher/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@jest/types": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", @@ -553,922 +331,6862 @@ "node": ">= 10.14.2" } }, - "node_modules/@swc/cli": { - "resolved": "../node_modules/.pnpm/@swc+cli@0.1.62_@swc+core@1.3.58/node_modules/@swc/cli", - "link": true - }, - "node_modules/@swc/core": { - "resolved": "../node_modules/.pnpm/@swc+core@1.3.58/node_modules/@swc/core", - "link": true - }, - "node_modules/@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "node_modules/@mole-inc/bin-wrapper": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", + "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" + "bin-check": "^4.1.0", + "bin-version-check": "^5.0.0", + "content-disposition": "^0.5.4", + "ext-name": "^5.0.0", + "file-type": "^17.1.6", + "filenamify": "^5.0.2", + "got": "^11.8.5", + "os-filter-obj": "^2.0.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", - "dev": true - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "@types/istanbul-lib-report": "*" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@types/node": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", - "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "dependencies": { - "undici-types": "~5.26.4" + "engines": { + "node": ">= 8" } }, - "node_modules/@types/yargs": { - "version": "15.0.18", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.18.tgz", - "integrity": "sha512-DDi2KmvAnNsT/EvU8jp1UR7pOJojBtJ3GLZ/uw1MUq4VbbESppPWoHUY4h0OB4BbEbGJiyEsmUcuZDZtoR+ZwQ==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "node_modules/@paulirish/trace_engine": { + "version": "0.0.23", + "resolved": "https://registry.npmjs.org/@paulirish/trace_engine/-/trace_engine-0.0.23.tgz", + "integrity": "sha512-2ym/q7HhC5K+akXkNV6Gip3oaHpbI6TsGjmcAsl7bcJ528MVbacPQeoauLFEeLXH4ulJvsxQwNDIg/kAEhFZxw==", "dev": true }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@puppeteer/browsers": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.3.tgz", + "integrity": "sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==", "dev": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.4.0", + "semver": "7.6.0", + "tar-fs": "3.0.5", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@puppeteer/browsers/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "ms": "2.1.2" }, "engines": { - "node": ">=8" + "node": ">=6.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "node_modules/@puppeteer/browsers/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "yallist": "^4.0.0" }, "engines": { - "node": ">=6.0" + "node": ">=10" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@puppeteer/browsers/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" + } + }, + "node_modules/@puppeteer/browsers/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@sentry/core": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz", + "integrity": "sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==", + "dev": true, + "dependencies": { + "@sentry/hub": "6.19.7", + "@sentry/minimal": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">=6" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@sentry/hub": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz", + "integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" }, "engines": { - "node": ">=7.0.0" + "node": ">=6" } }, - "node_modules/color-name": { + "node_modules/@sentry/minimal": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz", + "integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==", + "dev": true, + "dependencies": { + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.19.7.tgz", + "integrity": "sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==", + "dev": true, + "dependencies": { + "@sentry/core": "6.19.7", + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", + "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", + "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", + "dev": true, + "dependencies": { + "@sentry/types": "6.19.7", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@swc/cli": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.4.0.tgz", + "integrity": "sha512-4JdVrPtF/4rCMXp6Q1h5I6YkYZrCCcqod7Wk97ZQq7K8vNGzJUryBv4eHCvqx5sJOJBrbYm9fcswe1B0TygNoA==", + "dev": true, + "dependencies": { + "@mole-inc/bin-wrapper": "^8.0.1", + "@swc/counter": "^0.1.3", + "commander": "^8.3.0", + "fast-glob": "^3.2.5", + "minimatch": "^9.0.3", + "piscina": "^4.3.0", + "semver": "^7.3.8", + "slash": "3.0.0", + "source-map": "^0.7.3" + }, + "bin": { + "spack": "bin/spack.js", + "swc": "bin/swc.js", + "swcx": "bin/swcx.js" + }, + "engines": { + "node": ">= 16.14.0" + }, + "peerDependencies": { + "@swc/core": "^1.2.66", + "chokidar": "^3.5.1" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@swc/core": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.6.6.tgz", + "integrity": "sha512-sHfmIUPUXNrQTwFMVCY5V5Ena2GTOeaWjS2GFUpjLhAgVfP90OP67DWow7+cYrfFtqBdILHuWnjkTcd0+uPKlg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.9" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.6.6", + "@swc/core-darwin-x64": "1.6.6", + "@swc/core-linux-arm-gnueabihf": "1.6.6", + "@swc/core-linux-arm64-gnu": "1.6.6", + "@swc/core-linux-arm64-musl": "1.6.6", + "@swc/core-linux-x64-gnu": "1.6.6", + "@swc/core-linux-x64-musl": "1.6.6", + "@swc/core-win32-arm64-msvc": "1.6.6", + "@swc/core-win32-ia32-msvc": "1.6.6", + "@swc/core-win32-x64-msvc": "1.6.6" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.6.6.tgz", + "integrity": "sha512-5DA8NUGECcbcK1YLKJwNDKqdtTYDVnkfDU1WvQSXq/rU+bjYCLtn5gCe8/yzL7ISXA6rwqPU1RDejhbNt4ARLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.6.6.tgz", + "integrity": "sha512-2nbh/RHpweNRsJiYDFk1KcX7UtaKgzzTNUjwtvK5cp0wWrpbXmPvdlWOx3yzwoiSASDFx78242JHHXCIOlEdsw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.6.6.tgz", + "integrity": "sha512-YgytuyUfR7b0z0SRHKV+ylr83HmgnROgeT7xryEkth6JGpAEHooCspQ4RrWTU8+WKJ7aXiZlGXPgybQ4TiS+TA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.6.6.tgz", + "integrity": "sha512-yGwx9fddzEE0iURqRVwKBQ4IwRHE6hNhl15WliHpi/PcYhzmYkUIpcbRXjr0dssubXAVPVnx6+jZVDSbutvnfg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.6.6.tgz", + "integrity": "sha512-a6fMbqzSAsS5KCxFJyg1mD5kwN3ZFO8qQLyJ75R/htZP/eCt05jrhmOI7h2n+1HjiG332jLnZ9S8lkVE5O8Nqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.6.6.tgz", + "integrity": "sha512-hRGsUKNzzZle28YF0dYIpN0bt9PceR9LaVBq7x8+l9TAaDLFbgksSxcnU/ubTtsy+WsYSYGn+A83w3xWC0O8CQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.6.6.tgz", + "integrity": "sha512-NokIUtFxJDVv3LzGeEtYMTV3j2dnGKLac59luTeq36DQLZdJQawQIdTbzzWl2jE7lxxTZme+dhsVOH9LxE3ceg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.6.6.tgz", + "integrity": "sha512-lzYdI4qb4k1dFG26yv+9Jaq/bUMAhgs/2JsrLncGjLof86+uj74wKYCQnbzKAsq2hDtS5DqnHnl+//J+miZfGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.6.6.tgz", + "integrity": "sha512-bvl7FMaXIJQ76WZU0ER4+RyfKIMGb6S2MgRkBhJOOp0i7VFx4WLOnrmMzaeoPJaJSkityVKAftfNh7NBzTIydQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.6.6.tgz", + "integrity": "sha512-WAP0JoCTfgeYKgOeYJoJV4ZS0sQUmU3OwvXa2dYYtMLF7zsNqOiW4niU7QlThBHgUv/qNZm2p6ITEgh3w1cltw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true + }, + "node_modules/@swc/types": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.9.tgz", + "integrity": "sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==", + "dev": true, + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, + "node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "15.0.18", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.18.tgz", + "integrity": "sha512-DDi2KmvAnNsT/EvU8jp1UR7pOJojBtJ3GLZ/uw1MUq4VbbESppPWoHUY4h0OB4BbEbGJiyEsmUcuZDZtoR+ZwQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/axe-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", + "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz", + "integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==", + "dev": true, + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^2.0.0", + "bare-stream": "^2.0.0" + } + }, + "node_modules/bare-os": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.0.tgz", + "integrity": "sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==", + "dev": true, + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "dev": true, + "optional": true, + "dependencies": { + "bare-os": "^2.1.0" + } + }, + "node_modules/bare-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.1.3.tgz", + "integrity": "sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==", + "dev": true, + "optional": true, + "dependencies": { + "streamx": "^2.18.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bin-check": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", + "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", + "dev": true, + "dependencies": { + "execa": "^0.7.0", + "executable": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bin-version": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", + "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "find-versions": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version-check": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.1.0.tgz", + "integrity": "sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==", + "dev": true, + "dependencies": { + "bin-version": "^6.0.0", + "semver": "^7.5.3", + "semver-truncate": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/bin-version/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/bin-version/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bin-version/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bin-version/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bin-version/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bin-version/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chrome-launcher": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", + "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chrome-launcher/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chromium-bidi": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.24.tgz", + "integrity": "sha512-5xQNN2SVBdZv4TxeMLaI+PelrnZsHDhn8h2JtyriLr+0qHcZS8BMuo93qN6J1VmtmrgYP+rmcLHcbpnA8QJh+w==", + "dev": true, + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.23.8" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-js-pure": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.2.tgz", + "integrity": "sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/csp_evaluator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/csp_evaluator/-/csp_evaluator-1.1.1.tgz", + "integrity": "sha512-N3ASg0C4kNPUaNxt1XAvzHIVuzdtr8KLgfk1O8WDyimp1GisPAHESupArO2ieHk9QWbrJ/WkQODyh21Ps/xhxw==", + "dev": true + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1312386", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", + "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", + "dev": true + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "dependencies": { + "mime-db": "^1.28.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "dependencies": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-type": { + "version": "17.1.6", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", + "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", + "dev": true, + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0-alpha.9", + "token-types": "^5.0.0-alpha.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/filename-reserved-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", + "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filenamify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", + "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^3.0.0", + "strip-outer": "^2.0.0", + "trim-repeated": "^2.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-versions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "dev": true, + "dependencies": { + "semver-regex": "^4.0.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dev": true, + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-link-header": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.1.3.tgz", + "integrity": "sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/image-ssim": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/image-ssim/-/image-ssim-0.2.0.tgz", + "integrity": "sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/intl-messageformat": { + "version": "10.5.14", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz", + "integrity": "sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/fast-memoize": "2.2.0", + "@formatjs/icu-messageformat-parser": "2.7.8", + "tslib": "^2.4.0" + } + }, + "node_modules/intl-messageformat/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "dev": true + }, + "node_modules/js-library-detector": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/js-library-detector/-/js-library-detector-6.7.0.tgz", + "integrity": "sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lighthouse": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/lighthouse/-/lighthouse-12.1.0.tgz", + "integrity": "sha512-PQLaNcv3tQcybnYux6T8uoS6+RNrNYvVJBbGo0kkbD4XTjesGslOXWeMkUQDK7c28nLfVZi7gYWDUsicTLglKQ==", + "dev": true, + "dependencies": { + "@paulirish/trace_engine": "^0.0.23", + "@sentry/node": "^6.17.4", + "axe-core": "^4.9.1", + "chrome-launcher": "^1.1.2", + "configstore": "^5.0.1", + "csp_evaluator": "1.1.1", + "devtools-protocol": "0.0.1312386", + "enquirer": "^2.3.6", + "http-link-header": "^1.1.1", + "intl-messageformat": "^10.5.3", + "jpeg-js": "^0.4.4", + "js-library-detector": "^6.7.0", + "lighthouse-logger": "^2.0.1", + "lighthouse-stack-packs": "1.12.1", + "lodash": "^4.17.21", + "lookup-closest-locale": "6.2.0", + "metaviewport-parser": "0.3.0", + "open": "^8.4.0", + "parse-cache-control": "1.0.1", + "puppeteer-core": "^22.11.1", + "robots-parser": "^3.0.1", + "semver": "^5.3.0", + "speedline-core": "^1.4.3", + "third-party-web": "^0.24.3", + "tldts-icann": "^6.1.16", + "ws": "^7.0.0", + "yargs": "^17.3.1", + "yargs-parser": "^21.0.0" + }, + "bin": { + "chrome-debug": "core/scripts/manual-chrome-launcher.js", + "lighthouse": "cli/index.js", + "smokehouse": "cli/test/smokehouse/frontends/smokehouse-bin.js" + }, + "engines": { + "node": ">=18.16" + } + }, + "node_modules/lighthouse-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", + "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/lighthouse-stack-packs": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/lighthouse-stack-packs/-/lighthouse-stack-packs-1.12.1.tgz", + "integrity": "sha512-i4jTmg7tvZQFwNFiwB+nCK6a7ICR68Xcwo+VIVd6Spi71vBNFUlds5HiDrSbClZdkQDON2Bhqv+KKJIo5zkPeA==", + "dev": true + }, + "node_modules/lighthouse/node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lighthouse/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lighthouse/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lookup-closest-locale": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/lookup-closest-locale/-/lookup-closest-locale-6.2.0.tgz", + "integrity": "sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==", + "dev": true + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/marky": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/metaviewport-parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/metaviewport-parser/-/metaviewport-parser-0.3.0.tgz", + "integrity": "sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-filter-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", + "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", + "dev": true, + "dependencies": { + "arch": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "dev": true, + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/peek-readable": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.1.0.tgz", + "integrity": "sha512-Tq2I+yoz6Xq3S09E2PyjzOy/oYuNg5v7wyjmrw7OQYSKc7QnDs63q4RXFXraMoI6LZyiEOJ/wDEYzGDPhWwNPA==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", + "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", + "dev": true, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pptr-testing-library": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/pptr-testing-library/-/pptr-testing-library-0.8.0.tgz", + "integrity": "sha512-QcaSiD3sLuxNgfl/wkv/tFB3x3bSZOPieVbmiPyoJMIWv93O2eAOhPnq8uv8qqX22o8DK+gxWgovc1XMvaioGQ==", + "dev": true, + "dependencies": { + "@testing-library/dom": "^7.31.0", + "wait-for-expect": "^3.0.2" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "puppeteer": "*" + } + }, + "node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/puppeteer": { + "version": "22.12.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.12.1.tgz", + "integrity": "sha512-1GxY8dnEnHr1SLzdSDr0FCjM6JQfAh2E2I/EqzeF8a58DbGVk9oVjj4lFdqNoVbpgFSpAbz7VER9St7S1wDpNg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@puppeteer/browsers": "2.2.3", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1299070", + "puppeteer-core": "22.12.1" + }, + "bin": { + "puppeteer": "lib/esm/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "22.12.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.12.1.tgz", + "integrity": "sha512-XmqeDPVdC5/3nGJys1jbgeoZ02wP0WV1GBlPtr/ULRbGXJFuqgXMcKQ3eeNtFpBzGRbpeoCGWHge1ZWKWl0Exw==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "2.2.3", + "chromium-bidi": "0.5.24", + "debug": "^4.3.5", + "devtools-protocol": "0.0.1299070", + "ws": "^8.17.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1299070", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1299070.tgz", + "integrity": "sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg==", + "dev": true + }, + "node_modules/puppeteer-core/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/devtools-protocol": { + "version": "0.0.1299070", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1299070.tgz", + "integrity": "sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dev": true, + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/robots-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robots-parser/-/robots-parser-3.0.1.tgz", + "integrity": "sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-truncate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", + "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "dependencies": { + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/speedline-core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/speedline-core/-/speedline-core-1.4.3.tgz", + "integrity": "sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==", + "dev": true, + "dependencies": { + "@types/node": "*", + "image-ssim": "^0.2.0", + "jpeg-js": "^0.4.1" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-outer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", + "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "dev": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", + "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", + "dev": true, + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/text-decoder": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", + "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/third-party-web": { + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.24.3.tgz", + "integrity": "sha512-imE6hXZyaCeGinGFCvpWsv0oelsEaufSG39qYBQhp3urGq4OLOtsuEddf3XgKxmAAczBD/I1Tnp8L3gJ3ksTuQ==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tldts-core": { + "version": "6.1.30", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.30.tgz", + "integrity": "sha512-CPlL58/oIvnovk5KTHIho/B0bMuvPkZrcC7f4pfQH+BBPY/mMz6CekiIdhjFxk9XZZJNirbwh1rRTSo4e5KXQA==", + "dev": true + }, + "node_modules/tldts-icann": { + "version": "6.1.30", + "resolved": "https://registry.npmjs.org/tldts-icann/-/tldts-icann-6.1.30.tgz", + "integrity": "sha512-1ekjlDThO9urnJvPJ533AS/ZY9O2E7AVNmy7yX4QDQzATuvDv8qeUuuPsc+nWoinXila5LoQVEmqOR310q34BQ==", + "dev": true, + "dependencies": { + "tldts-core": "^6.1.30" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "dev": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/trim-repeated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", + "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/wait-for-expect": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.2.tgz", + "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==", + "dev": true + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/runtime": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/runtime-corejs3": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.2.tgz", + "integrity": "sha512-54cIh74Z1rp4oIjsHjqN+WM4fMyCBYe+LpZ9jWm51CZ1fbH3SkAzQD/3XLoNkjbJ7YEmjobLXyvQrFypRHOrXw==", + "dev": true, + "requires": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + } + }, + "@formatjs/ecma402-abstract": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", + "integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==", + "dev": true, + "requires": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, + "@formatjs/fast-memoize": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz", + "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==", + "dev": true, + "requires": { + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, + "@formatjs/icu-messageformat-parser": { + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz", + "integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-skeleton-parser": "1.8.2", + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, + "@formatjs/icu-skeleton-parser": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz", + "integrity": "sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "2.0.0", + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, + "@formatjs/intl-localematcher": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", + "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==", + "dev": true, + "requires": { + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@mole-inc/bin-wrapper": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", + "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", + "dev": true, + "requires": { + "bin-check": "^4.1.0", + "bin-version-check": "^5.0.0", + "content-disposition": "^0.5.4", + "ext-name": "^5.0.0", + "file-type": "^17.1.6", + "filenamify": "^5.0.2", + "got": "^11.8.5", + "os-filter-obj": "^2.0.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@paulirish/trace_engine": { + "version": "0.0.23", + "resolved": "https://registry.npmjs.org/@paulirish/trace_engine/-/trace_engine-0.0.23.tgz", + "integrity": "sha512-2ym/q7HhC5K+akXkNV6Gip3oaHpbI6TsGjmcAsl7bcJ528MVbacPQeoauLFEeLXH4ulJvsxQwNDIg/kAEhFZxw==", + "dev": true + }, + "@puppeteer/browsers": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.3.tgz", + "integrity": "sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==", + "dev": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.4.0", + "semver": "7.6.0", + "tar-fs": "3.0.5", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.2" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@sentry/core": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz", + "integrity": "sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==", + "dev": true, + "requires": { + "@sentry/hub": "6.19.7", + "@sentry/minimal": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz", + "integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==", + "dev": true, + "requires": { + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz", + "integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==", + "dev": true, + "requires": { + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sentry/node": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.19.7.tgz", + "integrity": "sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==", + "dev": true, + "requires": { + "@sentry/core": "6.19.7", + "@sentry/hub": "6.19.7", + "@sentry/types": "6.19.7", + "@sentry/utils": "6.19.7", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", + "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==", + "dev": true + }, + "@sentry/utils": { + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", + "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", + "dev": true, + "requires": { + "@sentry/types": "6.19.7", + "tslib": "^1.9.3" + } + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true + }, + "@swc/cli": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.4.0.tgz", + "integrity": "sha512-4JdVrPtF/4rCMXp6Q1h5I6YkYZrCCcqod7Wk97ZQq7K8vNGzJUryBv4eHCvqx5sJOJBrbYm9fcswe1B0TygNoA==", + "dev": true, + "requires": { + "@mole-inc/bin-wrapper": "^8.0.1", + "@swc/counter": "^0.1.3", + "commander": "^8.3.0", + "fast-glob": "^3.2.5", + "minimatch": "^9.0.3", + "piscina": "^4.3.0", + "semver": "^7.3.8", + "slash": "3.0.0", + "source-map": "^0.7.3" + } + }, + "@swc/core": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.6.6.tgz", + "integrity": "sha512-sHfmIUPUXNrQTwFMVCY5V5Ena2GTOeaWjS2GFUpjLhAgVfP90OP67DWow7+cYrfFtqBdILHuWnjkTcd0+uPKlg==", + "dev": true, + "requires": { + "@swc/core-darwin-arm64": "1.6.6", + "@swc/core-darwin-x64": "1.6.6", + "@swc/core-linux-arm-gnueabihf": "1.6.6", + "@swc/core-linux-arm64-gnu": "1.6.6", + "@swc/core-linux-arm64-musl": "1.6.6", + "@swc/core-linux-x64-gnu": "1.6.6", + "@swc/core-linux-x64-musl": "1.6.6", + "@swc/core-win32-arm64-msvc": "1.6.6", + "@swc/core-win32-ia32-msvc": "1.6.6", + "@swc/core-win32-x64-msvc": "1.6.6", + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.9" + } + }, + "@swc/core-darwin-arm64": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.6.6.tgz", + "integrity": "sha512-5DA8NUGECcbcK1YLKJwNDKqdtTYDVnkfDU1WvQSXq/rU+bjYCLtn5gCe8/yzL7ISXA6rwqPU1RDejhbNt4ARLQ==", + "dev": true, + "optional": true + }, + "@swc/core-darwin-x64": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.6.6.tgz", + "integrity": "sha512-2nbh/RHpweNRsJiYDFk1KcX7UtaKgzzTNUjwtvK5cp0wWrpbXmPvdlWOx3yzwoiSASDFx78242JHHXCIOlEdsw==", + "dev": true, + "optional": true + }, + "@swc/core-linux-arm-gnueabihf": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.6.6.tgz", + "integrity": "sha512-YgytuyUfR7b0z0SRHKV+ylr83HmgnROgeT7xryEkth6JGpAEHooCspQ4RrWTU8+WKJ7aXiZlGXPgybQ4TiS+TA==", + "dev": true, + "optional": true + }, + "@swc/core-linux-arm64-gnu": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.6.6.tgz", + "integrity": "sha512-yGwx9fddzEE0iURqRVwKBQ4IwRHE6hNhl15WliHpi/PcYhzmYkUIpcbRXjr0dssubXAVPVnx6+jZVDSbutvnfg==", + "dev": true, + "optional": true + }, + "@swc/core-linux-arm64-musl": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.6.6.tgz", + "integrity": "sha512-a6fMbqzSAsS5KCxFJyg1mD5kwN3ZFO8qQLyJ75R/htZP/eCt05jrhmOI7h2n+1HjiG332jLnZ9S8lkVE5O8Nqw==", + "dev": true, + "optional": true + }, + "@swc/core-linux-x64-gnu": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.6.6.tgz", + "integrity": "sha512-hRGsUKNzzZle28YF0dYIpN0bt9PceR9LaVBq7x8+l9TAaDLFbgksSxcnU/ubTtsy+WsYSYGn+A83w3xWC0O8CQ==", + "dev": true, + "optional": true + }, + "@swc/core-linux-x64-musl": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.6.6.tgz", + "integrity": "sha512-NokIUtFxJDVv3LzGeEtYMTV3j2dnGKLac59luTeq36DQLZdJQawQIdTbzzWl2jE7lxxTZme+dhsVOH9LxE3ceg==", + "dev": true, + "optional": true + }, + "@swc/core-win32-arm64-msvc": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.6.6.tgz", + "integrity": "sha512-lzYdI4qb4k1dFG26yv+9Jaq/bUMAhgs/2JsrLncGjLof86+uj74wKYCQnbzKAsq2hDtS5DqnHnl+//J+miZfGA==", + "dev": true, + "optional": true + }, + "@swc/core-win32-ia32-msvc": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.6.6.tgz", + "integrity": "sha512-bvl7FMaXIJQ76WZU0ER4+RyfKIMGb6S2MgRkBhJOOp0i7VFx4WLOnrmMzaeoPJaJSkityVKAftfNh7NBzTIydQ==", + "dev": true, + "optional": true + }, + "@swc/core-win32-x64-msvc": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.6.6.tgz", + "integrity": "sha512-WAP0JoCTfgeYKgOeYJoJV4ZS0sQUmU3OwvXa2dYYtMLF7zsNqOiW4niU7QlThBHgUv/qNZm2p6ITEgh3w1cltw==", + "dev": true, + "optional": true + }, + "@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true + }, + "@swc/types": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.9.tgz", + "integrity": "sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==", + "dev": true, + "requires": { + "@swc/counter": "^0.1.3" + } + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + } + }, + "@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true + }, + "@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, + "@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true + }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/yargs": { + "version": "15.0.18", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.18.tgz", + "integrity": "sha512-DDi2KmvAnNsT/EvU8jp1UR7pOJojBtJ3GLZ/uw1MUq4VbbESppPWoHUY4h0OB4BbEbGJiyEsmUcuZDZtoR+ZwQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, + "axe-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", + "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "dev": true + }, + "b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "optional": true + }, + "bare-fs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz", + "integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==", + "dev": true, + "optional": true, + "requires": { + "bare-events": "^2.0.0", + "bare-path": "^2.0.0", + "bare-stream": "^2.0.0" + } + }, + "bare-os": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.0.tgz", + "integrity": "sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==", + "dev": true, + "optional": true + }, + "bare-path": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "dev": true, + "optional": true, + "requires": { + "bare-os": "^2.1.0" + } + }, + "bare-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.1.3.tgz", + "integrity": "sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==", + "dev": true, + "optional": true, + "requires": { + "streamx": "^2.18.0" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true + }, + "bin-check": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", + "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "executable": "^4.1.0" + } + }, + "bin-version": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", + "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "find-versions": "^5.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "bin-version-check": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.1.0.tgz", + "integrity": "sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==", + "dev": true, + "requires": { + "bin-version": "^6.0.0", + "semver": "^7.5.3", + "semver-truncate": "^3.0.0" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, + "bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "requires": { + "run-applescript": "^7.0.0" + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true + }, + "cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chrome-launcher": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", + "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", + "dev": true, + "requires": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + } + } + }, + "chromium-bidi": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.24.tgz", + "integrity": "sha512-5xQNN2SVBdZv4TxeMLaI+PelrnZsHDhn8h2JtyriLr+0qHcZS8BMuo93qN6J1VmtmrgYP+rmcLHcbpnA8QJh+w==", + "dev": true, + "requires": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.23.8" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/core-js-pure": { - "version": "3.33.2", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.2.tgz", - "integrity": "sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q==", + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "core-js-pure": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.2.tgz", + "integrity": "sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q==", + "dev": true + }, + "cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "requires": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "csp_evaluator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/csp_evaluator/-/csp_evaluator-1.1.1.tgz", + "integrity": "sha512-N3ASg0C4kNPUaNxt1XAvzHIVuzdtr8KLgfk1O8WDyimp1GisPAHESupArO2ieHk9QWbrJ/WkQODyh21Ps/xhxw==", + "dev": true + }, + "data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true + }, + "debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } + } + }, + "default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "requires": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + } + }, + "default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true + }, + "degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "requires": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + } + }, + "devtools-protocol": { + "version": "0.0.1312386", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", + "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", + "dev": true + }, + "dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "requires": { + "pify": "^2.2.0" + } + }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "file-type": { + "version": "17.1.6", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", + "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", + "dev": true, + "requires": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0-alpha.9", + "token-types": "^5.0.0-alpha.2" + } + }, + "filename-reserved-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", + "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", + "dev": true + }, + "filenamify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", + "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", + "dev": true, + "requires": { + "filename-reserved-regex": "^3.0.0", + "strip-outer": "^2.0.0", + "trim-repeated": "^2.0.0" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-versions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "dev": true, + "requires": { + "semver-regex": "^4.0.5" + } + }, + "fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true + }, + "get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dev": true, + "requires": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "http-link-header": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.1.3.tgz", + "integrity": "sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==", + "dev": true + }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + } + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "image-ssim": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/image-ssim/-/image-ssim-0.2.0.tgz", + "integrity": "sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "intl-messageformat": { + "version": "10.5.14", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz", + "integrity": "sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/fast-memoize": "2.2.0", + "@formatjs/icu-messageformat-parser": "2.7.8", + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + } + } + }, + "ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "requires": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "requires": { + "is-docker": "^3.0.0" + }, + "dependencies": { + "is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true + } + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "dev": true + }, + "js-library-detector": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/js-library-detector/-/js-library-detector-6.7.0.tgz", + "integrity": "sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "lighthouse": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/lighthouse/-/lighthouse-12.1.0.tgz", + "integrity": "sha512-PQLaNcv3tQcybnYux6T8uoS6+RNrNYvVJBbGo0kkbD4XTjesGslOXWeMkUQDK7c28nLfVZi7gYWDUsicTLglKQ==", + "dev": true, + "requires": { + "@paulirish/trace_engine": "^0.0.23", + "@sentry/node": "^6.17.4", + "axe-core": "^4.9.1", + "chrome-launcher": "^1.1.2", + "configstore": "^5.0.1", + "csp_evaluator": "1.1.1", + "devtools-protocol": "0.0.1312386", + "enquirer": "^2.3.6", + "http-link-header": "^1.1.1", + "intl-messageformat": "^10.5.3", + "jpeg-js": "^0.4.4", + "js-library-detector": "^6.7.0", + "lighthouse-logger": "^2.0.1", + "lighthouse-stack-packs": "1.12.1", + "lodash": "^4.17.21", + "lookup-closest-locale": "6.2.0", + "metaviewport-parser": "0.3.0", + "open": "^8.4.0", + "parse-cache-control": "1.0.1", + "puppeteer-core": "^22.11.1", + "robots-parser": "^3.0.1", + "semver": "^5.3.0", + "speedline-core": "^1.4.3", + "third-party-web": "^0.24.3", + "tldts-icann": "^6.1.16", + "ws": "^7.0.0", + "yargs": "^17.3.1", + "yargs-parser": "^21.0.0" + }, + "dependencies": { + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "lighthouse-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", + "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "marky": "^1.2.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "lighthouse-stack-packs": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/lighthouse-stack-packs/-/lighthouse-stack-packs-1.12.1.tgz", + "integrity": "sha512-i4jTmg7tvZQFwNFiwB+nCK6a7ICR68Xcwo+VIVd6Spi71vBNFUlds5HiDrSbClZdkQDON2Bhqv+KKJIo5zkPeA==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lookup-closest-locale": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/lookup-closest-locale/-/lookup-closest-locale-6.2.0.tgz", + "integrity": "sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "marky": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", + "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "metaviewport-parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/metaviewport-parser/-/metaviewport-parser-0.3.0.tgz", + "integrity": "sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ==", + "dev": true + }, + "micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true + }, + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "dev": true, + "optional": true + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "requires": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "requires": { + "is-inside-container": "^1.0.0" + } + } + } + }, + "os-filter-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", + "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", + "dev": true, + "requires": { + "arch": "^2.1.0" + } + }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true + }, + "pac-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "dev": true, + "requires": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" + }, + "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + } + } + }, + "pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "requires": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "peek-readable": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.1.0.tgz", + "integrity": "sha512-Tq2I+yoz6Xq3S09E2PyjzOy/oYuNg5v7wyjmrw7OQYSKc7QnDs63q4RXFXraMoI6LZyiEOJ/wDEYzGDPhWwNPA==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, + "piscina": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", + "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", + "dev": true, + "requires": { + "nice-napi": "^1.0.2" + } + }, + "pptr-testing-library": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/pptr-testing-library/-/pptr-testing-library-0.8.0.tgz", + "integrity": "sha512-QcaSiD3sLuxNgfl/wkv/tFB3x3bSZOPieVbmiPyoJMIWv93O2eAOhPnq8uv8qqX22o8DK+gxWgovc1XMvaioGQ==", + "dev": true, + "requires": { + "@testing-library/dom": "^7.31.0", + "wait-for-expect": "^3.0.2" + } + }, + "pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "puppeteer": { + "version": "22.12.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.12.1.tgz", + "integrity": "sha512-1GxY8dnEnHr1SLzdSDr0FCjM6JQfAh2E2I/EqzeF8a58DbGVk9oVjj4lFdqNoVbpgFSpAbz7VER9St7S1wDpNg==", + "dev": true, + "requires": { + "@puppeteer/browsers": "2.2.3", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1299070", + "puppeteer-core": "22.12.1" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.1299070", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1299070.tgz", + "integrity": "sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg==", + "dev": true + } + } + }, + "puppeteer-core": { + "version": "22.12.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.12.1.tgz", + "integrity": "sha512-XmqeDPVdC5/3nGJys1jbgeoZ02wP0WV1GBlPtr/ULRbGXJFuqgXMcKQ3eeNtFpBzGRbpeoCGWHge1ZWKWl0Exw==", + "dev": true, + "requires": { + "@puppeteer/browsers": "2.2.3", + "chromium-bidi": "0.5.24", + "debug": "^4.3.5", + "devtools-protocol": "0.0.1299070", + "ws": "^8.17.1" + }, + "dependencies": { + "devtools-protocol": { + "version": "0.0.1299070", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1299070.tgz", + "integrity": "sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg==", + "dev": true + }, + "ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "requires": {} + } + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "requires": { + "readable-stream": "^3.6.0" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", "dev": true }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true }, - "node_modules/has-flag": { + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", "dev": true, - "engines": { - "node": ">=8" + "requires": { + "lowercase-keys": "^2.0.0" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "node_modules/lighthouse": { - "resolved": "../node_modules/.pnpm/lighthouse@10.2.0/node_modules/lighthouse", - "link": true + "robots-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robots-parser/-/robots-parser-3.0.1.tgz", + "integrity": "sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==", + "dev": true }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, - "bin": { - "lz-string": "bin/bin.js" + "requires": { + "queue-microtask": "^1.2.2" } }, - "node_modules/node-fetch": { - "resolved": "../node_modules/.pnpm/node-fetch@3.3.2/node_modules/node-fetch", - "link": true + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true }, - "node_modules/open": { - "resolved": "../node_modules/.pnpm/open@8.4.2/node_modules/open", - "link": true + "semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true }, - "node_modules/pptr-testing-library": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/pptr-testing-library/-/pptr-testing-library-0.7.0.tgz", - "integrity": "sha512-NYt6XQzAoWCC/WKkBWW40Uth+MBRKmdYr+3NdrF4gTgBeK31zNQN6gFvmTubjZY5mUVdHmPns60jTs7PZuwg2A==", + "semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true + }, + "semver-truncate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", + "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", "dev": true, - "dependencies": { - "@testing-library/dom": "^7.31.0", - "wait-for-expect": "^3.0.2" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "puppeteer": "*" + "requires": { + "semver": "^7.3.5" } }, - "node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" + "requires": { + "shebang-regex": "^1.0.0" } }, - "node_modules/puppeteer": { - "resolved": "../node_modules/.pnpm/puppeteer@19.11.1/node_modules/puppeteer", - "link": true + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "requires": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" } }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/wait-for-expect": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.2.tgz", - "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==", - "dev": true - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "debug": "^4.3.4" } } } }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } }, - "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "sort-keys": "^1.0.0" } }, - "@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, + "speedline-core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/speedline-core/-/speedline-core-1.4.3.tgz", + "integrity": "sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==", "dev": true, "requires": { - "regenerator-runtime": "^0.14.0" + "@types/node": "*", + "image-ssim": "^0.2.0", + "jpeg-js": "^0.4.1" } }, - "@babel/runtime-corejs3": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.2.tgz", - "integrity": "sha512-54cIh74Z1rp4oIjsHjqN+WM4fMyCBYe+LpZ9jWm51CZ1fbH3SkAzQD/3XLoNkjbJ7YEmjobLXyvQrFypRHOrXw==", + "sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", "dev": true, "requires": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" + "bare-events": "^2.2.0", + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" } }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "safe-buffer": "~5.2.0" } }, - "@swc/cli": { - "version": "file:../node_modules/.pnpm/@swc+cli@0.1.62_@swc+core@1.3.58/node_modules/@swc/cli", + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "requires": { - "@mole-inc/bin-wrapper": "^8.0.1", - "@swc/cli": "^0.1.43", - "@swc/core": "^1.2.66", - "@swc/jest": "^0.1.2", - "@types/jest": "^26.0.23", - "@types/node": "^12.19.16", - "@types/semver": "^7.3.13", - "chokidar": "^3.5.1", - "commander": "^7.1.0", - "deepmerge": "^4.2.2", - "fast-glob": "^3.2.5", - "jest": "^27.0.3", - "nano-staged": "^0.4.5", - "prettier": "^2.5.1", - "semver": "^7.3.8", - "simple-git-hooks": "^2.7.0", - "slash": "3.0.0", - "source-map": "^0.7.3", - "ts-jest": "^27.0.4", - "typescript": "~4.3.2" - } - }, - "@swc/core": { - "version": "file:../node_modules/.pnpm/@swc+core@1.3.58/node_modules/@swc/core", - "requires": { - "@babel/compat-data": "^7.17.0", - "@babel/core": "^7.13.16", - "@babel/generator": "^7.18.13", - "@babel/plugin-proposal-class-properties": "^7.13.0", - "@babel/plugin-proposal-decorators": "^7.13.15", - "@babel/plugin-proposal-object-rest-spread": "^7.13.8", - "@babel/preset-env": "^7.13.15", - "@babel/preset-react": "^7.13.13", - "@babel/preset-typescript": "^7.13.0", - "@babel/types": "^7.14.0", - "@napi-rs/cli": "^2.14.1", - "@swc/core": "=1.2.220", - "@swc/core-darwin-arm64": "1.3.58", - "@swc/core-darwin-x64": "1.3.58", - "@swc/core-linux-arm-gnueabihf": "1.3.58", - "@swc/core-linux-arm64-gnu": "1.3.58", - "@swc/core-linux-arm64-musl": "1.3.58", - "@swc/core-linux-x64-gnu": "1.3.58", - "@swc/core-linux-x64-musl": "1.3.58", - "@swc/core-win32-arm64-msvc": "1.3.58", - "@swc/core-win32-ia32-msvc": "1.3.58", - "@swc/core-win32-x64-msvc": "1.3.58", - "@swc/helpers": "^0.5.0", - "@swc/plugin-jest": "latest", - "@taplo/cli": "^0.3.2", - "@types/jest": "^28.1.4", - "@types/node": "^14.14.41", - "@types/terser": "^3.12.0", - "acorn": "^8.6.0", - "acorn-jsx": "^5.3.2", - "axios": "^0.21.1", - "babel-plugin-transform-node-env-inline": "^0.4.3", - "benchmark": "^2.1.4", - "bootstrap": "^5.2.1", - "class-validator": "^0.13.1", - "core-js": "^2.6.11", - "core-js-compat": "^3.21.1", - "cross-env": "^7.0.3", - "cspell": "^5.12.3", - "expect": "^27.4.2", - "glob": "^8.0.3", - "husky": "^7.0.2", - "jest": "^28.1.2", - "js-beautify": "^1.14.3", - "lint-staged": "^12.3.6", - "lodash": "^4.17.21", - "mocha": "^9.1.3", - "npm-run-all": "^4.1.5", - "prettier": "^2.6.2", - "progress": "^2.0.3", - "prop-types": "^15.7.2", - "react": "^17.0.2", - "reflect-metadata": "^0.1.13", - "regenerator-runtime": "^0.13.9", - "source-map": "^0.7.3", - "source-map-support": "^0.5.19", - "sourcemap-validator": "^2.1.0", - "swc-plugin-coverage-instrument": "^0.0.12", - "terser": "^5.7.1", - "ts-node": "^10.5.0", - "typescript": "^4.5.2" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "@testing-library/dom": { - "version": "7.31.2", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", - "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^4.2.2", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.6", - "lz-string": "^1.4.4", - "pretty-format": "^26.6.2" + "ansi-regex": "^5.0.1" } }, - "@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", "dev": true }, - "@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, - "@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "strip-outer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", + "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", + "dev": true + }, + "strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "*" + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" } }, - "@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "@types/istanbul-lib-report": "*" + "has-flag": "^4.0.0" } }, - "@types/node": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", - "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "tar-fs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", + "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", "dev": true, "requires": { - "undici-types": "~5.26.4" + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" } }, - "@types/yargs": { - "version": "15.0.18", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.18.tgz", - "integrity": "sha512-DDi2KmvAnNsT/EvU8jp1UR7pOJojBtJ3GLZ/uw1MUq4VbbESppPWoHUY4h0OB4BbEbGJiyEsmUcuZDZtoR+ZwQ==", + "tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, - "@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "text-decoder": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", + "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "dev": true, + "requires": { + "b4a": "^1.6.4" + } + }, + "third-party-web": { + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.24.3.tgz", + "integrity": "sha512-imE6hXZyaCeGinGFCvpWsv0oelsEaufSG39qYBQhp3urGq4OLOtsuEddf3XgKxmAAczBD/I1Tnp8L3gJ3ksTuQ==", "dev": true }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "tldts-core": { + "version": "6.1.30", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.30.tgz", + "integrity": "sha512-CPlL58/oIvnovk5KTHIho/B0bMuvPkZrcC7f4pfQH+BBPY/mMz6CekiIdhjFxk9XZZJNirbwh1rRTSo4e5KXQA==", + "dev": true + }, + "tldts-icann": { + "version": "6.1.30", + "resolved": "https://registry.npmjs.org/tldts-icann/-/tldts-icann-6.1.30.tgz", + "integrity": "sha512-1ekjlDThO9urnJvPJ533AS/ZY9O2E7AVNmy7yX4QDQzATuvDv8qeUuuPsc+nWoinXila5LoQVEmqOR310q34BQ==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "tldts-core": "^6.1.30" } }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "is-number": "^7.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "trim-repeated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", + "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "escape-string-regexp": "^5.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + } } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "core-js-pure": { - "version": "3.33.2", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.2.tgz", - "integrity": "sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q==", - "dev": true + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } }, - "dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", "dev": true }, - "lighthouse": { - "version": "file:../node_modules/.pnpm/lighthouse@10.2.0/node_modules/lighthouse", - "requires": { - "@build-tracker/cli": "^1.0.0-beta.15", - "@esbuild-kit/esm-loader": "^2.1.1", - "@jest/fake-timers": "^28.1.0", - "@rollup/plugin-alias": "^3.1.2", - "@rollup/plugin-commonjs": "^20.0.0", - "@rollup/plugin-dynamic-import-vars": "^1.1.1", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.4", - "@rollup/plugin-typescript": "^8.2.5", - "@sentry/node": "^6.17.4", - "@stadtlandnetz/rollup-plugin-postprocess": "^1.1.0", - "@testing-library/preact": "^3.1.1", - "@testing-library/preact-hooks": "^1.1.0", - "@types/archiver": "^2.1.2", - "@types/chrome": "^0.0.154", - "@types/configstore": "^4.0.0", - "@types/cpy": "^5.1.0", - "@types/debug": "^4.1.7", - "@types/eslint": "^8.2.1", - "@types/estree": "^0.0.50", - "@types/gh-pages": "^2.0.0", - "@types/google.analytics": "0.0.39", - "@types/jpeg-js": "^0.3.7", - "@types/jsdom": "^16.2.13", - "@types/lodash": "^4.14.178", - "@types/mocha": "^9.0.0", - "@types/node": "*", - "@types/pako": "^1.0.1", - "@types/resize-observer-browser": "^0.1.1", - "@types/semver": "^5.5.0", - "@types/tabulator-tables": "^4.9.1", - "@types/ws": "^7.0.0", - "@types/yargs": "^17.0.8", - "@types/yargs-parser": "^20.2.1", - "@typescript-eslint/eslint-plugin": "^5.48.0", - "@typescript-eslint/parser": "^5.48.0", - "acorn": "^8.5.0", - "angular": "^1.7.4", - "archiver": "^3.0.0", - "axe-core": "4.7.0", - "c8": "^7.11.3", - "chalk": "^2.4.1", - "chrome-devtools-frontend": "1.0.1070764", - "chrome-launcher": "^0.15.2", - "concurrently": "^6.4.0", - "configstore": "^5.0.1", - "conventional-changelog-cli": "^2.1.1", - "cpy": "^8.1.2", - "cross-env": "^7.0.2", - "csp_evaluator": "1.1.1", - "csv-validator": "^0.0.3", - "devtools-protocol": "0.0.1130274", - "enquirer": "^2.3.6", - "es-main": "^1.0.2", - "eslint": "^8.4.1", - "eslint-config-google": "^0.14.0", - "eslint-formatter-codeframe": "^7.32.1", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-local-rules": "1.1.0", - "event-target-shim": "^6.0.2", - "expect": "^28.1.0", - "firebase": "^9.0.2", - "gh-pages": "^2.0.1", - "glob": "^7.1.3", - "http-link-header": "^1.1.1", - "idb-keyval": "2.2.0", - "intl-messageformat": "^4.4.0", - "intl-messageformat-parser": "^1.8.1", - "jest-mock": "^27.3.0", - "jest-snapshot": "^28.1.0", - "jpeg-js": "^0.4.4", - "js-library-detector": "^6.6.0", - "jsdom": "^12.2.0", - "lighthouse-logger": "^1.3.0", - "lighthouse-plugin-publisher-ads": "1.5.7-beta", - "lighthouse-plugin-soft-navigation": "^1.0.1", - "lighthouse-stack-packs": "1.10.0", - "lodash": "^4.17.21", - "lookup-closest-locale": "6.2.0", - "magic-string": "^0.25.7", - "metaviewport-parser": "0.3.0", - "mime-types": "^2.1.30", - "mocha": "^10.0.0", - "node-fetch": "^2.6.1", - "npm-run-posix-or-windows": "^2.0.2", - "open": "^8.4.0", - "pako": "^2.0.3", - "parse-cache-control": "1.0.1", - "preact": "^10.7.2", - "pretty-json-stringify": "^0.0.2", - "ps-list": "^8.0.0", - "puppeteer": "^20.1.0", - "puppeteer-core": "^20.1.0", - "resolve": "^1.20.0", - "robots-parser": "^3.0.0", - "rollup": "^2.52.7", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-polyfill-node": "^0.12.0", - "rollup-plugin-replace": "^2.2.0", - "rollup-plugin-shim": "^1.0.0", - "rollup-plugin-terser": "^7.0.2", - "semver": "^5.3.0", - "speedline-core": "^1.4.3", - "tabulator-tables": "^4.9.3", - "terser": "^5.3.8", - "testdouble": "^3.16.8", - "third-party-web": "^0.20.2", - "typed-query-selector": "^2.6.1", - "typescript": "^5.0.4", - "wait-for-expect": "^3.0.2", - "webtreemap-cdt": "^3.2.1", - "ws": "^7.0.0", - "yargs": "^17.3.1", - "yargs-parser": "^21.0.0" - } + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true }, - "lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "wait-for-expect": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.2.tgz", + "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==", "dev": true }, - "node-fetch": { - "version": "file:../node_modules/.pnpm/node-fetch@3.3.2/node_modules/node-fetch", + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "requires": { - "abort-controller": "^3.0.0", - "abortcontroller-polyfill": "^1.7.1", - "busboy": "^1.4.0", - "c8": "^7.7.2", - "chai": "^4.3.4", - "chai-as-promised": "^7.1.1", - "chai-iterator": "^3.0.2", - "chai-string": "^1.5.0", - "coveralls": "^3.1.0", - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "form-data": "^4.0.0", - "formdata-node": "^4.2.4", - "formdata-polyfill": "^4.0.10", - "mocha": "^9.1.3", - "p-timeout": "^5.0.0", - "stream-consumers": "^1.0.1", - "tsd": "^0.14.0", - "xo": "^0.39.1" + "isexe": "^2.0.0" } }, - "open": { - "version": "file:../node_modules/.pnpm/open@8.4.2/node_modules/open", + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "requires": { - "@types/node": "^15.0.0", - "ava": "^3.15.0", - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0", - "tsd": "^0.14.0", - "xo": "^0.39.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, - "pptr-testing-library": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/pptr-testing-library/-/pptr-testing-library-0.7.0.tgz", - "integrity": "sha512-NYt6XQzAoWCC/WKkBWW40Uth+MBRKmdYr+3NdrF4gTgBeK31zNQN6gFvmTubjZY5mUVdHmPns60jTs7PZuwg2A==", + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "requires": { - "@testing-library/dom": "^7.31.0", - "wait-for-expect": "^3.0.2" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } + "requires": {} }, - "puppeteer": { - "version": "file:../node_modules/.pnpm/puppeteer@19.11.1/node_modules/puppeteer", - "requires": { - "@puppeteer/browsers": "0.5.0", - "cosmiconfig": "8.1.3", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.11.1" - } + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, - "regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" } }, - "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, - "wait-for-expect": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.2.tgz", - "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==", + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "dev": true } } diff --git a/centreon/lighthouse/package.json b/centreon/lighthouse/package.json index 84817c7f46..90f0c551c9 100644 --- a/centreon/lighthouse/package.json +++ b/centreon/lighthouse/package.json @@ -3,20 +3,22 @@ "version": "22.4.0", "description": "This is handle Lighthouse report", "scripts": { + "update:deps": "pnpx npm-check-updates -i --format group", "start:docker": "docker run -d -p 4000:80 --name centreon-dev docker.centreon.com/centreon/centreon-web-alma9:develop", "kill:docker": "docker stop centreon-dev && docker rm centreon-dev", - "run:lighthouse": "swc src/ -d build && node --experimental-modules --es-module-specifier-resolution=node ./build/lighthouseReport.js", + "run:lighthouse": "swc src/ -d build --strip-leading-paths && node --import=extensionless/register ./build/lighthouseReport.js", "start": "npm run start:docker && npm run run:lighthouse && npm run kill:docker", "eslint": "eslint . --ext .js,.jsx,.ts,.tsx", "eslint:fix": "pnpm eslint --fix" }, "type": "module", "devDependencies": { - "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.35", - "lighthouse": "^10.0.0", - "open": "^8.4.0", - "pptr-testing-library": "^0.7.0", - "puppeteer": "^19.7.0" + "@swc/cli": "^0.4.0", + "@swc/core": "^1.6.6", + "extensionless": "^1.9.9", + "lighthouse": "^12.1.0", + "open": "^10.1.0", + "pptr-testing-library": "^0.8.0", + "puppeteer": "^22.12.1" } } diff --git a/centreon/lighthouse/tsconfig.json b/centreon/lighthouse/tsconfig.json index 152b936ead..c75f79c2f2 100644 --- a/centreon/lighthouse/tsconfig.json +++ b/centreon/lighthouse/tsconfig.json @@ -4,10 +4,11 @@ "baseUrl": "./src", "typeRoots": ["./node_modules/@types"], "module": "nodenext", + "moduleResolution": "nodenext", "outDir": "build", "esModuleInterop": true, "resolveJsonModule": true }, "include": ["./**/*.ts"], "exclude": ["node_modules"] -} \ No newline at end of file +} diff --git a/centreon/lua/centreon-cloud-notifications.lua b/centreon/lua/centreon-cloud-notifications.lua index 662d67ad3d..a45d0f1340 100644 --- a/centreon/lua/centreon-cloud-notifications.lua +++ b/centreon/lua/centreon-cloud-notifications.lua @@ -142,9 +142,11 @@ local function get_configuration() if not ok then broker_log:error(0, "Unable to call the API to get the configuration.: " .. tostring(err)) end - update_conf(full.resp) local resp_code = c:getinfo(cURL.INFO_RESPONSE_CODE) broker_log:info(2, "Response code: " .. resp_code) + if resp_code == 200 then + update_conf(full.resp) + end if resp_code == 401 then broker_log:info(1, "Expired token. Trying to get a new one") login() @@ -165,7 +167,7 @@ end -- notification ID. -- @param id The notification ID we know from the first API configuration. -- @return A table with the notification content. -local function get_notification(id) +local function get_notification_rule(id) local content = {} local loop = true while loop do @@ -202,6 +204,87 @@ local function get_notification(id) return content end + +--- Get the notification configuration from the API. The parameter is the +-- notification ID. +-- @param id The notification ID we know from the first API configuration. +-- @return A table with the notification content. +local function get_notification(id) + local content = {} + local loop = true + while loop do + local c = cURL.easy{ + url = data.base_url .. "/configuration/notifications/" .. id, + post = false, + httpheader = { + 'Content-Type: application/json', + 'x-AUTH-TOKEN: ' .. tostring(data.token), + }, + writefunction = function(resp) + content = broker.json_decode(resp) + if content then + broker_log:info(2, resp) + else + broker_log:error(0, "Unable to decode the message '" .. tostring(resp) .. "'") + end + end, + } + ok, err = c:perform() + if not ok then + broker_log:error(0, "Unable to call the API to get the notif " .. id .. ": " .. tostring(err)) + end + local resp_code = c:getinfo(cURL.INFO_RESPONSE_CODE) + broker_log:info(2, "response code: " .. resp_code) + if resp_code == 401 then + broker_log:info(1, "Expired token. Trying to get a new one") + login() + else + loop = false + end + c:close() + end + return content +end + +--- Get the time periods from the API. +-- @return A table with the time periods content. +local function get_time_period(id) + local content = {} + local loop = true + while loop do + local c = cURL.easy{ + url = data.base_url .. "/configuration/timeperiods/" .. id, + post = false, + httpheader = { + 'Content-Type: application/json', + 'x-AUTH-TOKEN: ' .. tostring(data.token), + }, + writefunction = function(resp) + content = broker.json_decode(resp) + if content then + broker_log:info(2, resp) + else + broker_log:error(0, "Unable to decode the message '" .. tostring(resp) .. "'") + end + end, + } + ok, err = c:perform() + if not ok then + broker_log:error(0, "Unable to call the API to get time period : " .. tostring(err)) + end + local resp_code = c:getinfo(cURL.INFO_RESPONSE_CODE) + broker_log:info(2, "response code: " .. resp_code) + if resp_code == 401 then + broker_log:info(1, "Expired token. Trying to get a new one") + login() + else + loop = false + end + c:close() + end + return content +end + --- Fill a table with various key from the received event and the corresponding -- resource configuration. -- @param event A service status or a host status. @@ -382,6 +465,12 @@ function init(conf) end end +local function is_notifiable(notification) + local notif = get_notification(notification.notification_id) + local time_period = get_time_period(notif.timeperiod.id) + return time_period.in_period == true +end + function write(d) local now = os.time() if now >= data.last_refresh + data.refresh_delay then @@ -392,7 +481,7 @@ function write(d) -- PbServiceStatus if d._type == 65565 then -- Notification is done only on resources not in downtime and not acknowledged. - if d.scheduled_downtime_depth == 0 and d.acknowledgement_type == 0 then + if (d.scheduled_downtime_depth == 0 or d.scheduled_downtime_depth == nil) and (d.acknowledgement_type == 0 or d.acknowledgement_type == nil) then -- Look for the host containing this service in the notification configuration local host = data.host[d.host_id] if host then @@ -415,14 +504,22 @@ function write(d) broker_log:info(2, "Notification on service (" .. d.host_id .. "," .. d.service_id .. ") --- state: " .. d.state .. " ; notification_id: " .. svc.notification_id) - local notif = get_notification(svc.notification_id) + local notif = get_notification_rule(svc.notification_id) + if is_notifiable(notif) == false then + goto continue + end + if notif and notif.channels and notif.channels.email then notif = notif.channels.email send_mail(notif, d, svc, hostname) end end end + + ::continue:: end + else + broker_log:info(2, "host " .. d.host_id .. " not found") end else if d.scheduled_downtime_depth > 0 then @@ -434,7 +531,7 @@ function write(d) -- PbHostStatus elseif d._type == 65568 then -- Notification is done only on resources not in downtime and not acknowledged. - if d.scheduled_downtime_depth == 0 and d.acknowledgement_type == 0 then + if (d.scheduled_downtime_depth == 0 or d.scheduled_downtime_depth == nil) and (d.acknowledgement_type == 0 or d.acknowledgement_type == nil) then -- Looking for the host in the notification configuration local hst = data.host[d.host_id] -- We check that @@ -454,7 +551,12 @@ function write(d) broker_log:info(2, "Notification on host " .. d.host_id .. " --- notification_id: " .. hnotif.notification_id .. " state: " .. d.state) - local notif = get_notification(hnotif.notification_id) + + local notif = get_notification_rule(hnotif.notification_id) + if is_notifiable(notif) == false then + goto continue + end + if notif.channels and notif.channels.email then notif = notif.channels.email local host = { @@ -464,7 +566,11 @@ function write(d) send_mail(notif, d, host) end end + + ::continue:: end + else + broker_log:info(2, "host " .. d.host_id .. " not found") end else if d.scheduled_downtime_depth > 0 then diff --git a/centreon/package.json b/centreon/package.json index e25fad8a1e..8c2e47711b 100644 --- a/centreon/package.json +++ b/centreon/package.json @@ -1,186 +1,170 @@ { - "name": "centreon", - "version": "23.4.0", - "description": "centreon web package", - "scripts": { - "update:deps": "pnpx npm-check-updates -i --format group", - "widgets:build": "(cd www/widgets && pnpm build $WIDGETS)", - "widgets:build:dev": "(cd www/widgets && pnpm build:dev $WIDGETS)", - "widgets:watch": "(cd www/widgets && pnpm watch $WIDGETS)", - "widgets:build:analyze": "(cd www/widgets && pnpm build:analyze)", - "centreon:build": "rspack build -c ./rspack.config.prod.js", - "centreon:build:analyze": "rspack build -c ./rspack.config.prod.js --analyze", - "centreon:build:dev": "rspack serve -c ./rspack.config.dev.js", - "centreon:watch": "rspack serve -c ./rspack.config.dev.js", - "build": "pnpm widgets:build && pnpm centreon:build", - "build:dev": "pnpm widgets:build:dev && pnpm centreon:build:dev", - "build:watch": "pnpm centreon:watch & pnpm widgets:watch", - "build:analyze": "pnpm widgets:build:analyze && pnpm centreon:build:analyze", - "eslint": "eslint ./www/front_src --ext .js,.jsx,.ts,.tsx --max-warnings 0", - "eslint:fix": "pnpm eslint --fix", - "test": "jest", - "test:watch": "pnpm test --watch", - "test:coverage": "jest --coverage", - "cypress:cli": "./cypress/scripts/cypress-cli.sh", - "cypress:cli:updateSnapshot": "cypress run --component --browser=chrome --env updateSnapshots=true", - "cypress:ui": "cypress open --component --browser=chrome", - "cypress:run": "cypress run --component --browser=chrome", - "cypress:run:coverage": "cypress run --component --browser=chrome --env codeCoverageTasksRegistered=true", - "generate:lockfile:analysis": "npm shrinkwrap && mv ./npm-shrinkwrap.json ./package-lock.json", - "preview:api:doc": "pnpm --package=@redocly/cli dlx openapi preview-docs ./doc/API/centreon-api.yaml" - }, - "devDependencies": { - "@4tw/cypress-drag-drop": "^2.2.5", - "@centreon/js-config": "workspace:*", - "@cypress/code-coverage": "^3.12.38", - "@cypress/react": "^8.0.0", - "@cypress/webpack-dev-server": "^3.8.0", - "@cypress/webpack-preprocessor": "^6.0.1", - "@mui/utils": "^5.15.14", - "@rspack/cli": "^0.6.3", - "@rspack/core": "^0.6.3", - "@rspack/plugin-react-refresh": "^0.6.3", - "@svgr/webpack": "^8.1.0", - "@swc/core": "^1.4.17", - "@swc/core-linux-x64-gnu": "^1.5.2", - "@swc/jest": "^0.2.36", - "@testing-library/cypress": "^10.0.1", - "@testing-library/dom": "^9.3.4", - "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "^14.2.1", - "@testing-library/react-hooks": "^8.0.1", - "@testing-library/user-event": "^14.5.2", - "@types/cypress-image-snapshot": "^3.1.9", - "@types/d3-array": "^3.2.1", - "@types/ramda": "^0.29.9", - "@types/react": "^18.3.1", - "@types/react-grid-layout": "^1.3.5", - "@types/testing-library__cypress": "^5.0.13", - "@typescript-eslint/eslint-plugin": "^6.18.1", - "@typescript-eslint/parser": "^6.18.1", - "chromatic": "^7.4.0", - "css-loader": "^6.9.0", - "cypress": "^13.8.1", - "cypress-msw-interceptor": "2.2.0", - "cypress-plugin-tab": "^1.0.5", - "cypress-real-events": "^1.12.0", - "cypress-rspack-dev-server": "^0.0.5", - "eslint": "^8.56.0", - "eslint-config-airbnb": "19.0.4", - "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-alias": "1.1.2", - "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-hooks": "^0.4.3", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^27.6.3", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-prefer-arrow-functions": "^3.3.2", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "7.34.1", - "eslint-plugin-react-hooks": "^4.6.2", - "eslint-plugin-sort-keys-fix": "^1.1.2", - "eslint-plugin-typescript-sort-keys": "^3.2.0", - "identity-obj-proxy": "^3.0.0", - "istanbul": "^0.4.5", - "jest": "^28.1.3", - "jest-environment-jsdom": "^28.1.3", - "jest-fetch-mock": "^3.0.3", - "jest-junit": "^14.0.1", - "jsdom": "^23.2.0", - "mochawesome": "^7.1.3", - "mockdate": "^3.0.5", - "msw": "1.3.2", - "nyc": "^15.1.0", - "prettier": "^3.2.5", - "process": "^0.11.10", - "react-beautiful-dnd-test-utils": "^4.1.1", - "react-mock-router": "^1.0.15", - "react-refresh": "^0.14.2", - "resize-observer-polyfill": "^1.5.1", - "resolve-url-loader": "^5.0.0", - "style-loader": "^3.3.4", - "swc-loader": "^0.2.6", - "swc-plugin-coverage-instrument": "^0.0.21", - "typescript": "^5.4.5", - "webpack-merge": "^5.10.0" - }, - "dependencies": { - "@centreon/ui": "workspace:*", - "@centreon/ui-context": "workspace:*", - "@dnd-kit/core": "^6.1.0", - "@dnd-kit/sortable": "^7.0.2", - "@dnd-kit/utilities": "^3.2.2", - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", - "@lexical/html": "^0.12.6", - "@module-federation/utilities": "^3.0.16", - "@mui/icons-material": "^5.15.15", - "@mui/lab": "5.0.0-alpha.170", - "@mui/material": "^5.15.15", - "@mui/styles": "^5.15.15", - "@mui/system": "^5.15.15", - "@mui/x-date-pickers": "^6.19.0", - "@react-spring/web": "^9.7.3", - "@simonsmith/cypress-image-snapshot": "8.1.2", - "@tanstack/react-query": "^5.32.1", - "@tanstack/react-query-devtools": "^5.32.1", - "@visx/curve": "^3.3.0", - "@visx/responsive": "^3.10.2", - "@visx/scale": "^3.5.0", - "@visx/shape": "^3.5.0", - "@visx/threshold": "^3.5.0", - "@visx/visx": "3.10.2", - "axios": "^1.6.8", - "classnames": "^2.5.1", - "clsx": "^2.1.1", - "d3-array": "3.2.4", - "d3-color": "^3.1.0", - "d3-format": "^3.1.0", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-time": "^3.1.0", - "dayjs": "^1.11.11", - "dom-serializer": "^2.0.0", - "dom-to-image": "^2.6.0", - "dompurify": "^3.1.2", - "file-saver": "^2.0.5", - "formik": "^2.4.5", - "html-react-parser": "^5.1.10", - "i18next": "^23.11.3", - "intl-pluralrules": "^2.0.1", - "jotai": "2.8.0", - "jotai-suspense": "^0.2.0", - "notistack": "^3.0.1", - "numeral": "^2.0.6", - "pluralize": "^8.0.0", - "ramda": "0.29.1", - "react": "^18.2.0", - "react-cookie": "^7.1.4", - "react-dom": "^18.2.0", - "react-grid-layout": "^1.4.4", - "react-i18next": "^14.1.1", - "react-material-ui-carousel": "^3.4.2", - "react-resizable": "^3.0.5", - "react-router": "^6.23.0", - "react-router-dom": "^6.23.0", - "react-select": "^5.8.0", - "react-spring": "^9.7.3", - "string-argv": "^0.3.2", - "ts.data.json": "^2.2.0", - "tss-react": "^4.9.10", - "use-deep-compare-effect": "^1.8.1", - "yup": "^1.4.0" - }, - "jest-junit": { - "suiteName": "jest tests", - "output": "./jest-test-results.xml" - }, - "workspaces": [ - "packages/*", - "www/widgets" - ], - "msw": { - "workerDirectory": "www/front_src/public" - }, - "baseCodeCoveragePercentage": 90 -} \ No newline at end of file + "name": "centreon", + "version": "23.4.0", + "description": "centreon web package", + "scripts": { + "update:deps": "pnpx npm-check-updates -i --format group", + "widgets:build": "(cd www/widgets && pnpm build $WIDGETS)", + "widgets:build:dev": "(cd www/widgets && pnpm build:dev $WIDGETS)", + "widgets:watch": "(cd www/widgets && pnpm watch $WIDGETS)", + "widgets:build:analyze": "(cd www/widgets && pnpm build:analyze)", + "centreon:build": "rspack build -c ./rspack.config.prod.js", + "centreon:build:analyze": "rspack build -c ./rspack.config.prod.js --analyze", + "centreon:build:dev": "rspack serve -c ./rspack.config.dev.js", + "centreon:watch": "rspack serve -c ./rspack.config.dev.js", + "build": "pnpm widgets:build && pnpm centreon:build", + "build:dev": "pnpm widgets:build:dev && pnpm centreon:build:dev", + "build:watch": "pnpm centreon:watch & pnpm widgets:watch", + "build:analyze": "pnpm widgets:build:analyze && pnpm centreon:build:analyze", + "lint": "biome check ./www/front_src --error-on-warnings", + "lint:fix": "pnpm lint --fix", + "lint:ci": "biome ci ./www/front_src --error-on-warnings", + "test": "jest", + "test:watch": "pnpm test --watch", + "test:coverage": "jest --coverage", + "cypress:cli": "./cypress/scripts/cypress-cli.sh", + "cypress:cli:updateSnapshot": "cypress run --component --browser=chrome --env updateSnapshots=true", + "cypress:ui": "cypress open --component --browser=chrome", + "cypress:run": "cypress run --component --browser=chrome", + "cypress:run:coverage": "cypress run --component --browser=chrome --env codeCoverageTasksRegistered=true", + "generate:lockfile:analysis": "npm shrinkwrap && mv ./npm-shrinkwrap.json ./package-lock.json", + "preview:api:doc": "pnpm --package=@redocly/cli dlx openapi preview-docs ./doc/API/centreon-api.yaml" + }, + "devDependencies": { + "@4tw/cypress-drag-drop": "^2.2.5", + "@biomejs/biome": "^1.8.3", + "@centreon/js-config": "workspace:*", + "@cypress/code-coverage": "^3.12.45", + "@cypress/react": "^8.0.2", + "@cypress/webpack-dev-server": "^3.10.1", + "@cypress/webpack-preprocessor": "^6.0.2", + "@mui/utils": "^5.16.6", + "@rspack/cli": "^1.0.0", + "@rspack/core": "^1.0.0", + "@rspack/plugin-react-refresh": "^1.0.0", + "@simonsmith/cypress-image-snapshot": "9.1.0", + "@svgr/webpack": "^8.1.0", + "@swc/core": "^1.6.6", + "@swc/core-linux-x64-gnu": "^1.7.12", + "@swc/jest": "^0.2.36", + "@testing-library/cypress": "^10.0.2", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.4.8", + "@testing-library/react": "^16.0.0", + "@testing-library/react-hooks": "^8.0.1", + "@testing-library/user-event": "^14.5.2", + "@types/cypress-image-snapshot": "^3.1.9", + "@types/d3-array": "^3.2.1", + "@types/ramda": "^0.30.1", + "@types/react": "^18.3.3", + "@types/react-grid-layout": "^1.3.5", + "@types/testing-library__cypress": "^5.0.13", + "chromatic": "^11.7.1", + "css-loader": "^7.1.2", + "cypress": "^13.13.3", + "cypress-msw-interceptor": "2.2.0", + "cypress-plugin-tab": "^1.0.5", + "cypress-real-events": "^1.13.0", + "cypress-rspack-dev-server": "^0.0.6", + "identity-obj-proxy": "^3.0.0", + "istanbul": "^0.4.5", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jest-fetch-mock": "^3.0.3", + "jest-junit": "^16.0.0", + "jsdom": "^24.1.1", + "mochawesome": "^7.1.3", + "mockdate": "^3.0.5", + "msw": "1.3.2", + "nyc": "^17.0.0", + "prettier": "^3.3.3", + "process": "^0.11.10", + "react-beautiful-dnd-test-utils": "^4.1.1", + "react-mock-router": "^1.0.15", + "react-refresh": "^0.14.2", + "resize-observer-polyfill": "^1.5.1", + "resolve-url-loader": "^5.0.0", + "style-loader": "^4.0.0", + "swc-loader": "^0.2.6", + "swc-plugin-coverage-instrument": "^0.0.24", + "typescript": "^5.5.4", + "webpack-merge": "^6.0.1" + }, + "dependencies": { + "@centreon/ui": "workspace:*", + "@centreon/ui-context": "workspace:*", + "@dnd-kit/core": "^6.1.0", + "@dnd-kit/sortable": "^8.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@emotion/react": "^11.13.0", + "@emotion/styled": "^11.13.0", + "@lexical/html": "^0.17.0", + "@module-federation/utilities": "^3.1.3", + "@mui/icons-material": "^5.16.7", + "@mui/lab": "5.0.0-alpha.173", + "@mui/material": "^5.16.7", + "@mui/styles": "^5.16.7", + "@mui/system": "^5.16.7", + "@mui/x-date-pickers": "^7.13.0", + "@react-spring/web": "^9.7.4", + "@tanstack/react-query": "^5.51.23", + "@tanstack/react-query-devtools": "^5.51.23", + "@visx/curve": "^3.3.0", + "@visx/responsive": "^3.10.2", + "@visx/scale": "^3.5.0", + "@visx/shape": "^3.5.0", + "@visx/threshold": "^3.5.0", + "@visx/visx": "3.11.0", + "axios": "^1.7.4", + "classnames": "^2.5.1", + "clsx": "^2.1.1", + "d3-array": "3.2.4", + "d3-color": "^3.1.0", + "d3-format": "^3.1.0", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-time": "^3.1.0", + "dayjs": "^1.11.12", + "dom-serializer": "^2.0.0", + "dom-to-image": "^2.6.0", + "dompurify": "^3.1.6", + "file-saver": "^2.0.5", + "formik": "^2.4.6", + "html-react-parser": "^5.1.12", + "i18next": "^23.13.0", + "intl-pluralrules": "^2.0.1", + "jotai": "2.9.3", + "jotai-suspense": "^0.4.0", + "notistack": "^3.0.1", + "numeral": "^2.0.6", + "pluralize": "^8.0.0", + "ramda": "0.30.1", + "react": "^18.3.1", + "react-cookie": "^7.2.0", + "react-dom": "^18.3.1", + "react-grid-layout": "^1.4.4", + "react-i18next": "^15.0.1", + "react-material-ui-carousel": "^3.4.2", + "react-resizable": "^3.0.5", + "react-router": "^6.26.1", + "react-router-dom": "^6.26.1", + "react-select": "^5.8.0", + "react-spring": "^9.7.4", + "string-argv": "^0.3.2", + "ts.data.json": "^2.2.0", + "tss-react": "^4.9.12", + "use-deep-compare-effect": "^1.8.1", + "yup": "^1.4.0" + }, + "jest-junit": { + "suiteName": "jest tests", + "output": "./jest-test-results.xml" + }, + "workspaces": [ + "packages/*", + "www/widgets" + ], + "msw": { + "workerDirectory": "www/front_src/public" + } +} diff --git a/centreon/packages/js-config/biome/base.json b/centreon/packages/js-config/biome/base.json new file mode 100644 index 0000000000..00cf50c7c3 --- /dev/null +++ b/centreon/packages/js-config/biome/base.json @@ -0,0 +1,224 @@ +{ + "formatter": { + "enabled": true, + "indentStyle": "space", + "formatWithErrors": false + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "a11y": { + "noSvgWithoutTitle": "off" + }, + "complexity": { + "noBannedTypes": "off", + "noForEach": "off" + }, + "correctness": { + "noUnusedImports": "error", + "noUnusedVariables": "error", + "useExhaustiveDependencies": "off" + }, + "nursery": { + "noConsole": "error", + "noRestrictedImports": { + "level": "error", + "options": { + "paths": { + "lodash": "Using lodash is not encouraged.", + "moment": "Using moment is not encouraged." + } + } + }, + "noUnknownFunction": "error", + "noUnknownProperty": "error", + "noUnknownUnit": "error" + }, + "suspicious": { + "useAwait": "error" + }, + "performance": { + "noAccumulatingSpread": "off" + }, + "style": { + "useLiteralEnumMembers": "off", + "useImportType": "off", + "noNamespace": "error", + "noNamespaceImport": "error", + "useFragmentSyntax": "error", + "useFilenamingConvention": { + "level": "error", + "options": { + "strictCase": false, + "filenameCases": [ + "camelCase", + "PascalCase", + "kebab-case" + ] + } + }, + "useNamingConvention": { + "level": "error", + "options": { + "strictCase": false, + "conventions": [ + { + "formats": [ + "camelCase", + "PascalCase" + ], + "selector": { + "kind": "variable" + } + }, + { + "selector": { + "kind": "interface" + }, + "formats": [ + "PascalCase" + ] + }, + { + "selector": { + "kind": "enum" + }, + "formats": [ + "PascalCase" + ] + }, + { + "selector": { + "kind": "objectLiteralProperty" + }, + "match": ".*" + }, + { + "match": "_(.*)|([a-zA-Z].*)", + "selector": { + "kind": "functionParameter" + }, + "formats": [ + "snake_case", + "PascalCase", + "camelCase" + ] + }, + { + "match": ".*", + "formats": [ + "snake_case", + "camelCase", + "PascalCase", + "CONSTANT_CASE" + ] + } + ] + } + }, + "noRestrictedGlobals": { + "level": "error", + "options": { + "deniedGlobals": [ + "isFinite", + "isNaN", + "addEventListener", + "blur", + "close", + "closed", + "confirm", + "defaultStatus", + "defaultstatus", + "event", + "external", + "find", + "focus", + "frameElement", + "frames", + "history", + "innerHeight", + "innerWidth", + "length", + "location", + "locationbar", + "menubar", + "moveBy", + "moveTo", + "name", + "onblur", + "onerror", + "onfocus", + "onload", + "onresize", + "onunload", + "open", + "opener", + "opera", + "outerHeight", + "outerWidth", + "pageXOffset", + "pageYOffset", + "parent", + "print", + "removeEventListener", + "resizeBy", + "resizeTo", + "screen", + "screenLeft", + "screenTop", + "screenX", + "screenY", + "scroll", + "scrollbars", + "scrollBy", + "scrollTo", + "scrollX", + "scrollY", + "self", + "status", + "statusbar", + "stop", + "toolbar", + "top" + ] + } + } + } + } + }, + "javascript": { + "formatter": { + "enabled": true, + "quoteStyle": "single", + "semicolons": "always", + "indentStyle": "space", + "trailingCommas": "none" + }, + "linter": { + "enabled": true + } + }, + "json": { + "parser": { + "allowComments": true, + "allowTrailingCommas": false + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + } + }, + "css": { + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "linter": { + "enabled": true + } + } +} diff --git a/centreon/packages/js-config/cypress/component/commands.tsx b/centreon/packages/js-config/cypress/component/commands.tsx index f301919a6d..ff52da183c 100644 --- a/centreon/packages/js-config/cypress/component/commands.tsx +++ b/centreon/packages/js-config/cypress/component/commands.tsx @@ -86,6 +86,7 @@ Cypress.Commands.add( path.replace('./', '**'), (req, res, ctx) => { const getQuery = req?.url?.searchParams?.get(query?.name); + if (query && equals(query.value, getQuery)) { return res( ctx.delay(delay), diff --git a/centreon/packages/js-config/cypress/component/configuration.js b/centreon/packages/js-config/cypress/component/configuration.js index eb40750ef7..f37aae212d 100644 --- a/centreon/packages/js-config/cypress/component/configuration.js +++ b/centreon/packages/js-config/cypress/component/configuration.js @@ -28,6 +28,11 @@ module.exports = ({ addMatchImageSnapshotPlugin(on, config); cypressCodeCoverageTask(on, config); + on('task', { + coverageReport: () => { + return null; + } + }); on('before:browser:launch', (browser, launchOptions) => { if (browser.name === 'chrome' && browser.isHeadless) { diff --git a/centreon/packages/js-config/cypress/e2e/commands.ts b/centreon/packages/js-config/cypress/e2e/commands.ts index 235465dc5e..454cf29650 100644 --- a/centreon/packages/js-config/cypress/e2e/commands.ts +++ b/centreon/packages/js-config/cypress/e2e/commands.ts @@ -312,6 +312,10 @@ interface ExecInContainerProps { name: string; } +interface ExecInContainerOptions { + log: boolean; +} + interface ExecInContainerResult { exitCode: number; output: string; @@ -319,7 +323,7 @@ interface ExecInContainerResult { Cypress.Commands.add( 'execInContainer', - ({ command, name }: ExecInContainerProps): Cypress.Chainable => { + ({ command, name }, { log = true } = { log: true }): Cypress.Chainable => { const commands = typeof command === 'string' || command instanceof String ? [command] @@ -330,19 +334,22 @@ Cypress.Commands.add( cy.task( 'execInContainer', { command: runCommand, name }, - { timeout: 600000 } + { log, timeout: 600000 } ).then((result) => { + const displayedOutput = log ? result.output : 'hidden command output'; + const displayedRunCommand = log ? runCommand : 'hidden run command'; + if (result.exitCode) { - cy.log(result.output); + cy.log(displayedOutput); // output will not be truncated throw new Error(` -Execution of "${runCommand}" failed +Execution of "${displayedRunCommand}" failed Exit code: ${result.exitCode} -Output:\n${result.output}`); +Output:\n${displayedOutput}`); } - acc.output = `${acc.output}${result.output}`; + acc.output = `${acc.output}${displayedOutput}`; }); return acc; @@ -778,10 +785,10 @@ declare global { options?: Partial ) => Cypress.Chainable; createDirectory: (directoryPath: string) => Cypress.Chainable; - execInContainer: ({ - command, - name - }: ExecInContainerProps) => Cypress.Chainable; + execInContainer: ( + props: ExecInContainerProps, + options?: ExecInContainerOptions + ) => Cypress.Chainable; getByLabel: ({ patternType, tag, diff --git a/centreon/packages/js-config/cypress/e2e/commands/configuration.ts b/centreon/packages/js-config/cypress/e2e/commands/configuration.ts index a9195d3833..adb3dfd321 100644 --- a/centreon/packages/js-config/cypress/e2e/commands/configuration.ts +++ b/centreon/packages/js-config/cypress/e2e/commands/configuration.ts @@ -141,12 +141,12 @@ Cypress.Commands.add( ); interface Contact { + GUIAccess?: boolean; admin?: boolean; alias?: string | null; authenticationType?: 'local' | 'ldap'; email: string; enableNotifications?: boolean; - GUIAccess?: boolean; language?: string; name: string; password: string; @@ -203,7 +203,7 @@ Cypress.Commands.add( interface ContactGroup { alias?: string | null; - contacts: string[]; + contacts: Array; name: string; } @@ -449,7 +449,7 @@ Cypress.Commands.add( interface ServiceGroup { alias?: string | null; - hostsAndServices: string[][]; + hostsAndServices: Array>; name: string; } @@ -500,8 +500,8 @@ Cypress.Commands.add( interface ACLGroup { alias?: string | null; - contacts?: string[]; - contactGroups?: string[]; + contactGroups?: Array; + contacts?: Array; name: string; } @@ -525,7 +525,7 @@ Cypress.Commands.add( }) .then(() => { if (contacts) { - contacts.map((contact) => { + contacts.forEach((contact) => { cy.executeActionViaClapi({ bodyContent: { action: 'ADDCONTACT', @@ -536,7 +536,7 @@ Cypress.Commands.add( }); } if (contactGroups) { - contactGroups.map((contactGroup) => { + contactGroups.forEach((contactGroup) => { cy.executeActionViaClapi({ bodyContent: { action: 'ADDCONTACTGROUP', @@ -551,11 +551,11 @@ Cypress.Commands.add( ); interface ACLMenu { - name: string; - rule?: string[]; alias?: string | null; includeChildren?: boolean; + name: string; readOnly?: boolean; + rule?: Array; } Cypress.Commands.add( @@ -580,30 +580,31 @@ Cypress.Commands.add( } }) .then(() => { - if (rule.length == 0) { + if (rule.length === 0) { return cy.wrap(null); } let ruleCommand = ''; - rule.map((rulePage, index) => { + rule.forEach((rulePage, index) => { ruleCommand += rulePage + (index == rule.length - 1 ? '' : ';'); }); cy.executeActionViaClapi({ bodyContent: { - action: action, + action, object: 'ACLMENU', values: `${name};${children};${ruleCommand}` } }); + return cy.wrap(null); }); } ); interface ACLAction { - name: string; + actions?: Array; description: string; - actions?: Action[]; + name: string; } Cypress.Commands.add( @@ -618,12 +619,12 @@ Cypress.Commands.add( } }) .then(() => { - if (actions.length == 0) { + if (actions.length === 0) { return cy.wrap(null); } let actionCommand = ''; - actions.map((action, index) => { + actions.forEach((action, index) => { actionCommand += action + (index == actions.length - 1 ? '' : '|'); }); cy.executeActionViaClapi({ @@ -633,20 +634,22 @@ Cypress.Commands.add( values: `${name};${actionCommand}` } }); + return cy.wrap(null); }); } ); interface ACLResource { - name: string; alias?: string | null; + name: string; } Cypress.Commands.add( 'addACLResource', ({ name, alias = null }: ACLResource): Cypress.Chainable => { const ACLResourcesAlias = alias === null ? name : alias; + return cy.executeActionViaClapi({ bodyContent: { action: 'ADD', diff --git a/centreon/packages/js-config/cypress/e2e/commands/monitoring.ts b/centreon/packages/js-config/cypress/e2e/commands/monitoring.ts index 6b1a30e903..62b791d5ce 100644 --- a/centreon/packages/js-config/cypress/e2e/commands/monitoring.ts +++ b/centreon/packages/js-config/cypress/e2e/commands/monitoring.ts @@ -21,6 +21,112 @@ const getStatusNumberFromString = (status: string): number => { throw new Error(`Status ${status} does not exist`); }; +interface HostCheck { + host: string; + isForced?: boolean; +} + +Cypress.Commands.add( + 'scheduleHostCheck', + ({ + host, + isForced = true + }: ServiceCheck): Cypress.Chainable => { + let query = `SELECT id FROM resources WHERE name = '${host}' AND type = 1`; + + return cy + .requestOnDatabase({ + database: 'centreon_storage', + query + }) + .then(([rows]) => { + if (rows.length === 0) { + throw new Error(`Cannot find host ${host}`); + } + + const hostId = rows[0].id; + + return cy.request({ + body: { + check: { + is_forced: isForced + }, + resources: [ + { + id: hostId, + parent: null, + type: 'host' + } + ] + }, + method: 'POST', + timeout: 30000, + url: '/centreon/api/latest/monitoring/resources/check' + }).then((response) => { + expect(response.status).to.eq(204); + + return cy.wrap(null); + }); + }); + } +); + +interface ServiceCheck { + host: string; + isForced?: boolean; + service: string; +} + +Cypress.Commands.add( + 'scheduleServiceCheck', + ({ + host, + isForced = true, + service + }: ServiceCheck): Cypress.Chainable => { + let query = `SELECT parent_id, id FROM resources WHERE parent_name = '${host}' AND name = '${service}'`; + + return cy + .requestOnDatabase({ + database: 'centreon_storage', + query + }) + .then(([rows]) => { + if (rows.length === 0) { + throw new Error(`Cannot find service ${host} / ${service}`); + } + + const hostId = rows[0].parent_id; + const serviceId = rows[0].id; + + return cy.request({ + body: { + check: { + is_forced: isForced + }, + resources: [ + { + id: serviceId, + parent: { + id: hostId + }, + type: 'service' + } + ] + }, + method: 'POST', + timeout: 30000, + url: '/centreon/api/latest/monitoring/resources/check' + }).then((response) => { + expect(response.status).to.eq(204); + + return cy.wrap(null); + }); + }); + } +); + + interface SubmitResult { host: string; output: string; @@ -64,10 +170,54 @@ Cypress.Commands.add( } ); +interface Downtime { + host: string; + service?: string | null; +} + +Cypress.Commands.add( + 'waitForDowntime', + (downtime: Downtime): Cypress.Chainable => { + cy.log('Checking hosts in database'); + + let query = `SELECT COUNT(d.downtime_id) AS count_downtimes FROM downtimes as d + INNER JOIN hosts as h ON h.host_id = d.host_id AND h.name = '${downtime.host}'`; + if (downtime.service) { + query += ` INNER JOIN services as s ON s.service_id = d.service_id AND s.description = '${downtime.service}'`; + } + query += ` WHERE d.started=1`; + if (!downtime.service) { + query += ` AND d.service_id = 0`; + } + + cy.log(query); + + cy.waitUntil(() => { + return cy + .requestOnDatabase({ + database: 'centreon_storage', + query + }) + .then(([rows]) => { + const foundDowntimesCount = rows.length ? rows[0].count_downtimes : 0; + + cy.log('Downtime count in database', foundDowntimesCount); + + return cy.wrap(foundDowntimesCount > 0); + }); + }); + + return cy.wrap(null); + } +); + declare global { namespace Cypress { interface Chainable { + scheduleHostCheck: (hostCheck) => Cypress.Chainable; + scheduleServiceCheck: (serviceCheck) => Cypress.Chainable; submitResults: (props: Array) => Cypress.Chainable; + waitForDowntime: (downtime: Downtime) => Cypress.Chainable; } } } diff --git a/centreon/packages/js-config/cypress/e2e/configuration.ts b/centreon/packages/js-config/cypress/e2e/configuration.ts index b9ce82a44e..427daf0397 100644 --- a/centreon/packages/js-config/cypress/e2e/configuration.ts +++ b/centreon/packages/js-config/cypress/e2e/configuration.ts @@ -48,7 +48,8 @@ export default ({ reporterOptions: { configFile: `${__dirname}/reporter-config.js` }, - setupNodeEvents: async (on, config) => { + setupNodeEvents: async (cypressOn, config) => { + const on = require('cypress-on-fix')(cypressOn) installLogsPrinter(on); await esbuildPreprocessor(on, config); tasks(on); @@ -63,12 +64,16 @@ export default ({ DATABASE_IMAGE: 'bitnami/mariadb:10.11', OPENID_IMAGE_VERSION: process.env.MAJOR || '24.04', SAML_IMAGE_VERSION: process.env.MAJOR || '24.04', + STABILITY: 'unstable', WEB_IMAGE_OS: 'alma9', WEB_IMAGE_VERSION: webImageVersion }, execTimeout: 60000, requestTimeout: 20000, - retries: 0, + retries: { + openMode: 0, + runMode: 2 + }, screenshotsFolder: `${resultsFolder}/screenshots`, video: isDevelopment, videoCompression: 0, diff --git a/centreon/packages/js-config/cypress/e2e/plugins.ts b/centreon/packages/js-config/cypress/e2e/plugins.ts index b67e02f5be..4eecd8830f 100644 --- a/centreon/packages/js-config/cypress/e2e/plugins.ts +++ b/centreon/packages/js-config/cypress/e2e/plugins.ts @@ -3,6 +3,9 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable no-param-reassign */ +import fs from 'fs'; +import path from 'path'; + export default ( on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions @@ -32,5 +35,38 @@ export default ( return launchOptions; }); + on('after:run', (results) => { + const testRetries: { [key: string]: boolean } = {}; + if ('runs' in results) { + results.runs.forEach((run) => { + run.tests.forEach((test) => { + if (test.attempts && test.attempts.length > 1) { + const testTitle = test.title.join(' > '); // Convert the array to a string + testRetries[testTitle] = true; + } + }); + }); + } + + console.log('After run results:', results); + console.log('Test retries:', testRetries); + + // Save the testRetries object to a file in the e2e/results directory + const resultFilePath = path.join( + __dirname, + '../../../../tests/e2e/results', + 'hasRetries.json' + ); + if (results.totalFailed > 0) { + fs.writeFileSync(resultFilePath, '{}'); + } else if (Object.keys(testRetries).length > 0) { + // If tests succeeded but there were retries, write the retries to the file + fs.writeFileSync(resultFilePath, JSON.stringify(testRetries, null, 2)); + } else { + // If no retries, empty the file + fs.writeFileSync(resultFilePath, '{}'); + } + }); + return config; }; diff --git a/centreon/packages/js-config/cypress/e2e/tasks.ts b/centreon/packages/js-config/cypress/e2e/tasks.ts index 8c72d366cb..4bb5083627 100644 --- a/centreon/packages/js-config/cypress/e2e/tasks.ts +++ b/centreon/packages/js-config/cypress/e2e/tasks.ts @@ -157,7 +157,7 @@ export default (on: Cypress.PluginEvents): void => { user: 'centreon' }); - const [rows, fields] = await client.execute(query); + const [rows, fields] = await client.query(query); await client.end(); @@ -211,6 +211,7 @@ export default (on: Cypress.PluginEvents): void => { WEB_IMAGE: webImage }) .withProfiles(...profiles) + .withStartupTimeout(120000) .withWaitStrategy( 'web-1', Wait.forAll([ diff --git a/centreon/packages/js-config/package.json b/centreon/packages/js-config/package.json index 9b3fc2bd4b..321f6a0393 100644 --- a/centreon/packages/js-config/package.json +++ b/centreon/packages/js-config/package.json @@ -11,7 +11,7 @@ "eslint" ], "author": "centreon@centreon.com", - "license": "GPL-2.0", + "license": "MIT", "bugs": { "url": "https://github.com/centreon/centreon-frontend/issues" }, @@ -21,19 +21,19 @@ "prettier": "^3.0.0" }, "dependencies": { - "@badeball/cypress-cucumber-preprocessor": "^20.0.5", - "@bahmutov/cypress-esbuild-preprocessor": "^2.2.0", + "@badeball/cypress-cucumber-preprocessor": "^20.1.2", + "@bahmutov/cypress-esbuild-preprocessor": "^2.2.2", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@esbuild-plugins/node-modules-polyfill": "^0.2.2", - "@tsconfig/node16": "^16.1.1", - "@tsconfig/node20": "^20.1.2", + "@tsconfig/node16": "^16.1.3", + "@tsconfig/node20": "^20.1.4", "@types/cypress-cucumber-preprocessor": "^4.0.5", - "cypress": "^13.6.4", + "cypress": "^13.13.3", "cypress-multi-reporters": "^1.6.4", - "cypress-terminal-report": "^6.0.2", - "cypress-wait-until": "^3.0.1", + "cypress-terminal-report": "^6.1.2", + "cypress-wait-until": "^3.0.2", "dotenv": "^16.4.5", - "esbuild": "^0.20.0", + "esbuild": "^0.21.5", "eslint": "^8.53.0", "eslint-config-airbnb": "19.0.4", "eslint-config-prettier": "^8.5.0", @@ -52,8 +52,8 @@ "eslint-plugin-sort-keys-fix": "^1.1.2", "eslint-plugin-typescript-sort-keys": "^2.1.0", "mochawesome": "^7.1.3", - "mysql2": "^3.9.7", + "mysql2": "^3.11.0", "tar-fs": "^3.0.6", - "testcontainers": "^10.9.0" + "testcontainers": "^10.11.0" } -} \ No newline at end of file +} diff --git a/centreon/packages/ui-context/package.json b/centreon/packages/ui-context/package.json index 84bee92034..82ea94377e 100644 --- a/centreon/packages/ui-context/package.json +++ b/centreon/packages/ui-context/package.json @@ -5,9 +5,10 @@ "main": "src/index.ts", "keywords": [], "author": "centreon@centreon.com", - "license": "GPL-2.0", + "license": "MIT", "scripts": { - "eslint": "eslint ./src --ext .ts --max-warnings 0", - "eslint:fix": "pnpm eslint --fix" + "lint": "biome check ./src/ --error-on-warnings", + "lint:fix": "pnpm lint --fix", + "lint:ci": "biome ci ./src/ --error-on-warnings" } -} \ No newline at end of file +} diff --git a/centreon/packages/ui-context/src/defaults.ts b/centreon/packages/ui-context/src/defaults.ts index 99b056638c..b3d4cf8355 100644 --- a/centreon/packages/ui-context/src/defaults.ts +++ b/centreon/packages/ui-context/src/defaults.ts @@ -1,7 +1,8 @@ -import { User, ThemeMode, ListingVariant } from './types'; +import { ListingVariant, ThemeMode, User } from './types'; const defaultUser: User = { alias: '', + canManageApiTokens: false, default_page: '/monitoring/resources', id: undefined, isAdmin: undefined, diff --git a/centreon/packages/ui-context/src/index.ts b/centreon/packages/ui-context/src/index.ts index a95bac542e..2a9ee8ff03 100644 --- a/centreon/packages/ui-context/src/index.ts +++ b/centreon/packages/ui-context/src/index.ts @@ -11,6 +11,9 @@ export { platformFeaturesAtom, featureFlagsDerivedAtom } from './platformFeauresAtom'; + +export { platformVersionsAtom } from './platformVersionsAtom'; + export { isOnPublicPageAtom } from './isOnPublicPageAtom'; export { additionalResourcesAtom } from './additionalResources'; export { diff --git a/centreon/packages/ui-context/src/platformVersionsAtom.ts b/centreon/packages/ui-context/src/platformVersionsAtom.ts new file mode 100644 index 0000000000..f58f5eba7a --- /dev/null +++ b/centreon/packages/ui-context/src/platformVersionsAtom.ts @@ -0,0 +1,5 @@ +import { atom } from 'jotai'; + +import { PlatformVersions } from './types'; + +export const platformVersionsAtom = atom(null); diff --git a/centreon/packages/ui-context/src/types.ts b/centreon/packages/ui-context/src/types.ts index 52817250b2..b6aadf0873 100644 --- a/centreon/packages/ui-context/src/types.ts +++ b/centreon/packages/ui-context/src/types.ts @@ -20,6 +20,7 @@ export interface DashboardRolesAndPermissions { export interface User { alias: string; + canManageApiTokens: boolean; dashboard?: DashboardRolesAndPermissions | null; default_page?: string | null; id?: number; @@ -85,11 +86,8 @@ export interface Downtime { export interface FeatureFlags { adExclusionPeriods?: boolean; - dashboard?: boolean; - dashboardPlayList?: boolean; notification?: boolean; - resourceStatusFilterRevamp?: boolean; - resourceStatusTreeView?: boolean; + resouresTableOpenTickets: boolean; vault?: boolean; } @@ -129,3 +127,16 @@ export interface FederatedModule { remoteEntry: string; remoteUrl?: string; } + +interface Version { + fix: string; + major: string; + minor: string; + version: string; +} + +export interface PlatformVersions { + modules: Record; + web: Version; + widgets: Record; +} diff --git a/centreon/packages/ui/.eslintrc.cjs b/centreon/packages/ui/.eslintrc.cjs deleted file mode 100644 index 3ed77b36b2..0000000000 --- a/centreon/packages/ui/.eslintrc.cjs +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - root: true, - extends: [ - '../js-config/eslint/react/typescript.eslintrc.js' - ], - settings: { - 'import/resolver': { - alias: { - map: [ - ['@centreon/ui/fonts', './public/fonts'] - ] - } - } - }, - overrides: [ - { - // less strict for stories - "files": ["*.stories.tsx"], - "rules": { - "react/no-array-index-key": "warn", - } - } - ] -}; \ No newline at end of file diff --git a/centreon/packages/ui/.storybook/main.ts b/centreon/packages/ui/.storybook/main.ts index 94ae68fce8..6c129c4733 100644 --- a/centreon/packages/ui/.storybook/main.ts +++ b/centreon/packages/ui/.storybook/main.ts @@ -1,3 +1,4 @@ +import { dirname, join } from "path"; import type { StorybookConfig } from "@storybook/react-vite"; import remarkGfm from "remark-gfm"; import turbosnap from 'vite-plugin-turbosnap'; @@ -6,7 +7,8 @@ import { mergeConfig } from 'vite'; const config: StorybookConfig = { stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], addons: [ - "@storybook/addon-essentials", + getAbsolutePath("@storybook/addon-themes"), + getAbsolutePath("@storybook/addon-essentials"), { name: "@storybook/addon-docs", options: { @@ -18,23 +20,19 @@ const config: StorybookConfig = { }, }, }, - "@storybook/addon-styling", - "@storybook/addon-a11y", - "@storybook/addon-interactions", - "storybook-addon-mock", - "storybook-dark-mode", + getAbsolutePath("@storybook/addon-a11y"), + getAbsolutePath("storybook-addon-mock"), + getAbsolutePath("storybook-dark-mode") ], framework: { - name: "@storybook/react-vite", + name: getAbsolutePath("@storybook/react-vite"), options: {}, }, typescript: { reactDocgen: "react-docgen-typescript", }, - docs: { - autodocs: "tag", - }, - core: { builder: '@storybook/builder-vite' }, + docs: {}, + core: {}, async viteFinal(config, { configType }) { return mergeConfig(config, { plugins: configType === 'PRODUCTION' ? [turbosnap({ rootDir: process.cwd() })] : [], @@ -42,4 +40,8 @@ const config: StorybookConfig = { }, }; -export default config; \ No newline at end of file +export default config; + +function getAbsolutePath(value: string): any { + return dirname(require.resolve(join(value, "package.json"))); +} diff --git a/centreon/packages/ui/.storybook/preview.tsx b/centreon/packages/ui/.storybook/preview.tsx index d746e49bf1..3644960a64 100644 --- a/centreon/packages/ui/.storybook/preview.tsx +++ b/centreon/packages/ui/.storybook/preview.tsx @@ -28,10 +28,12 @@ const withQueryProvider: Decorator = (story, context): JSX.Element => ( const preview: Preview = { loaders: [mswLoader], + decorators: [ withThemeProvider, withQueryProvider, ], + globalTypes: { reactquerydevtools: { description: "React-Query devtools", @@ -46,8 +48,9 @@ const preview: Preview = { }, }, }, + parameters: { - actions: { argTypesRegex: "^on[A-Z].*" }, + // actions: { argTypesRegex: "^on[A-Z].*" }, a11y: { manual: true, }, @@ -68,7 +71,9 @@ const preview: Preview = { defaultViewport: 'tablet', defaultOrientation: 'landscape' }, - } + }, + + tags: ["autodocs"] }; export default preview; diff --git a/centreon/packages/ui/biome.json b/centreon/packages/ui/biome.json new file mode 100644 index 0000000000..35982b5e5d --- /dev/null +++ b/centreon/packages/ui/biome.json @@ -0,0 +1,12 @@ +{ + "extends": [ + "../js-config/biome/base.json" + ], + "files": { + "ignore": [ + "**/*{.,-}min.js", + "**/mockServiceWorker.js", + "**/*.test.tsx" + ] + } +} diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip when a single bar is hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip when a single bar is hovered.snap.png new file mode 100644 index 0000000000..f8171b1856 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip when a single bar is hovered.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip when a stacked bar is hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip when a stacked bar is hovered.snap.png new file mode 100644 index 0000000000..7554afecd9 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip when a stacked bar is hovered.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip with a single metric when a stacked bar is hovered and a prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip with a single metric when a stacked bar is hovered and a prop is set.snap.png new file mode 100644 index 0000000000..242f38a873 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays a tooltip with a single metric when a stacked bar is hovered and a prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays bar chart horizontally with a mix of stacked and non-stacked data.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays bar chart horizontally with a mix of stacked and non-stacked data.snap.png new file mode 100644 index 0000000000..c50b9d5497 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays bar chart horizontally with a mix of stacked and non-stacked data.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays bar chart vertically with a mix of stacked and non-stacked data.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays bar chart vertically with a mix of stacked and non-stacked data.snap.png new file mode 100644 index 0000000000..6c6aa227cb Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays bar chart vertically with a mix of stacked and non-stacked data.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart horizontally centered in zero.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart horizontally centered in zero.snap.png new file mode 100644 index 0000000000..e673328572 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart horizontally centered in zero.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart horizontally.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart horizontally.snap.png new file mode 100644 index 0000000000..f8171b1856 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart horizontally.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart vertically centered in zero.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart vertically centered in zero.snap.png new file mode 100644 index 0000000000..d2daaba88d Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart vertically centered in zero.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart vertically.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart vertically.snap.png new file mode 100644 index 0000000000..39406c7659 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the bar chart vertically.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart horizontally centered in zero.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart horizontally centered in zero.snap.png new file mode 100644 index 0000000000..31da359f16 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart horizontally centered in zero.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart horizontally.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart horizontally.snap.png new file mode 100644 index 0000000000..242f38a873 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart horizontally.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart vertically centered in zero.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart vertically centered in zero.snap.png new file mode 100644 index 0000000000..99dd2a6613 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart vertically centered in zero.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart vertically.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart vertically.snap.png new file mode 100644 index 0000000000..960e441c58 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- displays the stacked bar chart vertically.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- does not display a tooltip when a bar is hovered and a props is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- does not display a tooltip when a bar is hovered and a props is set.snap.png new file mode 100644 index 0000000000..242f38a873 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarChart/BarChart.cypress.spec.tsx/Bar chart -- does not display a tooltip when a bar is hovered and a props is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- adjusts size based on the provided width and height.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- adjusts size based on the provided width and height.snap.png index df4b66980b..13d683f594 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- adjusts size based on the provided width and height.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- adjusts size based on the provided width and height.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- conditionally displays values on rects based on displayValues prop.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- conditionally displays values on rects based on displayValues prop.snap.png index 36662c6497..cfc02402c8 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- conditionally displays values on rects based on displayValues prop.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- conditionally displays values on rects based on displayValues prop.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays Legend component based on displayLegend prop.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays Legend component based on displayLegend prop.snap.png index 720903dffd..b414370fe2 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays Legend component based on displayLegend prop.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays Legend component based on displayLegend prop.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays the title when the title is giving.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays the title when the title is giving.snap.png index 36662c6497..cfc02402c8 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays the title when the title is giving.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays the title when the title is giving.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays tooltip with correct information on hover.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays tooltip with correct information on hover.snap.png index d807d373e9..2654f9c88d 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays tooltip with correct information on hover.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays tooltip with correct information on hover.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays values on rects in percentage unit when displayValues is set to true and unit to percentage.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays values on rects in percentage unit when displayValues is set to true and unit to percentage.snap.png index d7b74d9c2c..98919cd57c 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays values on rects in percentage unit when displayValues is set to true and unit to percentage.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- displays values on rects in percentage unit when displayValues is set to true and unit to percentage.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders Bar stack correctly with provided data.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders Bar stack correctly with provided data.snap.png index 36662c6497..cfc02402c8 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders Bar stack correctly with provided data.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders Bar stack correctly with provided data.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders as a horizontal bar when variant is set to horizontal.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders as a horizontal bar when variant is set to horizontal.snap.png index 974037b8b9..9b97a57e9b 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders as a horizontal bar when variant is set to horizontal.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders as a horizontal bar when variant is set to horizontal.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders as a vertical bar when variant is set to vertical.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders as a vertical bar when variant is set to vertical.snap.png index 36662c6497..cfc02402c8 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders as a vertical bar when variant is set to vertical.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/BarStack/BarStack.cypress.spec.tsx/Bar stack -- renders as a vertical bar when variant is set to vertical.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays as centered to zero when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays as centered to zero when the prop is set.snap.png new file mode 100644 index 0000000000..4d040ed9f6 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays as centered to zero when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays only horizontal lines when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays only horizontal lines when the prop is set.snap.png new file mode 100644 index 0000000000..ebdab9c190 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays only horizontal lines when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays only vertical lines when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays only vertical lines when the prop is set.snap.png new file mode 100644 index 0000000000..e4f26635c3 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- displays only vertical lines when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- does not display axis borders when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- does not display axis borders when the prop is set.snap.png new file mode 100644 index 0000000000..6301563caa Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- does not display axis borders when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- does not display grids when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- does not display grids when the prop is set.snap.png new file mode 100644 index 0000000000..615f3cd6ab Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- does not display grids when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- rotates the tick label when the props is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- rotates the tick label when the props is set.snap.png new file mode 100644 index 0000000000..eb6e715d91 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Axis -- rotates the tick label when the props is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend in list mode when the corresponding props is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend in list mode when the corresponding props is set.snap.png new file mode 100644 index 0000000000..39a0ae11ec Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend in list mode when the corresponding props is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the left side of the graph when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the left side of the graph when the corresponding prop is set.snap.png new file mode 100644 index 0000000000..6ccd05bf66 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the left side of the graph when the corresponding prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the right side of the graph as list when the corresponding props are set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the right side of the graph as list when the corresponding props are set.snap.png new file mode 100644 index 0000000000..4a3960df7c Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the right side of the graph as list when the corresponding props are set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays lines with a custom line width when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays lines with a custom line width when the prop is set.snap.png new file mode 100644 index 0000000000..cbbd3a9b30 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays lines with a custom line width when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a natural style when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a natural style when the prop is set.snap.png new file mode 100644 index 0000000000..924a958061 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a natural style when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a step style when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a step style when the prop is set.snap.png new file mode 100644 index 0000000000..5119aeb000 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a step style when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- shows points when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- shows points when the prop is set.snap.png new file mode 100644 index 0000000000..55e93e501d Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- shows points when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- shows the area when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- shows the area when the prop is set.snap.png new file mode 100644 index 0000000000..1479a904d0 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Line style -- shows the area when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays a metric highlighted when the graph is hovered and the metric is the nearest point.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays a metric highlighted when the graph is hovered and the metric is the nearest point.snap.png new file mode 100644 index 0000000000..66f83e135a Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays a metric highlighted when the graph is hovered and the metric is the nearest point.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays a tooltip when the graph is hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays a tooltip when the graph is hovered.snap.png new file mode 100644 index 0000000000..65711086e8 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays a tooltip when the graph is hovered.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip a single metric when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip a single metric when the corresponding prop is set.snap.png new file mode 100644 index 0000000000..e71e215ad0 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip a single metric when the corresponding prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip with defined values when the graph is hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip with defined values when the graph is hovered.snap.png new file mode 100644 index 0000000000..481f77b6db Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip with defined values when the graph is hovered.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when null values are hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when null values are hovered.snap.png new file mode 100644 index 0000000000..21afd2b1c9 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when null values are hovered.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when the corresponding prop is set.snap.png new file mode 100644 index 0000000000..46c181a601 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when the corresponding prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is ascending when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is ascending when the corresponding prop is set.snap.png new file mode 100644 index 0000000000..f62d914d46 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is ascending when the corresponding prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is descending when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is descending when the corresponding prop is set.snap.png new file mode 100644 index 0000000000..742abf7a60 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is descending when the corresponding prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- displays the curves with different shades when curves have same color.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- displays the curves with different shades when curves have same color.snap.png new file mode 100644 index 0000000000..6cfd9a8bf6 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Line chart -- displays the curves with different shades when curves have same color.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- changes the unit on the left or right scales when a new unit is selected.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- changes the unit on the left or right scales when a new unit is selected.snap.png new file mode 100644 index 0000000000..fa913a5e74 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- changes the unit on the left or right scales when a new unit is selected.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays lines and bars in the same chart centered in zero.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays lines and bars in the same chart centered in zero.snap.png new file mode 100644 index 0000000000..4e51017641 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays lines and bars in the same chart centered in zero.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays lines and bars in the same chart.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays lines and bars in the same chart.snap.png new file mode 100644 index 0000000000..51cd065e95 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays lines and bars in the same chart.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays mixed lines and bars in the same chart centered in zero.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays mixed lines and bars in the same chart centered in zero.snap.png new file mode 100644 index 0000000000..44a2dee7cc Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays mixed lines and bars in the same chart centered in zero.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays mixed lines and bars in the same chart.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays mixed lines and bars in the same chart.snap.png new file mode 100644 index 0000000000..074bdf6304 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays mixed lines and bars in the same chart.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays stacked lines and bars in the same chart centered in zero.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays stacked lines and bars in the same chart centered in zero.snap.png new file mode 100644 index 0000000000..b7bdb30add Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays stacked lines and bars in the same chart centered in zero.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays stacked lines and bars in the same chart.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays stacked lines and bars in the same chart.snap.png new file mode 100644 index 0000000000..0b7db1fe24 Binary files /dev/null and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Chart/Chart.cypress.spec.tsx/Lines and bars -- displays stacked lines and bars in the same chart.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays ranged thresholds.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays ranged thresholds.snap.png index 562bbde333..11e3951ac3 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays ranged thresholds.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays ranged thresholds.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as critical when corresponding thresholds are set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as critical when corresponding thresholds are set.snap.png index a8751074c9..5e2d226c87 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as critical when corresponding thresholds are set.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as critical when corresponding thresholds are set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as success when corresponding thresholds are set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as success when corresponding thresholds are set.snap.png index bb0d85863b..712661ef4f 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as success when corresponding thresholds are set.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as success when corresponding thresholds are set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as warning when corresponding thresholds are set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as warning when corresponding thresholds are set.snap.png index cad8c92faa..9f5b23c247 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as warning when corresponding thresholds are set.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the gauge as warning when corresponding thresholds are set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the threshold tooltip when a threshold is hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the threshold tooltip when a threshold is hovered.snap.png index 0164ecf4b6..06f83633df 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the threshold tooltip when a threshold is hovered.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the threshold tooltip when a threshold is hovered.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the value as raw when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the value as raw when the prop is set.snap.png index f736486d61..68063db2c1 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the value as raw when the prop is set.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Gauge/Gauge.cypress.spec.tsx/Gauge -- displays the value as raw when the prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays as centered to zero when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays as centered to zero when the prop is set.snap.png deleted file mode 100644 index 5ef0f151f5..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays as centered to zero when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays only horizontal lines when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays only horizontal lines when the prop is set.snap.png deleted file mode 100644 index 4efdc0ba26..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays only horizontal lines when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays only vertical lines when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays only vertical lines when the prop is set.snap.png deleted file mode 100644 index 4ef6e2e6af..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- displays only vertical lines when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- does not display axis borders when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- does not display axis borders when the prop is set.snap.png deleted file mode 100644 index 75a8a36c26..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- does not display axis borders when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- does not display grids when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- does not display grids when the prop is set.snap.png deleted file mode 100644 index 21526d545d..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- does not display grids when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- rotates the tick label when the props is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- rotates the tick label when the props is set.snap.png deleted file mode 100644 index ab6eba45b3..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Axis -- rotates the tick label when the props is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend in list mode when the corresponding props is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend in list mode when the corresponding props is set.snap.png deleted file mode 100644 index c5f7aff3fa..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend in list mode when the corresponding props is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the left side of the graph when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the left side of the graph when the corresponding prop is set.snap.png deleted file mode 100644 index 47572a7f56..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the left side of the graph when the corresponding prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the right side of the graph as list when the corresponding props are set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the right side of the graph as list when the corresponding props are set.snap.png deleted file mode 100644 index 49471c2a64..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Legend -- displays the legend on the right side of the graph as list when the corresponding props are set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays lines with a custom line width when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays lines with a custom line width when the prop is set.snap.png deleted file mode 100644 index c34e7bda8c..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays lines with a custom line width when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays lines with dots width when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays lines with dots width when the prop is set.snap.png deleted file mode 100644 index 8e57280f12..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays lines with dots width when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a natural style when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a natural style when the prop is set.snap.png deleted file mode 100644 index 60b730651b..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a natural style when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a step style when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a step style when the prop is set.snap.png deleted file mode 100644 index 4a41191241..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- displays the curve in a step style when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows points when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows points when the prop is set.snap.png deleted file mode 100644 index c34220cdb0..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows points when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows the area when the prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows the area when the prop is set.snap.png deleted file mode 100644 index 1d0b7138a0..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows the area when the prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows the area with a custom transparency when props are set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows the area with a custom transparency when props are set.snap.png deleted file mode 100644 index 28d67e2fc1..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Line style -- shows the area with a custom transparency when props are set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays a metric highlighted when the graph is hovered and the metric is the nearest point.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays a metric highlighted when the graph is hovered and the metric is the nearest point.snap.png deleted file mode 100644 index 9164107022..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays a metric highlighted when the graph is hovered and the metric is the nearest point.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays a tooltip when the graph is hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays a tooltip when the graph is hovered.snap.png deleted file mode 100644 index 755bee4086..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays a tooltip when the graph is hovered.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip a single metric when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip a single metric when the corresponding prop is set.snap.png deleted file mode 100644 index a00a0518da..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip a single metric when the corresponding prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip with defined values whent the graph is hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip with defined values whent the graph is hovered.snap.png deleted file mode 100644 index c608640de8..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- displays the tooltip with defined values whent the graph is hovered.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when null values are hovered.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when null values are hovered.snap.png deleted file mode 100644 index bcef99e021..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when null values are hovered.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when the corresponding prop is set.snap.png deleted file mode 100644 index cbde62180f..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- does not display the tooltip when the corresponding prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is ascending when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is ascending when the corresponding prop is set.snap.png deleted file mode 100644 index d98438514a..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is ascending when the corresponding prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is descending when the corresponding prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is descending when the corresponding prop is set.snap.png deleted file mode 100644 index 99f445131a..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- Tooltip -- sorts metrics by their value is descending when the corresponding prop is set.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- displays the curves with different shades when curves have same color.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- displays the curves with different shades when curves have same color.snap.png deleted file mode 100644 index aa697a79a5..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/LineChart/LineChart.cypress.spec.tsx/Line chart -- displays the curves with different shades when curves have same color.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- adjusts outer radius when chart dimensions are too small.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- adjusts outer radius when chart dimensions are too small.snap.png index 20fe169a05..c2f89b16a2 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- adjusts outer radius when chart dimensions are too small.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- adjusts outer radius when chart dimensions are too small.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- adjusts size based on the provided width and height.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- adjusts size based on the provided width and height.snap.png index 63507e3db6..dfc7e22d22 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- adjusts size based on the provided width and height.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- adjusts size based on the provided width and height.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- conditionally displays values on arcs based on displayValues prop.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- conditionally displays values on arcs based on displayValues prop.snap.png index 91068ab6ff..26443e3116 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- conditionally displays values on arcs based on displayValues prop.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- conditionally displays values on arcs based on displayValues prop.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays Legend component based on displayLegend prop.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays Legend component based on displayLegend prop.snap.png index a5f68975cc..fe0f3cc4d8 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays Legend component based on displayLegend prop.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays Legend component based on displayLegend prop.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays the title when the title is giving.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays the title when the title is giving.snap.png index 91068ab6ff..26443e3116 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays the title when the title is giving.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays the title when the title is giving.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays tooltip with correct information on hover.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays tooltip with correct information on hover.snap.png index d8b1c52c56..e50b43beb5 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays tooltip with correct information on hover.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays tooltip with correct information on hover.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays values on arcs in percentage unit when displayValues is set to true and unit to percentage.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays values on arcs in percentage unit when displayValues is set to true and unit to percentage.snap.png index d701099e9b..fcbcba3783 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays values on arcs in percentage unit when displayValues is set to true and unit to percentage.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- displays values on arcs in percentage unit when displayValues is set to true and unit to percentage.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders as a donut when variant is set to donut.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders as a donut when variant is set to donut.snap.png index a169aa9bc3..3e63a39306 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders as a donut when variant is set to donut.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders as a donut when variant is set to donut.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders as a pie when variant is set to pie.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders as a pie when variant is set to pie.snap.png index 91068ab6ff..26443e3116 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders as a pie when variant is set to pie.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders as a pie when variant is set to pie.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders pie chart correctly with provided data.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders pie chart correctly with provided data.snap.png index e87bf3803f..26443e3116 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders pie chart correctly with provided data.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/PieChart/PieChart.cypress.spec.tsx/Pie chart -- renders pie chart correctly with provided data.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- cannot collapse a node when a node is not clickable.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- cannot collapse a node when a node is not clickable.snap.png index 2fc09758cc..c0801b1585 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- cannot collapse a node when a node is not clickable.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- cannot collapse a node when a node is not clickable.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- collapses a node when a node is clickable.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- collapses a node when a node is clickable.snap.png index 69916fee5e..250c572fe7 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- collapses a node when a node is clickable.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- collapses a node when a node is clickable.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- displays the tree with line links when a prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- displays the tree with line links when a prop is set.snap.png index d0443bca16..e42e41b6f8 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- displays the tree with line links when a prop is set.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- displays the tree with line links when a prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- displays the tree with step links when a prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- displays the tree with step links when a prop is set.snap.png index 20dfce6e5a..32af5b01f1 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- displays the tree with step links when a prop is set.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Complex data tree -- displays the tree with step links when a prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- cannot collapses a node when a leaf is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- cannot collapses a node when a leaf is clicked.snap.png index f1aefb2335..f58960542e 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- cannot collapses a node when a leaf is clicked.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- cannot collapses a node when a leaf is clicked.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- collapses a node's childrens when a node is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- collapses a node's childrens when a node is clicked.snap.png index 9ba1f7e9c2..ae6505ce4a 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- collapses a node's childrens when a node is clicked.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- collapses a node's childrens when a node is clicked.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- displays customized links when a prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- displays customized links when a prop is set.snap.png index c40483bf30..d60cdfa9c0 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- displays customized links when a prop is set.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- displays customized links when a prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- displays the whole tree.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- displays the whole tree.snap.png index f1aefb2335..f58960542e 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- displays the whole tree.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- displays the whole tree.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- expands a node's childrens when a node is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- expands a node's childrens when a node is clicked.snap.png index f1aefb2335..f58960542e 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- expands a node's childrens when a node is clicked.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- expands a node's childrens when a node is clicked.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- expands nodes by default when a prop is set.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- expands nodes by default when a prop is set.snap.png index 586e43a45b..1dc141ce7d 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- expands nodes by default when a prop is set.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/Graph/Tree/Tree.cypress.spec.tsx/Simple data tree -- expands nodes by default when a prop is set.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- adds the contact as viewer when a contact is selected and the corresponding button is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- adds the contact as viewer when a contact is selected and the corresponding button is clicked.snap.png index 3e92d6332a..50230f7fe0 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- adds the contact as viewer when a contact is selected and the corresponding button is clicked.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- adds the contact as viewer when a contact is selected and the corresponding button is clicked.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- adds the contact group as editor when a contact group is selected and the corresponding button is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- adds the contact group as editor when a contact group is selected and the corresponding button is clicked.snap.png index 54f926fea7..64439738a8 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- adds the contact group as editor when a contact group is selected and the corresponding button is clicked.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- adds the contact group as editor when a contact group is selected and the corresponding button is clicked.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- clears the autocomplete when a contact is selected and the contact type is changed.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- clears the autocomplete when a contact is selected and the contact type is changed.snap.png index e336a0c370..df510a8da7 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- clears the autocomplete when a contact is selected and the contact type is changed.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- clears the autocomplete when a contact is selected and the contact type is changed.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays a removed chip when the corresponding icon is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays a removed chip when the corresponding icon is clicked.snap.png index 36689a6b81..6671a1e624 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays a removed chip when the corresponding icon is clicked.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays a removed chip when the corresponding icon is clicked.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays statistics when a contact is added, a contact is updated and a contact is removed.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays statistics when a contact is added, a contact is updated and a contact is removed.snap.png index 457a1788a4..2e46793efd 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays statistics when a contact is added, a contact is updated and a contact is removed.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays statistics when a contact is added, a contact is updated and a contact is removed.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights in loading state.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights in loading state.snap.png index f6d97db632..383d5da813 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights in loading state.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights in loading state.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights list.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights list.snap.png index 5f3169e2b5..a1dc696c58 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights list.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights list.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights with an empty list.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights with an empty list.snap.png index f2a3d25e9d..6dfc589ed2 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights with an empty list.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights with an empty list.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- removes the contact from the list when the contact has been to the list and the corresponding button is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- removes the contact from the list when the contact has been to the list and the corresponding button is clicked.snap.png index 5f3169e2b5..ad290ff29f 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- removes the contact from the list when the contact has been to the list and the corresponding button is clicked.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- removes the contact from the list when the contact has been to the list and the corresponding button is clicked.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- removes the updated chip when the contact role is updated and its initial role is assigned back.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- removes the updated chip when the contact role is updated and its initial role is assigned back.snap.png index 5f3169e2b5..a1dc696c58 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- removes the updated chip when the contact role is updated and its initial role is assigned back.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- removes the updated chip when the contact role is updated and its initial role is assigned back.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- resets the role to viewer when the editor role is selected and a contact with viewer right is selected.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- resets the role to viewer when the editor role is selected and a contact with viewer right is selected.snap.png index a0caa23ac7..811e331be0 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- resets the role to viewer when the editor role is selected and a contact with viewer right is selected.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- resets the role to viewer when the editor role is selected and a contact with viewer right is selected.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- restores the contact when the contact is removed and the corresponding icon is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- restores the contact when the contact is removed and the corresponding icon is clicked.snap.png index a3813c56bf..f9f8aa4726 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- restores the contact when the contact is removed and the corresponding icon is clicked.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- restores the contact when the contact is removed and the corresponding icon is clicked.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- retrieves contact groups when the contact group radio is selected.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- retrieves contact groups when the contact group radio is selected.snap.png index c4fcc92db5..26c1a4a5a7 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- retrieves contact groups when the contact group radio is selected.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- retrieves contact groups when the contact group radio is selected.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- retrieves contacts when the contact radio is selected.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- retrieves contacts when the contact radio is selected.snap.png index 39071c0a14..c5384863ae 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- retrieves contacts when the contact radio is selected.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- retrieves contacts when the contact radio is selected.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list with the updated contact.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list with the updated contact.snap.png index e73dd8bb7f..73a6b35554 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list with the updated contact.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list with the updated contact.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list without the removed contact.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list without the removed contact.snap.png index e59f47846e..41782f7979 100644 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list without the removed contact.snap.png and b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list without the removed contact.snap.png differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- adds the contact as viewer when a contact is selected and the corresponding button is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- adds the contact as viewer when a contact is selected and the corresponding button is clicked.snap.png deleted file mode 100644 index 07ffd57491..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- adds the contact as viewer when a contact is selected and the corresponding button is clicked.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- adds the contact group as editor when a contact group is selected and the corresponding button is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- adds the contact group as editor when a contact group is selected and the corresponding button is clicked.snap.png deleted file mode 100644 index d8c3c60b62..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- adds the contact group as editor when a contact group is selected and the corresponding button is clicked.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- clears the autocomplete when a contact is selected and the contact type is changed.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- clears the autocomplete when a contact is selected and the contact type is changed.snap.png deleted file mode 100644 index c93d894695..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- clears the autocomplete when a contact is selected and the contact type is changed.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays a removed chip when the corresponding icon is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays a removed chip when the corresponding icon is clicked.snap.png deleted file mode 100644 index 06b85f09c8..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays a removed chip when the corresponding icon is clicked.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays statistics when a contact is added, a contact is updated and a contact is removed.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays statistics when a contact is added, a contact is updated and a contact is removed.snap.png deleted file mode 100644 index 6e6610d825..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays statistics when a contact is added, a contact is updated and a contact is removed.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights in loading state.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights in loading state.snap.png deleted file mode 100644 index cbf12ebecb..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights in loading state.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights with an empty list.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights with an empty list.snap.png deleted file mode 100644 index 69023d34fe..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights with an empty list.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights without link.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights without link.snap.png deleted file mode 100644 index cfa7d8882e..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- displays the access rights without link.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- removes the contact from the list when the contact has been to the list and the corresponding button is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- removes the contact from the list when the contact has been to the list and the corresponding button is clicked.snap.png deleted file mode 100644 index ffe2a01147..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- removes the contact from the list when the contact has been to the list and the corresponding button is clicked.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- removes the updated chip when the contact role is updated and its initial role is assigned back.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- removes the updated chip when the contact role is updated and its initial role is assigned back.snap.png deleted file mode 100644 index ffe2a01147..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- removes the updated chip when the contact role is updated and its initial role is assigned back.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- resets the role to viewer when the editor role is selected and a contact with viewer right is selected.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- resets the role to viewer when the editor role is selected and a contact with viewer right is selected.snap.png deleted file mode 100644 index 6f47a1aa78..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- resets the role to viewer when the editor role is selected and a contact with viewer right is selected.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- restores the contact when the contact is removed and the corresponding icon is clicked.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- restores the contact when the contact is removed and the corresponding icon is clicked.snap.png deleted file mode 100644 index 34822583a9..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- restores the contact when the contact is removed and the corresponding icon is clicked.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- retrieves contact groups when the contact group radio is selected.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- retrieves contact groups when the contact group radio is selected.snap.png deleted file mode 100644 index b4f5932283..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- retrieves contact groups when the contact group radio is selected.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- retrieves contacts when the contact radio is selected.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- retrieves contacts when the contact radio is selected.snap.png deleted file mode 100644 index 44d3bf2011..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- retrieves contacts when the contact radio is selected.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list with the updated contact.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list with the updated contact.snap.png deleted file mode 100644 index 9299357454..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list with the updated contact.snap.png and /dev/null differ diff --git a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list without the removed contact.snap.png b/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list without the removed contact.snap.png deleted file mode 100644 index 8536241952..0000000000 Binary files a/centreon/packages/ui/cypress/visual-testing-snapshots/src/components/Form/AccessRightsV2/AccessRights.cypress.spec.tsx/Access rights -- submits the new acces rights list without the removed contact.snap.png and /dev/null differ diff --git a/centreon/packages/ui/jest.config.js b/centreon/packages/ui/jest.config.js index 2fad50181f..93908cecf1 100644 --- a/centreon/packages/ui/jest.config.js +++ b/centreon/packages/ui/jest.config.js @@ -4,21 +4,15 @@ module.exports = { ...baseConfig, moduleNameMapper: { '\\.(s?css|png|svg)$': 'identity-obj-proxy', - '^@centreon/ui/fonts(.*)$': '/public/fonts$1', + '^@centreon/ui/fonts(.*)$': '/src/fonts$1', '^react($|/.+)': '/../../node_modules/react$1', 'd3-array': '/node_modules/d3-array/dist/d3-array.min.js' }, reporters: ['default', ['jest-junit', { outputName: 'junit.xml' }]], roots: ['/src/', '/test/'], - setupFilesAfterEnv: [ - '/test/setupTests.js', - '@testing-library/jest-dom/extend-expect' - ], + setupFilesAfterEnv: ['/test/setupTests.js'], testResultsProcessor: 'jest-junit', - transform: { - ...baseConfig.transform, - '^.+\\.mdx?$': '@storybook/addon-docs/jest-transform-mdx' - }, + transform: baseConfig.transform, transformIgnorePatterns: [ '/../../node_modules/(?!d3-array|d3-scale|d3-interpolation|d3-interpolate)' ] diff --git a/centreon/packages/ui/modern.config.ts b/centreon/packages/ui/modern.config.ts deleted file mode 100644 index 3dfb6146d5..0000000000 --- a/centreon/packages/ui/modern.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default { - output: { - disableTsChecker: true - } -}; diff --git a/centreon/packages/ui/package.json b/centreon/packages/ui/package.json index 6f4001a1bc..c98b1f89c5 100644 --- a/centreon/packages/ui/package.json +++ b/centreon/packages/ui/package.json @@ -4,17 +4,18 @@ "description": "Centreon UI Components", "scripts": { "update:deps": "pnpx npm-check-updates -i --format group", - "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0", - "eslint:fix": "pnpm eslint --fix", + "lint": "biome check ./src/ --error-on-warnings", + "lint:fix": "pnpm lint --fix", + "lint:ci": "biome ci ./src/ --error-on-warnings", "storybook": "storybook dev -p 9001 -c .storybook", "build:storybook": "storybook build -c .storybook -o .out", "test": "jest", "test:storybook:local": "test-storybook --url http://127.0.0.1:9001", "test:ci": "jest --silent --reporter=jest-junit", "cypress:ui": "cypress open --component --browser=chrome", - "cypress:cli:updateSnapshot": "pnpm cypress:cli --env updateSnapshots=true", + "cypress:run:updateSnapshots": "cypress run --component --browser=chrome --env updateSnapshots=true", "cypress:run:coverage": "cypress run --component --browser=chrome --env codeCoverageTasksRegistered=true", - "cypress:cli": "cypress run --component --browser=chrome", + "cypress:run": "cypress run --component --browser=chrome", "tokens:transform": "TS_NODE_PROJECT=tsconfig.node.json ts-node style-dictionary.transform.ts" }, "sideEffects": false, @@ -29,8 +30,7 @@ "author": { "name": "centreon@centreon.com" }, - "baseCodeCoveragePercentage": 60, - "license": "GPL-2.0", + "license": "MIT", "bugs": { "url": "https://github.com/centreon/centreon/issues" }, @@ -39,7 +39,7 @@ "exports": { ".": "./src/index.ts", "./components": "./src/components/index.ts", - "./fonts/*": "./public/fonts/*", + "./fonts/*": "./src/fonts/*", "./test/testRenderer": "./test/testRenderer.tsx" }, "files": [ @@ -49,123 +49,104 @@ "test/*" ], "devDependencies": { - "@cypress/react": "^8.0.0", - "@cypress/webpack-dev-server": "^3.7.4", + "@cypress/react": "^8.0.2", + "@cypress/webpack-dev-server": "^3.10.1", "@faker-js/faker": "^8.4.1", "@mdx-js/react": "^3.0.1", - "@modern-js/prod-server": "^2.49.2", - "@modern-js/storybook": "^2.49.2", - "@simonsmith/cypress-image-snapshot": "^9.0.1", - "@storybook/addon-a11y": "^7.0.9", - "@storybook/addon-docs": "^7.0.9", - "@storybook/addon-essentials": "^7.0.9", - "@storybook/addon-interactions": "^7.0.9", - "@storybook/addon-styling": "^1.0.6", - "@storybook/blocks": "^7.0.26", - "@storybook/builder-vite": "^7.6.18", - "@storybook/jest": "^0.1.0", - "@storybook/manager-api": "^7.0.9", + "@modern-js/prod-server": "^2.58.1", + "@modern-js/storybook": "^2.58.1", + "@simonsmith/cypress-image-snapshot": "^9.1.0", + "@storybook/addon-a11y": "^8.2.9", + "@storybook/addon-docs": "^8.2.9", + "@storybook/addon-essentials": "^8.2.9", + "@storybook/addon-interactions": "^8.2.9", + "@storybook/addon-themes": "^8.2.9", + "@storybook/blocks": "^8.2.9", + "@storybook/manager-api": "^8.2.9", "@storybook/mdx2-csf": "^1.1.0", - "@storybook/preview-api": "^7.0.9", - "@storybook/react": "^7.0.9", - "@storybook/react-vite": "^7.0.9", - "@storybook/test-runner": "^0.16.0", - "@storybook/testing-library": "^0.1.0", - "@storybook/theming": "^7.0.9", - "@testing-library/cypress": "^8.0.7", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", + "@storybook/preview-api": "^8.2.9", + "@storybook/react": "^8.2.9", + "@storybook/react-vite": "^8.2.9", + "@storybook/test": "^8.2.9", + "@storybook/test-runner": "^0.19.1", + "@storybook/theming": "^8.2.9", + "@testing-library/cypress": "^10.0.2", + "@testing-library/jest-dom": "^6.4.8", + "@testing-library/react": "^16.0.0", "@testing-library/react-hooks": "^8.0.1", "@types/jest": "^29.5.12", - "@types/mocha": "^10.0.6", - "@types/ramda": "^0.29.9", - "@types/react": "^18.2.65", + "@types/mocha": "^10.0.7", + "@types/ramda": "^0.30.1", + "@types/react": "^18.3.3", "@types/testing-library__jest-dom": "^6.0.0", - "@vitejs/plugin-react": "^4.2.1", - "@vitejs/plugin-react-swc": "^3.6.0", - "axios-mock-adapter": "^1.22.0", - "cypress": "^13.7.1", + "@vitejs/plugin-react": "^4.3.1", + "@vitejs/plugin-react-swc": "^3.7.0", + "chai": "^5.1.1", + "cypress": "^13.13.3", "identity-obj-proxy": "^3.0.0", "jest-transform-stub": "^2.0.0", "mochawesome": "^7.1.3", - "msw": "1.3.2", - "msw-storybook-addon": "^1.10.0", - "puppeteer": "^13.7.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-test-renderer": "^18.2.0", - "remark-gfm": "^3.0.1", - "speed-measure-vite-plugin": "^0.1.2", - "storybook": "^7.6.8", - "storybook-addon-mock": "^4.3.0", - "storybook-dark-mode": "^3.0.3", - "style-dictionary": "^3.9.2", + "msw": "2.3.5", + "msw-storybook-addon": "^2.0.3", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-test-renderer": "^18.3.1", + "remark-gfm": "^4.0.0", + "speed-measure-vite-plugin": "^1.0.1", + "storybook": "^8.2.9", + "storybook-addon-mock": "^5.0.0", + "storybook-dark-mode": "^4.0.2", + "style-dictionary": "^4.0.1", "ts-node": "^10.9.2", "use-resize-observer": "^9.1.0", - "vite": "^4.3.5", - "vite-plugin-istanbul": "^5.0.0", - "vite-plugin-svgr": "^3.3.0", + "vite": "^5.4.1", + "vite-plugin-istanbul": "^6.0.2", + "vite-plugin-svgr": "^4.2.0", "vite-plugin-turbosnap": "^1.0.3" }, + "peerDependencies": { + "@centreon/ui-context": "file:../ui-context" + }, "dependencies": { - "@lexical/html": "^0.12.6", - "@lexical/link": "^0.12.6", - "@lexical/list": "^0.12.6", - "@lexical/react": "^0.12.6", - "@lexical/rich-text": "^0.12.6", - "@lexical/selection": "^0.12.6", - "@lexical/utils": "^0.12.6", - "@react-spring/web": "^9.7.3", + "@lexical/html": "^0.17.0", + "@lexical/link": "^0.17.0", + "@lexical/list": "^0.17.0", + "@lexical/react": "^0.17.0", + "@lexical/rich-text": "^0.17.0", + "@lexical/selection": "^0.17.0", + "@lexical/utils": "^0.17.0", + "@mui/material": "^5.16.7", + "@react-spring/web": "^9.7.4", "@visx/clip-path": "^3.3.0", - "@visx/curve": "^2.1.0", + "@visx/curve": "^3.3.0", "@visx/event": "^3.3.0", "@visx/group": "^3.3.0", "@visx/hierarchy": "^3.3.0", - "@visx/legend": "^3.5.0", + "@visx/legend": "^3.10.3", "@visx/pattern": "^3.3.0", "@visx/point": "^3.3.0", "@visx/scale": "^3.5.0", - "@visx/shape": "^2.18.0", + "@visx/shape": "^3.5.0", "@visx/text": "^3.3.0", - "@visx/threshold": "^2.12.2", - "@visx/visx": "2.16.0", + "@visx/threshold": "^3.5.0", + "@visx/visx": "3.11.0", "@visx/zoom": "^3.3.0", "anylogger": "^1.0.11", "d3-array": "3.2.4", - "humanize-duration": "^3.31.0", - "lexical": "^0.12.6", + "dayjs": "^1.11.12", + "humanize-duration": "^3.32.1", + "lexical": "^0.17.0", "notistack": "^3.0.1", "numeral": "^2.0.6", - "ramda": "0.29.1", + "ramda": "0.30.1", "react-grid-layout": "^1.4.4", "react-html-parser": "^2.0.2", "react-resizable": "^3.0.5", + "react-router-dom": "^6.26.1", "react-transition-group": "^4.4.5", - "sanitize-html": "^2.12.1", + "sanitize-html": "^2.13.0", "ulog": "^2.0.0-beta.19" }, - "peerDependencies": { - "@centreon/ui-context": "file:../ui-context", - "@dnd-kit/core": "6.x", - "@dnd-kit/sortable": "6.x", - "@dnd-kit/utilities": "3.x", - "@mui/icons-material": "5.x", - "@mui/material": "5.x", - "@mui/styles": "5.x", - "@tanstack/react-query": "5.x", - "axios": ">= 1.6.4", - "dayjs": "1.x", - "formik": "2.x", - "jotai": "2.x", - "numeral": "2.x", - "ramda": "0.x", - "react-i18next": "12.x", - "react-router-dom": "6.x", - "react-scale-text": "1.x", - "resize-observer-polyfill": "1.x", - "ts.data.json": "2.x", - "tss-react": "4.x" - }, "jest-junit": { "suiteName": "jest tests", "output": "./junit.xml" @@ -175,4 +156,4 @@ "public" ] } -} \ No newline at end of file +} diff --git a/centreon/packages/ui/rspack.config.js b/centreon/packages/ui/rspack.config.js deleted file mode 100644 index 66067d3aaf..0000000000 --- a/centreon/packages/ui/rspack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const rspack = require('@rspack/core'); - -/** - * @type {import('@rspack/cli').Configuration} - */ -module.exports = { - context: __dirname, - entry: { - main: './src/index.ts' - }, - module: { - rules: [ - { - test: /\.[jt]sx?$/, - use: { - loader: 'swc-loader', - options: { - jsc: { - externalHelpers: true, - parser: { - jsx: true, - syntax: 'typescript' - }, - preserveAllComments: false, - transform: { - react: { - runtime: 'automatic', - throwIfNamespace: true, - useBuiltins: false - } - } - }, - sourceMap: true - } - } - }, - { - test: /\.svg$/, - type: 'asset' - } - ] - }, - optimization: { - minimize: false // Disabling minification because it takes too long on CI - }, - plugins: [ - new rspack.HtmlRspackPlugin({ - template: './index.html' - }) - ], - resolve: { - extensions: ['...', '.ts', '.tsx', '.jsx'] - } -}; diff --git a/centreon/packages/ui/src/@assets/icons/downtime.icon.svg b/centreon/packages/ui/src/@assets/icons/downtime.icon.svg deleted file mode 100644 index c08900b955..0000000000 --- a/centreon/packages/ui/src/@assets/icons/downtime.icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/centreon/packages/ui/src/@types/globals.d.ts b/centreon/packages/ui/src/@types/globals.d.ts index fc2aeaf749..9d2ad8203a 100644 --- a/centreon/packages/ui/src/@types/globals.d.ts +++ b/centreon/packages/ui/src/@types/globals.d.ts @@ -1,9 +1,9 @@ +import { FunctionComponent, SVGProps } from 'react'; + declare module '*.scss'; declare module '*.svg' { - import * as React from 'react'; - - export const ReactComponent: React.FunctionComponent< - React.SVGProps & { title?: string } + export const ReactComponent: FunctionComponent< + SVGProps & { title?: string } >; } diff --git a/centreon/packages/ui/src/ActionsList/ActionsList.styles.ts b/centreon/packages/ui/src/ActionsList/ActionsList.styles.ts index 9290f4fbd5..3f74d5e554 100644 --- a/centreon/packages/ui/src/ActionsList/ActionsList.styles.ts +++ b/centreon/packages/ui/src/ActionsList/ActionsList.styles.ts @@ -1,5 +1,5 @@ -import { makeStyles } from 'tss-react/mui'; import { equals } from 'ramda'; +import { makeStyles } from 'tss-react/mui'; import { Theme } from '@mui/material'; diff --git a/centreon/packages/ui/src/ActionsList/index.stories.tsx b/centreon/packages/ui/src/ActionsList/index.stories.tsx index a11d846316..f8d30e882c 100644 --- a/centreon/packages/ui/src/ActionsList/index.stories.tsx +++ b/centreon/packages/ui/src/ActionsList/index.stories.tsx @@ -1,8 +1,8 @@ import { ComponentMeta, ComponentStory } from '@storybook/react'; +import CopyIcon from '@mui/icons-material/ContentCopy'; import DeleteIcon from '@mui/icons-material/Delete'; import EditIcon from '@mui/icons-material/Edit'; -import CopyIcon from '@mui/icons-material/ContentCopy'; import { ActionVariants } from './models'; diff --git a/centreon/packages/ui/src/ActionsList/index.tsx b/centreon/packages/ui/src/ActionsList/index.tsx index f2acf89f92..3c15136834 100644 --- a/centreon/packages/ui/src/ActionsList/index.tsx +++ b/centreon/packages/ui/src/ActionsList/index.tsx @@ -1,13 +1,12 @@ -/* eslint-disable react/no-array-index-key */ -import { useTranslation } from 'react-i18next'; import { equals } from 'ramda'; +import { useTranslation } from 'react-i18next'; import { - MenuList, - MenuItem, - ListItemText, - ListItemIcon, Divider, + ListItemIcon, + ListItemText, + MenuItem, + MenuList, SvgIconTypeMap } from '@mui/material'; import { OverridableComponent } from '@mui/material/OverridableComponent'; @@ -50,6 +49,7 @@ const ActionsList = ({ {actions?.map((action, idx) => { if (equals(action, ActionsListActionDivider.divider)) { + // biome-ignore lint/suspicious/noArrayIndexKey: return ; } diff --git a/centreon/packages/ui/src/Button/Icon/index.stories.tsx b/centreon/packages/ui/src/Button/Icon/index.stories.tsx index 8e36c3209a..39d76411a8 100644 --- a/centreon/packages/ui/src/Button/Icon/index.stories.tsx +++ b/centreon/packages/ui/src/Button/Icon/index.stories.tsx @@ -1,4 +1,4 @@ -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; import { makeStyles } from 'tss-react/mui'; import AccessibilityIcon from '@mui/icons-material/Accessibility'; diff --git a/centreon/packages/ui/src/Button/Icon/index.tsx b/centreon/packages/ui/src/Button/Icon/index.tsx index 933588706b..494d1f351e 100644 --- a/centreon/packages/ui/src/Button/Icon/index.tsx +++ b/centreon/packages/ui/src/Button/Icon/index.tsx @@ -1,8 +1,8 @@ import { makeStyles } from 'tss-react/mui'; import { - IconButton as MuiIconButton, IconButtonProps, + IconButton as MuiIconButton, Tooltip } from '@mui/material'; diff --git a/centreon/packages/ui/src/Button/Save/StartIcon.tsx b/centreon/packages/ui/src/Button/Save/StartIcon.tsx index d6fadad489..cc620b2312 100644 --- a/centreon/packages/ui/src/Button/Save/StartIcon.tsx +++ b/centreon/packages/ui/src/Button/Save/StartIcon.tsx @@ -1,4 +1,4 @@ -import { always, cond, not, pipe, propEq, T } from 'ramda'; +import { T, always, cond, not, pipe, propEq } from 'ramda'; import CheckIcon from '@mui/icons-material/Check'; import SaveIcon from '@mui/icons-material/Save'; diff --git a/centreon/packages/ui/src/Checkbox/Checkbox.tsx b/centreon/packages/ui/src/Checkbox/Checkbox.tsx index 20c6ebddf4..fd137e6d7e 100644 --- a/centreon/packages/ui/src/Checkbox/Checkbox.tsx +++ b/centreon/packages/ui/src/Checkbox/Checkbox.tsx @@ -1,9 +1,9 @@ -import { makeStyles } from 'tss-react/mui'; import { T, always, cond, equals } from 'ramda'; +import { makeStyles } from 'tss-react/mui'; import { SvgIconComponent } from '@mui/icons-material'; +import { Box, FormControlLabel, Checkbox as MuiCheckbox } from '@mui/material'; import Typography, { TypographyProps } from '@mui/material/Typography'; -import { FormControlLabel, Checkbox as MuiCheckbox, Box } from '@mui/material'; export type LabelPlacement = 'bottom' | 'top' | 'end' | 'start' | undefined; diff --git a/centreon/packages/ui/src/Colors/index.stories.tsx b/centreon/packages/ui/src/Colors/index.stories.tsx index a5cac8ca6f..13c3d99937 100644 --- a/centreon/packages/ui/src/Colors/index.stories.tsx +++ b/centreon/packages/ui/src/Colors/index.stories.tsx @@ -1,5 +1,3 @@ -import React from 'react'; - import { ComponentMeta, ComponentStory } from '@storybook/react'; import { Paper } from '@mui/material'; diff --git a/centreon/packages/ui/src/Colors/index.tsx b/centreon/packages/ui/src/Colors/index.tsx index 8cfdb16b0e..0850a8b739 100644 --- a/centreon/packages/ui/src/Colors/index.tsx +++ b/centreon/packages/ui/src/Colors/index.tsx @@ -1,7 +1,7 @@ -import { makeStyles } from 'tss-react/mui'; import { includes, toPairs } from 'ramda'; +import { makeStyles } from 'tss-react/mui'; -import { Stack, Box, useTheme, Typography, Divider, Grid } from '@mui/material'; +import { Box, Divider, Grid, Stack, Typography, useTheme } from '@mui/material'; import { ThemeMode } from '@centreon/ui-context'; @@ -90,7 +90,11 @@ const GroupedColorStatus = (): JSX.Element => { key={status} keyTheme={status} /> - + ))} diff --git a/centreon/packages/ui/src/ContentWithCircularProgress/index.stories.tsx b/centreon/packages/ui/src/ContentWithCircularProgress/index.stories.tsx index 041a411377..c93d1ffae1 100644 --- a/centreon/packages/ui/src/ContentWithCircularProgress/index.stories.tsx +++ b/centreon/packages/ui/src/ContentWithCircularProgress/index.stories.tsx @@ -1,7 +1,7 @@ import { ComponentMeta, ComponentStory } from '@storybook/react'; import { makeStyles } from 'tss-react/mui'; -import { Typography, Theme } from '@mui/material'; +import { Theme, Typography } from '@mui/material'; import ContentWithCircularLoading from '.'; diff --git a/centreon/packages/ui/src/Dashboard/Dashboard.cypress.spec.tsx b/centreon/packages/ui/src/Dashboard/Dashboard.cypress.spec.tsx index 06c2417f68..fc15d1f732 100644 --- a/centreon/packages/ui/src/Dashboard/Dashboard.cypress.spec.tsx +++ b/centreon/packages/ui/src/Dashboard/Dashboard.cypress.spec.tsx @@ -41,6 +41,8 @@ const dashboardLayout: Array = [ ]; const initialize = (): void => { + cy.adjustViewport(); + cy.mount({ Component: ( @@ -52,6 +54,8 @@ const initialize = (): void => { ) }); + + cy.viewport('macbook-13'); }; describe('Dashboard', () => { @@ -61,7 +65,6 @@ describe('Dashboard', () => { cy.get('[data-widget-skeleton="a"]').should('not.exist'); cy.get('[data-widget-skeleton="b"]').should('not.exist'); cy.get('[data-widget-skeleton="c"]').should('not.exist'); - cy.get('[data-widget-skeleton="d"]').should('exist'); cy.makeSnapshot(); }); diff --git a/centreon/packages/ui/src/Dashboard/Dashboard.styles.ts b/centreon/packages/ui/src/Dashboard/Dashboard.styles.ts index 4276ff978a..3cf51ca639 100644 --- a/centreon/packages/ui/src/Dashboard/Dashboard.styles.ts +++ b/centreon/packages/ui/src/Dashboard/Dashboard.styles.ts @@ -1,110 +1,111 @@ -import { makeStyles } from 'tss-react/mui'; - -import { alpha } from '@mui/material'; - -export const useDashboardLayoutStyles = makeStyles()( - (theme, isStatic: boolean) => ({ - container: { - '& .react-grid-item': { - borderRadius: theme.shape.borderRadius, - transition: theme.transitions.create('all', { - delay: 0, - duration: 100, - easing: theme.transitions.easing.easeOut - }) - }, - '& .react-grid-item.react-draggable-dragging': { - boxShadow: theme.shadows[3] - }, - '& .react-grid-item.react-grid-placeholder': { - backgroundColor: alpha(theme.palette.primary.main, 0.2) - }, - '& .react-grid-item.resizing': { - boxShadow: theme.shadows[3] - }, - '& .react-resizable-handle': { - backgroundColor: theme.palette.action.focus, - backgroundImage: 'none', - borderRadius: theme.shape.borderRadius, - display: isStatic ? 'none' : 'block', - opacity: 0, - position: 'absolute' - }, - '& .react-resizable-handle.react-resizable-handle-e': { - cursor: 'ew-resize', - height: `calc(100% - ${theme.spacing(3)})`, - marginTop: 0, - right: 0, - top: 0, - transform: 'rotate(0deg)', - width: theme.spacing(1) - }, - '& .react-resizable-handle.react-resizable-handle-s': { - bottom: 0, - cursor: 'ns-resize', - height: theme.spacing(1), - left: 0, - marginLeft: 0, - transform: 'rotate(0deg)', - width: `calc(100% - ${theme.spacing(3)})` - }, - '& .react-resizable-handle.react-resizable-handle-se': { - bottom: 0, - cursor: 'nwse-resize', - height: theme.spacing(2), - right: 0, - transform: 'rotate(0deg)', - width: theme.spacing(2) - }, - '& .react-resizable-handle::after': { - content: 'none' - }, - '& .react-resizable-handle:hover': { - opacity: 1 - }, - position: 'relative' - } - }) -); - -export const useDashboardItemStyles = makeStyles<{ hasHeader: boolean }>()( - (theme, { hasHeader }) => ({ - widgetContainer: { - '&[data-padding="false"]': { - padding: 0 - }, - background: theme.palette.background.widget, - border: 'none', - borderRadius: theme.spacing(1), - height: '100%', - width: '100%' - }, - widgetContent: { - height: hasHeader - ? `calc(100% - ${theme.spacing(3.5)} - ${theme.spacing(0.5)})` - : `calc(100% - ${theme.spacing(3.5)})` - }, - widgetHeader: { - '&:hover': { - backgroundColor: theme.palette.action.hover - }, - '&[data-canMove="false"]': { - cursor: 'default' - }, - '&[data-canMove="true"]': { - cursor: 'move' - }, - padding: theme.spacing(0, 1.5), - position: 'relative' - }, - widgetHeaderDraggable: { - height: '100%', - position: 'absolute', - width: '95%' - }, - widgetPadding: { - overflowX: 'auto', - padding: theme.spacing(0.5, 1.5, 1.5) - } - }) -); +import { makeStyles } from 'tss-react/mui'; + +import { alpha } from '@mui/material'; + +export const useDashboardLayoutStyles = makeStyles()( + (theme, isStatic: boolean) => ({ + container: { + '& .react-grid-item': { + borderRadius: theme.shape.borderRadius, + transition: theme.transitions.create('all', { + delay: 0, + duration: 100, + easing: theme.transitions.easing.easeOut + }) + }, + '& .react-grid-item.react-draggable-dragging': { + boxShadow: theme.shadows[3] + }, + '& .react-grid-item.react-grid-placeholder': { + backgroundColor: alpha(theme.palette.primary.main, 0.2) + }, + '& .react-grid-item.resizing': { + boxShadow: theme.shadows[3] + }, + '& .react-resizable-handle': { + backgroundColor: theme.palette.action.focus, + backgroundImage: 'none', + borderRadius: theme.shape.borderRadius, + display: isStatic ? 'none' : 'block', + opacity: 0, + position: 'absolute' + }, + '& .react-resizable-handle.react-resizable-handle-e': { + cursor: 'ew-resize', + height: `calc(100% - ${theme.spacing(3)})`, + marginTop: 0, + right: 0, + top: 0, + transform: 'rotate(0deg)', + width: theme.spacing(1) + }, + '& .react-resizable-handle.react-resizable-handle-s': { + bottom: 0, + cursor: 'ns-resize', + height: theme.spacing(1), + left: 0, + marginLeft: 0, + transform: 'rotate(0deg)', + width: `calc(100% - ${theme.spacing(3)})` + }, + '& .react-resizable-handle.react-resizable-handle-se': { + bottom: 0, + cursor: 'nwse-resize', + height: theme.spacing(2), + right: 0, + transform: 'rotate(0deg)', + width: theme.spacing(2) + }, + '& .react-resizable-handle::after': { + content: 'none' + }, + '& .react-resizable-handle:hover': { + opacity: 1 + }, + position: 'relative' + } + }) +); + +export const useDashboardItemStyles = makeStyles<{ hasHeader: boolean }>()( + (theme, { hasHeader }) => ({ + widgetContainer: { + '&[data-padding="false"]': { + padding: 0 + }, + background: theme.palette.background.widget, + border: 'none', + borderRadius: theme.spacing(1), + height: '100%', + width: '100%' + }, + widgetContent: { + height: hasHeader + ? `calc(100% - ${theme.spacing(3.5)} - ${theme.spacing(0.5)})` + : `calc(100% - ${theme.spacing(3.5)})` + }, + widgetHeader: { + '&:hover': { + backgroundColor: theme.palette.action.hover + }, + '&[data-canMove="false"]': { + cursor: 'default' + }, + '&[data-canMove="true"]': { + cursor: 'move' + }, + padding: theme.spacing(0, 1.5), + position: 'relative' + }, + widgetHeaderDraggable: { + height: '100%', + position: 'absolute', + width: '95%' + }, + widgetPadding: { + overflowX: 'auto', + padding: theme.spacing(0.5, 1.5, 1.5), + position: 'relative' + } + }) +); diff --git a/centreon/packages/ui/src/Dashboard/Grid.tsx b/centreon/packages/ui/src/Dashboard/Grid.tsx index d1a8cdd2f6..42a7185e9c 100644 --- a/centreon/packages/ui/src/Dashboard/Grid.tsx +++ b/centreon/packages/ui/src/Dashboard/Grid.tsx @@ -1,7 +1,7 @@ -import { useMemo, ReactElement } from 'react'; +import { ReactElement, useMemo } from 'react'; -import { Grid as VisxGrid } from '@visx/visx'; import { scaleLinear } from '@visx/scale'; +import { Grid as VisxGrid } from '@visx/visx'; import { useTheme } from '@mui/material'; diff --git a/centreon/packages/ui/src/Dashboard/Item.tsx b/centreon/packages/ui/src/Dashboard/Item.tsx index 14aeb92488..bacf26ee6f 100644 --- a/centreon/packages/ui/src/Dashboard/Item.tsx +++ b/centreon/packages/ui/src/Dashboard/Item.tsx @@ -1,20 +1,23 @@ import { CSSProperties, ForwardedRef, - forwardRef, MouseEvent, ReactElement, - useEffect + forwardRef, + useEffect, + useMemo } from 'react'; -import { isNil, prop } from 'ramda'; +import { useAtomValue } from 'jotai'; +import { equals, isNil, prop } from 'ramda'; import { Card, useTheme } from '@mui/material'; -import { useMemoComponent, useViewportIntersection } from '../utils'; import LoadingSkeleton from '../LoadingSkeleton'; +import { useMemoComponent, useViewportIntersection } from '../utils'; import { useDashboardItemStyles } from './Dashboard.styles'; +import { isResizingItemAtom } from './atoms'; interface DashboardItemProps { additionalMemoProps?: Array; @@ -55,6 +58,18 @@ const Item = forwardRef( const { classes, cx } = useDashboardItemStyles({ hasHeader }); const theme = useTheme(); + const isResizingItem = useAtomValue(isResizingItemAtom); + + const isResizing = useMemo( + () => equals(id, isResizingItem), + [isResizingItem, id] + ); + + const sanitizedReactGridLayoutClassName = useMemo( + () => (isResizing ? className : className?.replace(' resizing ', '')), + [className, isResizing] + ); + const listeners = { onMouseDown, onMouseUp, @@ -75,7 +90,7 @@ const Item = forwardRef( Component: (
( > {header && (
-
+ {canMove && ( +
+ )} {header}
)} diff --git a/centreon/packages/ui/src/Dashboard/Layout.tsx b/centreon/packages/ui/src/Dashboard/Layout.tsx index 23c0258c49..e423d16ca2 100644 --- a/centreon/packages/ui/src/Dashboard/Layout.tsx +++ b/centreon/packages/ui/src/Dashboard/Layout.tsx @@ -1,17 +1,19 @@ -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; +import { useSetAtom } from 'jotai'; import GridLayout, { Layout, WidthProvider } from 'react-grid-layout'; import 'react-grid-layout/css/styles.css'; import { - Responsive as ResponsiveHeight, ParentSize, + Responsive as ResponsiveHeight, useMemoComponent } from '..'; import { useDashboardLayoutStyles } from './Dashboard.styles'; -import { getColumnsFromScreenSize, getLayout, rowHeight } from './utils'; import Grid from './Grid'; +import { isResizingItemAtom } from './atoms'; +import { getColumnsFromScreenSize, getLayout, rowHeight } from './utils'; const ReactGridLayout = WidthProvider(GridLayout); @@ -36,10 +38,20 @@ const DashboardLayout = ({ const [columns, setColumns] = useState(getColumnsFromScreenSize()); + const setIsResizingItem = useSetAtom(isResizingItemAtom); + const resize = (): void => { setColumns(getColumnsFromScreenSize()); }; + const startResize = useCallback((_, _e, newItem: T) => { + setIsResizingItem(newItem.i); + }, []); + + const stopResize = useCallback(() => { + setIsResizingItem(null); + }, []); + useEffect(() => { window.addEventListener('resize', resize); @@ -66,6 +78,8 @@ const DashboardLayout = ({ rowHeight={rowHeight} width={width} onLayoutChange={changeLayout} + onResizeStart={startResize} + onResizeStop={stopResize} > {children} diff --git a/centreon/packages/ui/src/Dashboard/atoms.ts b/centreon/packages/ui/src/Dashboard/atoms.ts new file mode 100644 index 0000000000..a8a29855a4 --- /dev/null +++ b/centreon/packages/ui/src/Dashboard/atoms.ts @@ -0,0 +1,3 @@ +import { atom } from 'jotai'; + +export const isResizingItemAtom = atom(null); diff --git a/centreon/packages/ui/src/Dashboard/index.tsx b/centreon/packages/ui/src/Dashboard/index.tsx index afde535637..2399d7958c 100644 --- a/centreon/packages/ui/src/Dashboard/index.tsx +++ b/centreon/packages/ui/src/Dashboard/index.tsx @@ -1,9 +1,9 @@ -import Layout from './Layout'; -import Item from './Item'; - -export * from './utils'; - -export const DashboardLayout = { - Item, - Layout -}; +import Item from './Item'; +import Layout from './Layout'; + +export * from './utils'; + +export const DashboardLayout = { + Item, + Layout +}; diff --git a/centreon/packages/ui/src/Dialog/Duplicate/index.test.tsx b/centreon/packages/ui/src/Dialog/Duplicate/index.test.tsx index 1641b089c0..717b1dc6b4 100644 --- a/centreon/packages/ui/src/Dialog/Duplicate/index.test.tsx +++ b/centreon/packages/ui/src/Dialog/Duplicate/index.test.tsx @@ -1,4 +1,4 @@ -import { render, fireEvent } from '../../../test/testRenderer'; +import { fireEvent, render } from '../../../test/testRenderer'; import DialogDuplicate from '.'; diff --git a/centreon/packages/ui/src/Dialog/Duplicate/index.tsx b/centreon/packages/ui/src/Dialog/Duplicate/index.tsx index 7e60e35df4..6a12390992 100644 --- a/centreon/packages/ui/src/Dialog/Duplicate/index.tsx +++ b/centreon/packages/ui/src/Dialog/Duplicate/index.tsx @@ -22,7 +22,7 @@ const Duplicate = ({ labelInput = 'Count', labelConfirm = 'Duplicate', labelTitle = 'Duplicate', - limit = Infinity, + limit = Number.POSITIVE_INFINITY, onConfirm, ...rest }: Props): JSX.Element => { @@ -37,7 +37,10 @@ const Duplicate = ({ onConfirm(event, value); }; - const isConfirmDisabled = or(isEmpty(value), parseInt(value, 10) > limit); + const isConfirmDisabled = or( + isEmpty(value), + Number.parseInt(value, 10) > limit + ); return ( ({ logo: { diff --git a/centreon/packages/ui/src/FileDropZone/index.stories.tsx b/centreon/packages/ui/src/FileDropZone/index.stories.tsx index b9f77ea91c..2bbf10d94f 100644 --- a/centreon/packages/ui/src/FileDropZone/index.stories.tsx +++ b/centreon/packages/ui/src/FileDropZone/index.stories.tsx @@ -2,8 +2,8 @@ import { useState } from 'react'; import { makeStyles } from 'tss-react/mui'; -import { Button, Paper, Typography, Theme } from '@mui/material'; import PersonIcon from '@mui/icons-material/Person'; +import { Button, Paper, Theme, Typography } from '@mui/material'; import FileDropZone, { CustomDropZoneContentProps, diff --git a/centreon/packages/ui/src/FileDropZone/index.tsx b/centreon/packages/ui/src/FileDropZone/index.tsx index 522ed8949c..d310d91c66 100644 --- a/centreon/packages/ui/src/FileDropZone/index.tsx +++ b/centreon/packages/ui/src/FileDropZone/index.tsx @@ -1,19 +1,19 @@ -import { useTranslation } from 'react-i18next'; +import { useAtomValue } from 'jotai'; import { + T, cond, equals, flatten, identity, includes, isNil, - split, - T + split } from 'ramda'; -import { useAtomValue } from 'jotai'; +import { useTranslation } from 'react-i18next'; import { makeStyles } from 'tss-react/mui'; import PostAddIcon from '@mui/icons-material/PostAdd'; -import { alpha, Box, FormHelperText, Typography } from '@mui/material'; +import { Box, FormHelperText, Typography, alpha } from '@mui/material'; import { userAtom } from '@centreon/ui-context'; diff --git a/centreon/packages/ui/src/FileDropZone/useDropzone.test.ts b/centreon/packages/ui/src/FileDropZone/useDropzone.test.ts index 3e4cc8384d..b2faafb407 100644 --- a/centreon/packages/ui/src/FileDropZone/useDropzone.test.ts +++ b/centreon/packages/ui/src/FileDropZone/useDropzone.test.ts @@ -1,4 +1,4 @@ -import { act, renderHook, RenderHookResult } from '@testing-library/react'; +import { RenderHookResult, act, renderHook } from '@testing-library/react'; import { labelFileTooBig, labelInvalidFileType } from './translatedLabels'; import useDropzone, { UseDropzoneProps, UseDropzoneState } from './useDropzone'; diff --git a/centreon/packages/ui/src/FileDropZone/useDropzone.ts b/centreon/packages/ui/src/FileDropZone/useDropzone.ts index 95886e1f59..6d15f0e25a 100644 --- a/centreon/packages/ui/src/FileDropZone/useDropzone.ts +++ b/centreon/packages/ui/src/FileDropZone/useDropzone.ts @@ -7,7 +7,7 @@ import { useState } from 'react'; -import { all, isNil, lte, not, path, pluck } from 'ramda'; +import { path, all, isNil, lte, not, pluck } from 'ramda'; import { labelFileTooBig, labelInvalidFileType } from './translatedLabels'; diff --git a/centreon/packages/ui/src/Form/CollapsibleGroup.tsx b/centreon/packages/ui/src/Form/CollapsibleGroup.tsx index 3cef1348f6..bcc399468b 100644 --- a/centreon/packages/ui/src/Form/CollapsibleGroup.tsx +++ b/centreon/packages/ui/src/Form/CollapsibleGroup.tsx @@ -3,16 +3,16 @@ import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { makeStyles } from 'tss-react/mui'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import ExpandMore from '@mui/icons-material/ExpandMore'; import { + Box, Collapse, - Tooltip, - IconButton as MuiIconButton, - Typography, ListItemButton, - Box + IconButton as MuiIconButton, + Tooltip, + Typography } from '@mui/material'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; -import ExpandMore from '@mui/icons-material/ExpandMore'; import { Group } from './Inputs/models'; diff --git a/centreon/packages/ui/src/Form/Form.cypress.spec.tsx b/centreon/packages/ui/src/Form/Form.cypress.spec.tsx index dce295aa03..33affad15d 100644 --- a/centreon/packages/ui/src/Form/Form.cypress.spec.tsx +++ b/centreon/packages/ui/src/Form/Form.cypress.spec.tsx @@ -1,6 +1,6 @@ -import { object } from 'yup'; import { faker } from '@faker-js/faker'; import { useFormikContext } from 'formik'; +import { object } from 'yup'; import { Typography } from '@mui/material'; diff --git a/centreon/packages/ui/src/Form/Form.stories.tsx b/centreon/packages/ui/src/Form/Form.stories.tsx index 4977fb8739..bbcb8dd056 100644 --- a/centreon/packages/ui/src/Form/Form.stories.tsx +++ b/centreon/packages/ui/src/Form/Form.stories.tsx @@ -1,14 +1,14 @@ import { Paper } from '@mui/material'; +import { Form, GroupDirection } from './Form'; import { BasicForm, + CustomButton, basicFormGroups, basicFormInitialValues, basicFormInputs, - basicFormValidationSchema, - CustomButton + basicFormValidationSchema } from './storiesData'; -import { Form, GroupDirection } from './Form'; export default { title: 'Form' }; diff --git a/centreon/packages/ui/src/Form/Form.tsx b/centreon/packages/ui/src/Form/Form.tsx index cb2f7b71bd..d4398026f0 100644 --- a/centreon/packages/ui/src/Form/Form.tsx +++ b/centreon/packages/ui/src/Form/Form.tsx @@ -4,12 +4,13 @@ import { FormikSharedConfig, FormikValues } from 'formik'; -import * as Yup from 'yup'; +import { ComponentType } from 'react'; +import { Schema } from 'yup'; +import { useStyles } from './Form.styles'; import FormButtons from './FormButtons'; import Inputs from './Inputs'; import { Group, InputProps } from './Inputs/models'; -import { useStyles } from './Form.styles'; export enum GroupDirection { Horizontal = 'horizontal', @@ -17,7 +18,7 @@ export enum GroupDirection { } export type FormProps = { - Buttons?: React.ComponentType; + Buttons?: ComponentType; areGroupsOpen?: boolean; children?: JSX.Element; className?: string; @@ -30,7 +31,7 @@ export type FormProps = { isLoading?: boolean; submit: (values: T, bag: FormikHelpers) => void | Promise; validate?: (values: FormikValues) => void; - validationSchema: Yup.SchemaOf; + validationSchema: Schema; } & Omit, 'isInitialValid'>; const Form = ({ diff --git a/centreon/packages/ui/src/Form/FormButtons.tsx b/centreon/packages/ui/src/Form/FormButtons.tsx index 95a66de89e..eca5e27204 100644 --- a/centreon/packages/ui/src/Form/FormButtons.tsx +++ b/centreon/packages/ui/src/Form/FormButtons.tsx @@ -1,14 +1,14 @@ import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; import { FormikValues, useFormikContext } from 'formik'; import { not } from 'ramda'; +import { useTranslation } from 'react-i18next'; import { makeStyles } from 'tss-react/mui'; import { Button } from '@mui/material'; import SaveButton from '../Button/Save'; -import { useMemoComponent, getNormalizedId } from '../utils'; +import { getNormalizedId, useMemoComponent } from '../utils'; import { labelReset, diff --git a/centreon/packages/ui/src/Form/Inputs/Autocomplete.tsx b/centreon/packages/ui/src/Form/Inputs/Autocomplete.tsx index f963e1e3f7..6d2239eafa 100644 --- a/centreon/packages/ui/src/Form/Inputs/Autocomplete.tsx +++ b/centreon/packages/ui/src/Form/Inputs/Autocomplete.tsx @@ -1,16 +1,16 @@ import { useCallback, useMemo, useState } from 'react'; import { FormikValues, useFormikContext } from 'formik'; -import { equals, isNil, map, not, path, prop, type } from 'ramda'; +import { path, equals, isNil, map, not, prop, type } from 'ramda'; import { useTranslation } from 'react-i18next'; import { FormHelperText, Stack } from '@mui/material'; +import { SelectEntry } from '../../InputField/Select'; import SingleAutocompleteField from '../../InputField/Select/Autocomplete'; -import { labelPressEnterToAccept } from '../translatedLabels'; import MultiAutocompleteField from '../../InputField/Select/Autocomplete/Multi'; import { useMemoComponent } from '../../utils'; -import { SelectEntry } from '../../InputField/Select'; +import { labelPressEnterToAccept } from '../translatedLabels'; import { InputPropsWithoutGroup, InputType } from './models'; diff --git a/centreon/packages/ui/src/Form/Inputs/Checkbox.tsx b/centreon/packages/ui/src/Form/Inputs/Checkbox.tsx index 535e14df1f..755a8d5bf8 100644 --- a/centreon/packages/ui/src/Form/Inputs/Checkbox.tsx +++ b/centreon/packages/ui/src/Form/Inputs/Checkbox.tsx @@ -5,8 +5,8 @@ import { path, split } from 'ramda'; import { Box } from '@mui/material'; -import { Checkbox as CheckboxComponent } from '../../Checkbox'; import { useMemoComponent } from '../..'; +import { Checkbox as CheckboxComponent } from '../../Checkbox'; import { InputPropsWithoutGroup } from './models'; diff --git a/centreon/packages/ui/src/Form/Inputs/CheckboxGroup.tsx b/centreon/packages/ui/src/Form/Inputs/CheckboxGroup.tsx index d0d6e5f5a5..6ba57dd53d 100644 --- a/centreon/packages/ui/src/Form/Inputs/CheckboxGroup.tsx +++ b/centreon/packages/ui/src/Form/Inputs/CheckboxGroup.tsx @@ -1,12 +1,12 @@ import { ChangeEvent, useEffect } from 'react'; import { FormikValues, useFormikContext } from 'formik'; -import { equals, includes, path, split } from 'ramda'; +import { path, equals, includes, split } from 'ramda'; import { Box, Typography } from '@mui/material'; -import { CheckboxGroup as CheckboxGroupComponent } from '../../Checkbox'; import { useMemoComponent } from '../..'; +import { CheckboxGroup as CheckboxGroupComponent } from '../../Checkbox'; import { InputPropsWithoutGroup } from './models'; diff --git a/centreon/packages/ui/src/Form/Inputs/ConnectedAutocomplete.tsx b/centreon/packages/ui/src/Form/Inputs/ConnectedAutocomplete.tsx index 4160116573..8aff3a3273 100644 --- a/centreon/packages/ui/src/Form/Inputs/ConnectedAutocomplete.tsx +++ b/centreon/packages/ui/src/Form/Inputs/ConnectedAutocomplete.tsx @@ -1,7 +1,7 @@ import { useCallback, useMemo } from 'react'; import { FormikValues, useFormikContext } from 'formik'; -import { equals, isEmpty, path, split } from 'ramda'; +import { path, equals, isEmpty, propEq, reject, split } from 'ramda'; import { useTranslation } from 'react-i18next'; import { @@ -102,9 +102,21 @@ const ConnectedAutocomplete = ({ [isMultiple] ); + const deleteItem = (_, option): void => { + const newValue = reject(propEq(option.id, 'id'), value); + + setFieldValue(fieldName, newValue); + }; + + const chipProps = connectedAutocomplete && { + color: connectedAutocomplete?.chipColor || 'default', + onDelete: deleteItem + }; + return useMemoComponent({ Component: ( , (props: InputPropsWithoutGroup) => JSX.Element | null >([ + [equals(InputType.Switch) as (b: InputType) => boolean, always(SwitchInput)], + [equals(InputType.Radio) as (b: InputType) => boolean, always(RadioInput)], [ - R.equals(InputType.Switch) as (b: InputType) => boolean, - R.always(SwitchInput) - ], - [ - R.equals(InputType.Radio) as (b: InputType) => boolean, - R.always(RadioInput) - ], - [ - R.equals(InputType.SingleAutocomplete) as (b: InputType) => boolean, - R.always(Autocomplete) - ], - [ - R.equals(InputType.MultiAutocomplete) as (b: InputType) => boolean, - R.always(Autocomplete) + equals(InputType.SingleAutocomplete) as (b: InputType) => boolean, + always(Autocomplete) ], [ - R.equals(InputType.MultiConnectedAutocomplete) as (b: InputType) => boolean, - R.always(ConnectedAutocomplete) + equals(InputType.MultiAutocomplete) as (b: InputType) => boolean, + always(Autocomplete) ], [ - R.equals(InputType.SingleConnectedAutocomplete) as ( - b: InputType - ) => boolean, - R.always(ConnectedAutocomplete) + equals(InputType.MultiConnectedAutocomplete) as (b: InputType) => boolean, + always(ConnectedAutocomplete) ], [ - R.equals(InputType.FieldsTable) as (b: InputType) => boolean, - R.always(FieldsTable) + equals(InputType.SingleConnectedAutocomplete) as (b: InputType) => boolean, + always(ConnectedAutocomplete) ], - [R.equals(InputType.Grid) as (b: InputType) => boolean, R.always(Grid)], - [R.equals(InputType.Custom) as (b: InputType) => boolean, R.always(Custom)], [ - R.equals(InputType.Checkbox) as (b: InputType) => boolean, - R.always(Checkbox) + equals(InputType.FieldsTable) as (b: InputType) => boolean, + always(FieldsTable) ], + [equals(InputType.Grid) as (b: InputType) => boolean, always(Grid)], + [equals(InputType.Custom) as (b: InputType) => boolean, always(Custom)], + [equals(InputType.Checkbox) as (b: InputType) => boolean, always(Checkbox)], [ - R.equals(InputType.CheckboxGroup) as (b: InputType) => boolean, - R.always(CheckboxGroup) + equals(InputType.CheckboxGroup) as (b: InputType) => boolean, + always(CheckboxGroup) ], - [R.equals(InputType.List) as (b: InputType) => boolean, R.always(List)], - [R.T, R.always(TextInput)] + [equals(InputType.List) as (b: InputType) => boolean, always(List)], + [T, always(TextInput)] ]); interface StylesProps { @@ -86,13 +96,13 @@ const useStyles = makeStyles()((theme, { groupDirection }) => ({ justifyContent: 'flex-end' }, divider: { - margin: R.equals(groupDirection, GroupDirection.Horizontal) + margin: equals(groupDirection, GroupDirection.Horizontal) ? theme.spacing(0, 2) : theme.spacing(2, 0) }, groups: { display: 'flex', - flexDirection: R.equals(groupDirection, GroupDirection.Horizontal) + flexDirection: equals(groupDirection, GroupDirection.Horizontal) ? 'row' : 'column' }, @@ -129,9 +139,9 @@ const Inputs = ({ const { classes, cx } = useStyles({ groupDirection }); const formikContext = useFormikContext(); - const groupsName = R.pluck('name', groups); + const groupsName = pluck('name', groups); - const visibleInputs = R.filter( + const visibleInputs = filter( ({ hideInput }) => formikContext ? !hideInput?.(formikContext?.values) || false : true, inputs @@ -139,30 +149,30 @@ const Inputs = ({ const inputsByGroup = useMemo( () => - R.groupBy( - ({ group }) => R.find(R.equals(group), groupsName) as string, + groupBy( + ({ group }) => find(equals(group), groupsName) as string, visibleInputs ), [visibleInputs] ) as Record>; const sortedGroupNames = useMemo(() => { - const sortedGroups = R.sort(R.ascend(R.prop('order')), groups); + const sortedGroups = sort(ascend(prop('order')), groups); - const usedGroups = R.filter( - ({ name }) => R.any(R.equals(name), R.keys(inputsByGroup)), + const usedGroups = filter( + ({ name }) => any(equals(name), keys(inputsByGroup)), sortedGroups ); - return R.pluck('name', usedGroups); + return pluck('name', usedGroups); }, []); const sortedInputsByGroup = useMemo( () => - R.reduce>>( + reduce>>( (acc, value) => ({ ...acc, - [value]: R.sort( + [value]: sort( (a, b) => (b?.required ? 1 : 0) - (a?.required ? 1 : 0), inputsByGroup[value] ) @@ -173,24 +183,24 @@ const Inputs = ({ [visibleInputs] ); - const lastGroup = useMemo(() => R.last(sortedGroupNames), []); + const lastGroup = useMemo(() => last(sortedGroupNames), []); const normalizedInputsByGroup = ( - R.isEmpty(sortedInputsByGroup) + isEmpty(sortedInputsByGroup) ? [[null, visibleInputs]] - : R.toPairs(sortedInputsByGroup) + : toPairs(sortedInputsByGroup) ) as Array<[string | null, Array]>; return (
{normalizedInputsByGroup.map(([groupName, groupedInputs], index) => { - const hasGroupTitle = R.not(R.isNil(groupName)); + const hasGroupTitle = not(isNil(groupName)); const groupProps = hasGroupTitle - ? R.find(R.propEq(groupName, 'name'), groups) + ? find(propEq(groupName, 'name'), groups) : ({} as Group); - const isFirstElement = areGroupsOpen || R.equals(index, 0); + const isFirstElement = areGroupsOpen || equals(index, 0); return ( @@ -240,18 +250,17 @@ const Inputs = ({
- {hasGroupTitle && - R.not(R.equals(lastGroup, groupName as string)) && ( - - )} + {hasGroupTitle && not(equals(lastGroup, groupName as string)) && ( + + )} ); })} diff --git a/centreon/packages/ui/src/Form/Inputs/models.ts b/centreon/packages/ui/src/Form/Inputs/models.ts index 53a2ac2b17..f58224c262 100644 --- a/centreon/packages/ui/src/Form/Inputs/models.ts +++ b/centreon/packages/ui/src/Form/Inputs/models.ts @@ -6,20 +6,20 @@ import { SelectEntry } from '../../InputField/Select'; import { ConditionsSearchParameter } from '../../api/buildListingEndpoint/models'; export enum InputType { - Switch, - Radio, - Text, - SingleAutocomplete, - MultiAutocomplete, - Password, - SingleConnectedAutocomplete, - MultiConnectedAutocomplete, - FieldsTable, - Grid, - Custom, - Checkbox, - CheckboxGroup, - List + Switch = 0, + Radio = 1, + Text = 2, + SingleAutocomplete = 3, + MultiAutocomplete = 4, + Password = 5, + SingleConnectedAutocomplete = 6, + MultiConnectedAutocomplete = 7, + FieldsTable = 8, + Grid = 9, + Custom = 10, + Checkbox = 11, + CheckboxGroup = 12, + List = 13 } interface FieldsTableGetRequiredProps { @@ -46,6 +46,7 @@ export interface InputProps { }; connectedAutocomplete?: { additionalConditionParameters: Array; + chipColor?: string; endpoint?: string; filterKey?: string; getRenderedOptionText?: (option) => string | JSX.Element; diff --git a/centreon/packages/ui/src/Form/storiesData.tsx b/centreon/packages/ui/src/Form/storiesData.tsx index 613d8e6bee..9299c98ca9 100644 --- a/centreon/packages/ui/src/Form/storiesData.tsx +++ b/centreon/packages/ui/src/Form/storiesData.tsx @@ -1,14 +1,14 @@ import { FormikValues, useFormikContext } from 'formik'; -import * as Yup from 'yup'; import { equals, prop } from 'ramda'; -import { Typography } from '@mui/material'; import HelpOutlineIcon from '@mui/icons-material/HelpOutline'; import MailIcon from '@mui/icons-material/MailOutline'; +import { Typography } from '@mui/material'; import { SelectEntry } from '../InputField/Select'; import { Listing } from '../api/models'; +import { array, boolean, number, object, string } from 'yup'; import { Group, InputProps, @@ -43,46 +43,42 @@ export interface BasicForm { sports: Array; } -const selectEntryValidationSchema = Yup.object().shape({ - id: Yup.number().required('Required'), - name: Yup.string().required('Required') +const selectEntryValidationSchema = object().shape({ + id: number().required('Required'), + name: string().required('Required') }); -export const basicFormValidationSchema = Yup.object().shape({ - active: Yup.boolean().required('Active is required'), - activeSortableFieldsTable: Yup.boolean().required( +export const basicFormValidationSchema = object().shape({ + active: boolean().required('Active is required'), + activeSortableFieldsTable: boolean().required( 'Active Sortable FieldsTable is required' ), - animals: Yup.array().of(selectEntryValidationSchema.required('Required')), - anotherText: Yup.string(), - certificate: Yup.string(), + animals: array().of(selectEntryValidationSchema.required('Required')), + anotherText: string(), + certificate: string(), class: selectEntryValidationSchema.nullable().required('Required'), - custom: Yup.string().required('Custom is required'), - email: Yup.string().email('Invalid email').required('Email is required'), + custom: string().required('Custom is required'), + email: string().email('Invalid email').required('Email is required'), group: selectEntryValidationSchema.nullable().required('Required'), - inviteUsers: Yup.array().of( - Yup.object({ - email: Yup.string() - .email('Invalid user email') - .required('Email is required'), + inviteUsers: array().of( + object({ + email: string().email('Invalid user email').required('Email is required'), role: selectEntryValidationSchema }) ), - inviteUsers2: Yup.array().of(Yup.string().email('Invalid user email')), - isForced: Yup.boolean().required('Is forced is required'), - language: Yup.string().required('Language is required'), - name: Yup.string().required('Name is required'), - password: Yup.string().required('Password is required'), - roleMapping: Yup.array().of( - Yup.object({ + inviteUsers2: array().of(string().email('Invalid user email')), + isForced: boolean().required('Is forced is required'), + language: string().required('Language is required'), + name: string().required('Name is required'), + password: string().required('Password is required'), + roleMapping: array().of( + object({ role: selectEntryValidationSchema, - value: Yup.string().required('Role value is required') + value: string().required('Role value is required') }) ), - scopes: Yup.array().of( - Yup.string().min(3, '3 characters min').required('Required') - ), - sports: Yup.array().of(selectEntryValidationSchema.required('Required')) + scopes: array().of(string().min(3, '3 characters min').required('Required')), + sports: array().of(selectEntryValidationSchema.required('Required')) }); const roleEntries: Array = [ diff --git a/centreon/packages/ui/src/Form/storiesData.tsx-E b/centreon/packages/ui/src/Form/storiesData.tsx-E new file mode 100644 index 0000000000..a8fd7e8258 --- /dev/null +++ b/centreon/packages/ui/src/Form/storiesData.tsx-E @@ -0,0 +1,481 @@ +import { FormikValues, useFormikContext } from 'formik'; +import { equals, prop } from 'ramda'; + +import HelpOutlineIcon from '@mui/icons-material/HelpOutline'; +import MailIcon from '@mui/icons-material/MailOutline'; +import { Typography } from '@mui/material'; + +import { SelectEntry } from '../InputField/Select'; +import { Listing } from '../api/models'; + +import { + Group, + InputProps, + InputPropsWithoutGroup, + InputType +} from './Inputs/models'; +import { object } from '; + +export interface BasicForm { + active: boolean; + activeSortableFieldsTable: boolean; + animals: Array; + anotherText: string; + certificate: string; + class: { id: number; name: string } | null; + custom: string; + email: string; + group: { id: number; name: string } | null; + inviteUsers: Array<{ + role: SelectEntry; + user: string; + }>; + inviteUsers2: Array; + isForced: boolean; + language: string; + name: string; + password: string; + roleMapping: Array<{ + role: SelectEntry; + value: string; + }>; + scopes: Array; + sports: Array; +} + +const selectEntryValidationSchema = object().shape({ + id: number().required('Required'), + name: string().required('Required') +}); + +export const basicFormValidationSchema = object().shape({ + active: boolean().required('Active is required'), + activeSortableFieldsTable: boolean().required( + 'Active Sortable FieldsTable is required' + ), + animals: array().of(selectEntryValidationSchema.required('Required')), + anotherText: string(), + certificate: string(), + class: selectEntryValidationSchema.nullable().required('Required'), + custom: string().required('Custom is required'), + email: string().email('Invalid email').required('Email is required'), + group: selectEntryValidationSchema.nullable().required('Required'), + inviteUsers: array().of( + object({ + email: string() + .email('Invalid user email') + .required('Email is required'), + role: selectEntryValidationSchema + }) + ), + inviteUsers2: array().of(string().email('Invalid user email')), + isForced: boolean().required('Is forced is required'), + language: string().required('Language is required'), + name: string().required('Name is required'), + password: string().required('Password is required'), + roleMapping: array().of( + object({ + role: selectEntryValidationSchema, + value: string().required('Role value is required') + }) + ), + scopes: array().of( + string().min(3, '3 characters min').required('Required') + ), + sports: Yup.array().of(selectEntryValidationSchema.required('Required')) +}); + +const roleEntries: Array = [ + { + id: 1, + name: 'Administrator' + }, + { + id: 2, + name: 'User' + }, + { + id: 3, + name: 'Editor' + } +]; + +export const basicFormInitialValues = { + active: false, + activeSortableFieldsTable: false, + animals: [], + certificate: '', + class: { id: 0, name: 'Class 0' }, + custom: '', + email: '', + group: null, + inviteUsers: [], + inviteUsers2: [], + isForced: false, + language: 'French', + name: '', + notifications: { + channels: { Icon: MailIcon, checked: true, label: 'mail' }, + hostevents: ['ok', 'warning'], + includeServices: { checked: true, label: 'Include services for this host' } + }, + password: '', + roleMapping: [ + { + priority: 0, + role: roleEntries[0], + value: 'example' + }, + { + priority: 1, + role: roleEntries[1], + value: 'example2' + }, + { + priority: 2, + role: roleEntries[2], + value: 'example3' + } + ], + scopes: [], + sports: [] +}; + +export const classOptions = [...Array(10).keys()].map((idx) => ({ + id: idx, + name: `Class ${idx}` +})); + +export const sportOptions = [...Array(10).keys()].map((idx) => ({ + id: idx, + name: `Sport ${idx}` +})); + +export const basicFormGroups: Array = [ + { + name: 'First group', + order: 1 + }, + { + EndIcon: () => , + TooltipContent: (): JSX.Element => Tooltip content, + name: 'Second group', + order: 2 + }, + { + name: 'Third group', + order: 3 + } +]; + +export const basicFormInputs: Array = [ + { + fieldName: 'name', + group: 'First group', + label: 'Name', + type: InputType.Text + }, + { + fieldName: 'email', + group: 'First group', + label: 'Email', + text: { + endAdornment: , + placeholder: 'Your email here' + }, + type: InputType.Text + }, + { + fieldName: 'active', + group: 'Second group', + label: 'Active', + type: InputType.Switch + }, + { + additionalLabel: 'This a very special label', + fieldName: 'password', + group: 'First group', + hideInput: (values) => values.active, + label: 'Password', + type: InputType.Password + }, + { + fieldName: 'language', + group: 'First group', + label: 'Language', + radio: { + options: [ + { + label: 'French', + value: 'French' + }, + { + label: 'English', + value: 'English' + } + ] + }, + type: InputType.Radio + }, + { + additionalLabel: 'Notifications', + fieldName: '', + grid: { + alignItems: 'center', + columns: [ + { + checkbox: { + direction: 'horizontal' + }, + fieldName: 'notifications.channels', + label: 'channels', + type: InputType.Checkbox + }, + { + fieldName: 'notifications.includeServices', + label: 'Iclude services', + type: InputType.Checkbox + }, + { + checkbox: { + direction: 'horizontal', + labelPlacement: 'top', + options: ['ok', 'warning', 'critical', 'unknown'] + }, + fieldName: 'notifications.hostevents', + label: 'host events', + type: InputType.CheckboxGroup + } + ] + }, + group: 'Third group', + label: 'Notifications', + type: InputType.Grid + }, + { + fieldName: 'anotherText', + group: 'First group', + hideInput: ({ language }) => equals(language, 'French'), + label: 'Another Text input', + type: InputType.Text + }, + { + fieldName: 'isForced', + group: 'First group', + label: 'Is Forced?', + radio: { + options: [ + { + label: 'Is not forced', + value: false + }, + { + label: 'Is forced', + value: true + } + ] + }, + type: InputType.Radio + }, + { + fieldName: '', + grid: { + columns: [ + { + autocomplete: { + options: classOptions + }, + fieldName: 'class', + label: 'Class (Single autocomplete)', + type: InputType.SingleAutocomplete + }, + { + autocomplete: { + options: sportOptions + }, + fieldName: 'sports', + label: 'Sports (Multi autocomplete)', + type: InputType.MultiAutocomplete + } + ] + }, + group: 'First group', + label: 'autocompletes', + type: InputType.Grid + }, + { + autocomplete: { + creatable: true, + options: [] + }, + fieldName: 'scopes', + group: 'First group', + label: 'Scopes (Multi autocomplete that allows value creation)', + type: InputType.MultiAutocomplete + }, + { + fieldName: '', + grid: { + columns: [ + { + connectedAutocomplete: { + additionalConditionParameters: [], + endpoint: 'endpoint' + }, + fieldName: 'group', + label: 'Group (Single connected autocomplete)', + type: InputType.SingleConnectedAutocomplete + }, + { + connectedAutocomplete: { + additionalConditionParameters: [], + endpoint: 'endpoint' + }, + fieldName: 'animals', + label: 'Animals (Multi connected autocomplete)', + type: InputType.MultiConnectedAutocomplete + } + ], + gridTemplateColumns: '400px 1fr' + }, + group: 'First group', + label: 'connected autocompletes', + type: InputType.Grid + }, + { + custom: { + Component: ({ label }: InputPropsWithoutGroup): JSX.Element => ( + This is a {label} component + ) + }, + fieldName: 'custom', + group: 'Second group', + label: 'Custom', + type: InputType.Custom + }, + { + fieldName: 'inviteUsers', + fieldsTable: { + columns: [ + { + fieldName: 'email', + label: 'Email', + required: true, + type: InputType.Text + }, + { + autocomplete: { + creatable: false, + options: roleEntries + }, + fieldName: 'role', + label: 'Role', + type: InputType.SingleAutocomplete + } + ], + defaultRowValue: { + email: 'example@test.fr', + role: null + }, + deleteLabel: 'Delete' + }, + group: 'First group', + label: 'inviteUsers', + type: InputType.FieldsTable + }, + { + fieldName: 'inviteUsers2', + fieldsTable: { + columns: [ + { + fieldName: 'email', + label: 'Email', + required: true, + type: InputType.Text + } + ], + defaultRowValue: 'example', + deleteLabel: 'Delete', + hasSingleValue: true + }, + group: 'First group', + label: 'inviteUsers2', + type: InputType.FieldsTable + }, + { + fieldName: 'activeSortableFieldsTable', + group: 'First group', + label: 'Active Sortable Fields Table', + type: InputType.Switch + }, + { + fieldName: 'roleMapping', + fieldsTable: { + columns: [ + { + fieldName: 'value', + label: 'RoleValue', + required: true, + type: InputType.Text + }, + { + autocomplete: { + creatable: false, + options: roleEntries + }, + fieldName: 'role', + label: 'RoleAcl', + type: InputType.SingleAutocomplete + } + ], + defaultRowValue: { + role: null, + value: '' + }, + deleteLabel: 'Delete', + getSortable: (values: FormikValues): boolean => + prop('activeSortableFieldsTable', values) + }, + group: 'First group', + label: 'roleMapping', + type: InputType.FieldsTable + }, + { + fieldName: 'certificate', + group: 'First group', + label: 'Certificate', + text: { + multilineRows: 4 + }, + type: InputType.Text + } +]; + +export const CustomButton = (): JSX.Element => { + const { dirty, isValid } = useFormikContext(); + + return ( +
+ Has form changed? {JSON.stringify(dirty)} + Is valid? {JSON.stringify(isValid)} +
+ ); +}; + +const buildEntities = (from): Array => { + return Array(10) + .fill(0) + .map((_, index) => ({ + id: from + index, + name: `Entity ${from + index}` + })); +}; + +export const buildResult = (page): Listing => ({ + meta: { + limit: 10, + page, + total: 40 + }, + result: buildEntities((page - 1) * 10) +}); diff --git a/centreon/packages/ui/src/Graph/BarChart/BarChart.cypress.spec.tsx b/centreon/packages/ui/src/Graph/BarChart/BarChart.cypress.spec.tsx new file mode 100644 index 0000000000..500c11efc9 --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/BarChart.cypress.spec.tsx @@ -0,0 +1,283 @@ +import { renderHook } from '@testing-library/react'; +import dayjs from 'dayjs'; +import { useAtomValue } from 'jotai'; + +import { userAtom } from '@centreon/ui-context'; + +import dataPingService from '../mockedData/pingService.json'; +import dataPingServiceMixedStacked from '../mockedData/pingServiceMixedStacked.json'; +import dataPingServiceStacked from '../mockedData/pingServiceStacked.json'; + +import BarChart, { BarChartProps } from './BarChart'; + +const defaultStart = new Date( + dayjs(Date.now()).subtract(24, 'hour').toDate().getTime() +).toISOString(); + +const defaultEnd = new Date(Date.now()).toISOString(); + +const defaultArgs = { + end: defaultEnd, + height: 500, + loading: false, + start: defaultStart +}; + +const initialize = ({ + data = dataPingService, + legend, + tooltip, + axis, + orientation, + barStyle +}: Pick< + BarChartProps, + 'data' | 'legend' | 'axis' | 'barStyle' | 'orientation' | 'tooltip' +>): void => { + cy.adjustViewport(); + + cy.mount({ + Component: ( +
+ +
+ ) + }); + + cy.viewport('macbook-13'); +}; + +const checkWidth = (orientation): void => { + if (orientation === 'vertical') { + cy.get('g[class*="visx-rows"] > line') + .eq(0) + .should('have.attr', 'x2') + .and('equal', '1135'); + + return; + } + cy.get('g[class*="visx-rows"] > line') + .eq(0) + .should('have.attr', 'x2') + .and('equal', '1170'); +}; + +describe('Bar chart', () => { + ['horizontal', 'vertical'].forEach((orientation) => { + it(`displays the bar chart ${orientation}ly`, () => { + initialize({ orientation }); + const userData = renderHook(() => useAtomValue(userAtom)); + userData.result.current.locale = 'en'; + + checkWidth(orientation); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.08644').should('be.visible'); + + cy.makeSnapshot(); + }); + + it(`displays the bar chart ${orientation}ly centered in zero`, () => { + initialize({ axis: { isCenteredZero: true }, orientation }); + + checkWidth(orientation); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.08644').should('be.visible'); + + cy.makeSnapshot(); + }); + + it(`displays the stacked bar chart ${orientation}ly`, () => { + initialize({ data: dataPingServiceStacked, orientation }); + + checkWidth(orientation); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.16196').should('be.visible'); + + cy.makeSnapshot(); + }); + + it(`displays bar chart ${orientation}ly with a mix of stacked and non-stacked data`, () => { + initialize({ data: dataPingServiceMixedStacked, orientation }); + + checkWidth(orientation); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.08644').should('be.visible'); + }); + + it(`displays the stacked bar chart ${orientation}ly centered in zero`, () => { + initialize({ + axis: { isCenteredZero: true }, + data: dataPingServiceStacked, + orientation + }); + + checkWidth(orientation); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.16196').should('be.visible'); + + cy.makeSnapshot(); + }); + + it(`displays bar chart ${orientation}ly with a mix of stacked and non-stacked data centered in zero`, () => { + initialize({ + axis: { isCenteredZero: true }, + data: dataPingServiceMixedStacked, + orientation + }); + + checkWidth(orientation); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.08644').should('be.visible'); + }); + + it(`displays bar chart ${orientation}ly with a custom style`, () => { + initialize({ + barStyle: { opacity: 0.5, radius: 0.5 }, + data: dataPingServiceMixedStacked, + orientation + }); + + checkWidth(orientation); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.08644').should('be.visible'); + }); + }); + + it('displays a tooltip when a single bar is hovered', () => { + initialize({ + orientation: 'horizontal' + }); + + checkWidth('horizontal'); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-10-0-7650.368581547736').realHover(); + + cy.contains('06/19/2024').should('be.visible'); + cy.contains('Centreon-Server: Round-Trip Maximum Time').should( + 'be.visible' + ); + cy.contains('7.47 KB').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('does not display a tooltip when a bar is hovered and a props is set', () => { + initialize({ + data: dataPingServiceStacked, + orientation: 'horizontal', + tooltip: { + mode: 'hidden', + sortOrder: 'descending' + } + }); + + checkWidth('horizontal'); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-1-0-0.05296').realHover(); + + cy.contains('06/19/2024').should('not.exist'); + + cy.findByTestId('stacked-bar-3-0-0.12340000000000001').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays a tooltip when a stacked bar is hovered', () => { + initialize({ + data: dataPingServiceStacked, + orientation: 'horizontal', + tooltip: { + mode: 'all', + sortOrder: 'ascending' + } + }); + + checkWidth('horizontal'); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-1-0-0.05296').realHover(); + + cy.contains('06/19/2024').should('be.visible'); + cy.contains('Centreon-Server: Round-Trip Maximum Time').should( + 'be.visible' + ); + cy.contains('Centreon-Server: Round-Trip Average Time').should( + 'be.visible' + ); + cy.contains('Centreon-Server: Round-Trip Minimum Time').should( + 'be.visible' + ); + cy.contains('0.05 ms').should('be.visible'); + cy.contains('0.02 ms').should('be.visible'); + cy.contains('0.11 ms').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.16196').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays a tooltip with a single metric when a stacked bar is hovered and a prop is set', () => { + initialize({ + data: dataPingServiceStacked, + orientation: 'horizontal', + tooltip: { + mode: 'single', + sortOrder: 'descending' + } + }); + + checkWidth('horizontal'); + cy.contains('0 ms').should('be.visible'); + cy.contains('20').should('be.visible'); + cy.contains(':40 AM').should('be.visible'); + + cy.findByTestId('stacked-bar-1-0-0.05296').realHover(); + + cy.contains('06/19/2024').should('be.visible'); + cy.contains('Centreon-Server: Round-Trip Average Time').should( + 'be.visible' + ); + cy.contains('0.05 ms').should('be.visible'); + + cy.findByTestId('stacked-bar-3-0-0.16196').should('be.visible'); + + cy.makeSnapshot(); + }); +}); diff --git a/centreon/packages/ui/src/Graph/BarChart/BarChart.stories.tsx b/centreon/packages/ui/src/Graph/BarChart/BarChart.stories.tsx new file mode 100644 index 0000000000..45f30c111e --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/BarChart.stories.tsx @@ -0,0 +1,213 @@ +import { Meta, StoryObj } from '@storybook/react'; +import dayjs from 'dayjs'; + +import { LineChartData } from '../common/models'; +import dataPingService from '../mockedData/pingService.json'; +import dataPingServiceMixedStacked from '../mockedData/pingServiceMixedStacked.json'; +import dataPingServiceStacked from '../mockedData/pingServiceStacked.json'; + +import BarChart from './BarChart'; + +const meta: Meta = { + component: BarChart +}; +export default meta; + +type Story = StoryObj; + +const defaultStart = new Date( + dayjs(Date.now()).subtract(24, 'hour').toDate().getTime() +).toISOString(); + +const defaultEnd = new Date(Date.now()).toISOString(); + +const defaultArgs = { + end: defaultEnd, + height: 500, + loading: false, + start: defaultStart +}; + +const Template = (args): JSX.Element => ( + +); + +export const Default: Story = { + args: defaultArgs, + render: Template +}; + +export const withCenteredZero: Story = { + args: { + ...defaultArgs, + axis: { + isCenteredZero: true + } + }, + render: Template +}; + +export const vertical: Story = { + args: { + ...defaultArgs, + height: 800, + orientation: 'vertical' + }, + render: Template +}; + +export const verticalCenteredZero: Story = { + args: { + ...defaultArgs, + axis: { + isCenteredZero: true + }, + height: 800, + orientation: 'vertical' + }, + render: Template +}; + +export const stacked: Story = { + args: { + ...defaultArgs, + data: dataPingServiceStacked + }, + render: Template +}; + +export const stackedVertical: Story = { + args: { + ...defaultArgs, + data: dataPingServiceStacked, + height: 800, + orientation: 'vertical' + }, + render: Template +}; + +export const stackedCenteredZero: Story = { + args: { + ...defaultArgs, + axis: { + isCenteredZero: true + }, + data: dataPingServiceStacked + }, + render: Template +}; + +export const stackedVerticalCenteredZero: Story = { + args: { + ...defaultArgs, + axis: { + isCenteredZero: true + }, + data: dataPingServiceStacked, + height: 800, + orientation: 'vertical' + }, + render: Template +}; + +export const thresholds: Story = { + args: { + ...defaultArgs, + thresholdUnit: 'ms', + thresholds: { + critical: [ + { + label: 'critical 1', + value: 0.1 + } + ], + enabled: true, + warning: [ + { + label: 'warning 1', + value: 0.05 + } + ] + } + }, + render: Template +}; + +export const thresholdsVertical: Story = { + args: { + ...defaultArgs, + axis: { + isCenteredZero: true + }, + orientation: 'vertical', + thresholdUnit: 'ms', + thresholds: { + critical: [ + { + label: 'critical 1', + value: 0.1 + } + ], + enabled: true, + warning: [ + { + label: 'warning 1', + value: 0.05 + } + ] + } + }, + render: Template +}; + +export const thresholdStacked: Story = { + args: { + ...defaultArgs, + data: dataPingServiceStacked, + thresholdUnit: 'ms', + thresholds: { + critical: [ + { + label: 'critical 1', + value: 0.1 + } + ], + enabled: true, + warning: [ + { + label: 'warning 1', + value: 0.05 + } + ] + } + }, + render: Template +}; + +export const customBarStyle: Story = { + args: { + ...defaultArgs, + barStyle: { + opacity: 0.5, + radius: 0.5 + } + }, + render: Template +}; + +export const mixedStacked: Story = { + args: { + ...defaultArgs, + data: dataPingServiceMixedStacked + }, + render: Template +}; + +export const mixedStackedVertical: Story = { + args: { + ...defaultArgs, + data: dataPingServiceMixedStacked, + orientation: 'vertical' + }, + render: Template +}; diff --git a/centreon/packages/ui/src/Graph/BarChart/BarChart.tsx b/centreon/packages/ui/src/Graph/BarChart/BarChart.tsx new file mode 100644 index 0000000000..6e705e73a5 --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/BarChart.tsx @@ -0,0 +1,104 @@ +import { useRef } from 'react'; + +import dayjs from 'dayjs'; +import 'dayjs/locale/en'; +import 'dayjs/locale/es'; +import 'dayjs/locale/fr'; +import 'dayjs/locale/pt'; +import localizedFormat from 'dayjs/plugin/localizedFormat'; +import timezonePlugin from 'dayjs/plugin/timezone'; +import utcPlugin from 'dayjs/plugin/utc'; +import { Provider } from 'jotai'; + +import { Box } from '@mui/material'; + +import { ParentSize } from '../../ParentSize'; +import LoadingSkeleton from '../Chart/LoadingSkeleton'; +import { LineChartProps } from '../Chart/models'; +import useChartData from '../Chart/useChartData'; +import { LineChartData, Thresholds } from '../common/models'; + +import ResponsiveBarChart from './ResponsiveBarChart'; +import { BarStyle } from './models'; + +dayjs.extend(localizedFormat); +dayjs.extend(utcPlugin); +dayjs.extend(timezonePlugin); + +export interface BarChartProps + extends Partial< + Pick + > { + barStyle?: BarStyle; + data?: LineChartData; + end: string; + limitLegend?: false | number; + loading: boolean; + orientation: 'vertical' | 'horizontal' | 'auto'; + start: string; + thresholdUnit?: string; + thresholds?: Thresholds; +} + +const BarChart = ({ + data, + end, + start, + height = 500, + tooltip, + axis, + legend, + loading, + limitLegend, + thresholdUnit, + thresholds, + orientation = 'horizontal', + header, + barStyle = { + opacity: 1, + radius: 0.2 + } +}: BarChartProps): JSX.Element => { + const { adjustedData } = useChartData({ data, end, start }); + const lineChartRef = useRef(null); + + if (loading && !adjustedData) { + return ( + + ); + } + + return ( + + + + {({ height: responsiveHeight, width }) => ( + + )} + + + + ); +}; + +export default BarChart; diff --git a/centreon/packages/ui/src/Graph/BarChart/BarGroup.tsx b/centreon/packages/ui/src/Graph/BarChart/BarGroup.tsx new file mode 100644 index 0000000000..48bda98a59 --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/BarGroup.tsx @@ -0,0 +1,239 @@ +import { memo, useMemo } from 'react'; + +import { Group } from '@visx/group'; +import { scaleBand, scaleOrdinal } from '@visx/scale'; +import { BarGroupHorizontal, BarGroup as VisxBarGroup } from '@visx/shape'; +import { ScaleLinear } from 'd3-scale'; +import { difference, equals, keys, omit, pick, pluck, uniq } from 'ramda'; + +import { useDeepMemo } from '../../utils'; +import { + getSortedStackedLines, + getTime, + getTimeSeriesForLines, + getUnits +} from '../common/timeSeries'; +import { Line, TimeValue } from '../common/timeSeries/models'; + +import BarStack from './BarStack'; +import { BarStyle } from './models'; + +interface Props { + barStyle: BarStyle; + isTooltipHidden: boolean; + lines: Array; + orientation: 'horizontal' | 'vertical'; + size: number; + timeSeries: Array; + xScale; + yScalesPerUnit: Record>; +} + +const BarGroup = ({ + orientation, + timeSeries, + size, + lines, + xScale, + yScalesPerUnit, + isTooltipHidden, + barStyle +}: Props): JSX.Element => { + const isHorizontal = equals(orientation, 'horizontal'); + + const [firstUnit] = getUnits(lines); + + const BarComponent = useMemo( + () => (isHorizontal ? VisxBarGroup : BarGroupHorizontal), + [isHorizontal] + ); + + const stackedLines = getSortedStackedLines(lines); + const stackedUnits = uniq(pluck('unit', stackedLines)); + const notStackedLines = difference(lines, stackedLines); + + const stackedKeys = stackedUnits.reduce( + (acc, unit) => ({ + ...acc, + [`stacked-${unit}`]: null + }), + {} + ); + const stackedLinesTimeSeriesPerUnit = stackedUnits.reduce( + (acc, stackedUnit) => { + const relatedLines = stackedLines.filter(({ unit }) => + equals(unit, stackedUnit) + ); + + return { + ...acc, + [stackedUnit]: { + lines: relatedLines, + timeSeries: getTimeSeriesForLines({ + lines: relatedLines, + timeSeries + }) + } + }; + }, + {} + ); + + const notStackedTimeSeries = getTimeSeriesForLines({ + lines: notStackedLines, + timeSeries + }); + + const normalizedTimeSeries = notStackedTimeSeries.map((timeSerie) => ({ + ...timeSerie, + ...stackedKeys + })); + + const lineKeys = useDeepMemo({ + deps: [normalizedTimeSeries], + variable: keys(omit(['timeTick'], normalizedTimeSeries[0])) + }); + const colors = useDeepMemo({ + deps: [lineKeys, lines], + variable: lineKeys.map((key) => { + const metric = lines.find(({ metric_id }) => + equals(metric_id, Number(key)) + ); + + return metric?.lineColor || ''; + }) + }); + + const colorScale = useMemo( + () => + scaleOrdinal({ + domain: lineKeys, + range: colors + }), + [...lineKeys, ...colors] + ); + const metricScale = useMemo( + () => + scaleBand({ + domain: lineKeys, + padding: 0.1, + range: [0, xScale.bandwidth()] + }), + [...lineKeys, xScale.bandwidth()] + ); + + const placeholderScale = yScalesPerUnit[firstUnit]; + + const barComponentBaseProps = useMemo( + () => + isHorizontal + ? { + x0: getTime, + x0Scale: xScale, + x1Scale: metricScale, + yScale: placeholderScale + } + : { + xScale: placeholderScale, + y0: getTime, + y0Scale: xScale, + y1Scale: metricScale + }, + [isHorizontal, placeholderScale, xScale, metricScale] + ); + + return ( + + color={colorScale} + data={normalizedTimeSeries} + height={size} + keys={lineKeys} + {...barComponentBaseProps} + > + {(barGroups) => + barGroups.map((barGroup) => ( + + {barGroup.bars.map((bar) => { + const isStackedBar = bar.key.startsWith('stacked-'); + const linesBar = isStackedBar + ? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')] + .lines + : (notStackedLines.find(({ metric_id }) => + equals(metric_id, Number(bar.key)) + ) as Line); + const timeSeriesBar = isStackedBar + ? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')] + .timeSeries + : notStackedTimeSeries.map((timeSerie) => ({ + timeTick: timeSerie.timeTick, + [bar.key]: timeSerie[Number(bar.key)] + })); + + return isStackedBar ? ( + + ) : ( + + ); + })} + + )) + } + + ); +}; + +const propsToMemoize = [ + 'orientation', + 'timeSeries', + 'size', + 'lines', + 'secondUnit', + 'isCenteredZero', + 'barStyle' +]; + +export default memo(BarGroup, (prevProps, nextProps) => { + const prevYScale = prevProps.yScalesPerUnit; + const prevXScale = [ + ...prevProps.xScale.domain(), + ...prevProps.xScale.range() + ]; + + const nextYScale = nextProps.yScalesPerUnit; + const nextXScale = [ + ...nextProps.xScale.domain(), + ...nextProps.xScale.range() + ]; + + return ( + equals(pick(propsToMemoize, prevProps), pick(propsToMemoize, nextProps)) && + equals(prevYScale, nextYScale) && + equals(prevXScale, nextXScale) + ); +}); diff --git a/centreon/packages/ui/src/Graph/BarChart/BarStack.tsx b/centreon/packages/ui/src/Graph/BarChart/BarStack.tsx new file mode 100644 index 0000000000..6597a73532 --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/BarStack.tsx @@ -0,0 +1,141 @@ +import { memo } from 'react'; + +import { scaleBand } from '@visx/scale'; +import { BarRounded } from '@visx/shape'; +import { dec, equals, gt, pick } from 'ramda'; + +import { BarStyle } from './models'; +import { UseBarStackProps, useBarStack } from './useBarStack'; + +const xScale = scaleBand({ + domain: [0, 0], + padding: 0, + range: [0, 0] +}); + +interface Props extends Omit { + barIndex: number; + barPadding: number; + barStyle: BarStyle; + barWidth: number; + isTooltipHidden: boolean; +} + +const getPadding = ({ padding, size, isNegativeValue }): number => { + if (!isNegativeValue) { + return padding; + } + + return padding + size; +}; + +const BarStack = ({ + timeSeries, + isHorizontal, + yScale, + lines, + barWidth, + barPadding, + barIndex, + isTooltipHidden, + barStyle = { opacity: 1, radius: 0.2 } +}: Props): JSX.Element => { + const { + BarStackComponent, + commonBarStackProps, + colorScale, + lineKeys, + exitBar, + hoverBar + } = useBarStack({ isHorizontal, lines, timeSeries, xScale, yScale }); + + return ( + + {(barStacks) => { + return barStacks.map((barStack, index) => + barStack.bars.map((bar) => { + const shouldApplyRadiusOnBottom = equals(index, 0); + const shouldApplyRadiusOnTop = equals(index, dec(barStacks.length)); + const isNegativeValue = gt(0, bar.bar[1]); + + const barRoundedProps = { + [isHorizontal ? 'bottom' : 'left']: shouldApplyRadiusOnBottom, + [isHorizontal ? 'top' : 'right']: shouldApplyRadiusOnTop + }; + + return ( + + ); + }) + ); + }} + + ); +}; + +const propsToMemoize = [ + 'timeSeries', + 'isHorizontal', + 'barWidth', + 'lines', + 'barPadding', + 'barIndex', + 'isTooltipHidden', + 'barStyle' +]; + +export default memo(BarStack, (prevProps, nextProps) => { + const prevYScaleDomain = prevProps.yScale.domain(); + const prevYScaleRange = prevProps.yScale.range(); + const nextYScaleDomain = nextProps.yScale.domain(); + const nextYScaleRange = nextProps.yScale.range(); + + return ( + equals( + [...prevYScaleDomain, ...prevYScaleRange], + [...nextYScaleDomain, ...nextYScaleRange] + ) && + equals(pick(propsToMemoize, prevProps), pick(propsToMemoize, nextProps)) + ); +}); diff --git a/centreon/packages/ui/src/Graph/BarChart/ResponsiveBarChart.tsx b/centreon/packages/ui/src/Graph/BarChart/ResponsiveBarChart.tsx new file mode 100644 index 0000000000..88983b8298 --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/ResponsiveBarChart.tsx @@ -0,0 +1,253 @@ +import { MutableRefObject, useEffect, useMemo, useRef, useState } from 'react'; + +import { useAtom } from 'jotai'; +import { equals, flatten, gte, has, isNil, pluck } from 'ramda'; + +import { Skeleton } from '@mui/material'; + +import { Tooltip } from '../../components'; +import { useDeepCompare } from '../../utils'; +import { margin } from '../Chart/common'; +import { Data, LineChartProps } from '../Chart/models'; +import { useIntersection } from '../Chart/useChartIntersection'; +import BaseChart from '../common/BaseChart/BaseChart'; +import ChartSvgWrapper from '../common/BaseChart/ChartSvgWrapper'; +import { useComputeBaseChartDimensions } from '../common/BaseChart/useComputeBaseChartDimensions'; +import Thresholds from '../common/Thresholds/Thresholds'; +import { Thresholds as ThresholdsModel } from '../common/models'; +import { + getUnits, + getXScaleBand, + getYScalePerUnit +} from '../common/timeSeries'; +import { Line } from '../common/timeSeries/models'; +import { useTooltipStyles } from '../common/useTooltipStyles'; + +import BarGroup from './BarGroup'; +import BarChartTooltip from './Tooltip/BarChartTooltip'; +import { tooltipDataAtom } from './atoms'; +import { BarStyle } from './models'; + +interface Props + extends Pick { + barStyle: BarStyle; + graphData: Data; + graphRef: MutableRefObject; + height: number; + limitLegend?: false | number; + orientation: 'vertical' | 'horizontal' | 'auto'; + thresholdUnit?: string; + thresholds?: ThresholdsModel; + width: number; +} + +const ResponsiveBarChart = ({ + graphRef, + graphData, + legend, + height, + width, + axis, + thresholdUnit, + thresholds, + header, + limitLegend, + orientation, + tooltip, + barStyle +}: Props): JSX.Element => { + const { title, timeSeries, baseAxis, lines } = graphData; + + const { classes, cx } = useTooltipStyles(); + + const [linesGraph, setLinesGraph] = useState>(lines); + const graphSvgRef = useRef(null); + + const [tooltipData, setTooltipData] = useAtom(tooltipDataAtom); + + const { isInViewport } = useIntersection({ element: graphRef?.current }); + + const displayedLines = useMemo( + () => linesGraph.filter(({ display }) => display), + [linesGraph] + ); + + const [firstUnit, secondUnit] = getUnits(displayedLines); + const allUnits = getUnits(lines); + + const { legendRef, graphWidth, graphHeight } = useComputeBaseChartDimensions({ + hasSecondUnit: Boolean(secondUnit), + height, + legendDisplay: legend?.display, + legendPlacement: legend?.placement, + width + }); + + const thresholdValues = flatten([ + pluck('value', thresholds?.warning || []), + pluck('value', thresholds?.critical || []) + ]); + + const isHorizontal = useMemo(() => { + if (!equals(orientation, 'auto')) { + return equals(orientation, 'horizontal'); + } + + return gte(graphWidth, graphHeight + 60); + }, [orientation, graphWidth, graphHeight]); + + const xScale = useMemo( + () => + getXScaleBand({ + dataTime: timeSeries, + valueWidth: isHorizontal ? graphWidth : graphHeight - 30 + }), + [timeSeries, graphWidth, isHorizontal, graphHeight] + ); + + const yScalesPerUnit = useMemo( + () => + getYScalePerUnit({ + dataLines: displayedLines, + dataTimeSeries: timeSeries, + isCenteredZero: axis?.isCenteredZero, + isHorizontal, + scale: axis?.scale, + scaleLogarithmicBase: axis?.scaleLogarithmicBase, + thresholdUnit, + thresholds: (thresholds?.enabled && thresholdValues) || [], + valueGraphHeight: + (isHorizontal ? graphHeight : graphWidth) - margin.bottom + }), + [ + displayedLines, + timeSeries, + graphHeight, + thresholdValues, + graphWidth, + thresholds?.enabled, + axis?.isCenteredZero, + axis?.scale, + axis?.scaleLogarithmicBase + ] + ); + + const leftScale = yScalesPerUnit[firstUnit]; + const rightScale = yScalesPerUnit[secondUnit]; + + useEffect( + () => { + setLinesGraph(lines); + }, + useDeepCompare([lines]) + ); + + const displayLegend = legend?.display ?? true; + + const showGridLines = useMemo( + () => isNil(axis?.showGridLines) || axis?.showGridLines, + [axis?.showGridLines] + ); + + if (!isInViewport) { + return ( + + ); + } + + const isTooltipHidden = equals(tooltip?.mode, 'hidden'); + + return ( + + + } + open={!equals(tooltip?.mode, 'hidden') && Boolean(tooltipData)} + placement="top" + > +
+ + <> + + {thresholds?.enabled && ( + setTooltipData(null)} + isHorizontal={isHorizontal} + showTooltip={({ tooltipData: thresholdLabel }) => + setTooltipData({ + thresholdLabel + }) + } + thresholdUnit={thresholdUnit} + thresholds={thresholds as ThresholdsModel} + width={isHorizontal ? graphWidth : graphHeight - margin.top} + yScalesPerUnit={yScalesPerUnit} + /> + )} + + +
+
+
+ ); +}; + +export default ResponsiveBarChart; diff --git a/centreon/packages/ui/src/Graph/BarChart/Tooltip/BarChartTooltip.tsx b/centreon/packages/ui/src/Graph/BarChart/Tooltip/BarChartTooltip.tsx new file mode 100644 index 0000000000..651857d2cc --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/Tooltip/BarChartTooltip.tsx @@ -0,0 +1,122 @@ +import { useAtomValue } from 'jotai'; +import { + path, + T, + always, + cond, + equals, + filter, + gt, + has, + isNil, + prop, + reverse, + sortBy +} from 'ramda'; + +import { Box, Typography } from '@mui/material'; + +import { useLocaleDateTimeFormat } from '../../../utils'; +import { Tooltip } from '../../Chart/models'; +import { formatMetricValueWithUnit } from '../../common/timeSeries'; +import { TimeValue } from '../../common/timeSeries/models'; +import { tooltipDataAtom } from '../atoms'; + +import { useBarChartTooltipStyles } from './useBarChartTooltipStyles'; + +interface Props extends Partial> { + base: number; + timeSeries: Array; +} + +const BarChartTooltip = ({ + timeSeries, + base, + mode, + sortOrder +}: Props): JSX.Element | null => { + const { classes } = useBarChartTooltipStyles(); + const { toDate, toTime } = useLocaleDateTimeFormat(); + const tooltipData = useAtomValue(tooltipDataAtom); + + if (isNil(tooltipData)) { + return null; + } + + if (has('thresholdLabel', tooltipData)) { + return {tooltipData.thresholdLabel}; + } + + const date = timeSeries[tooltipData.index].timeTick; + const formattedDateTime = `${toDate(date)} / ${toTime(date)}`; + + const isSingleMode = equals(mode, 'single'); + + const filteredMetrics = isSingleMode + ? filter( + ({ metric }) => equals(metric.metric_id, tooltipData.highlightedMetric), + tooltipData.data + ) + : tooltipData.data; + + const displayHighLightedMetric = gt(filteredMetrics.length, 1); + + const sortedMetrics = cond([ + [equals('name'), always(sortBy(path(['metric', 'name']), filteredMetrics))], + [equals('ascending'), always(sortBy(prop('value'), filteredMetrics))], + [ + equals('descending'), + always(reverse(sortBy(prop('value'), filteredMetrics))) + ], + [T, always(filteredMetrics)] + ])(sortOrder); + + return ( +
+ + {formattedDateTime} + +
+ {sortedMetrics.map(({ metric, value }) => ( +
+ + + {metric.name} + + + {formatMetricValueWithUnit({ + base, + unit: metric.unit, + value + })} + +
+ ))} +
+
+ ); +}; + +export default BarChartTooltip; diff --git a/centreon/packages/ui/src/Graph/BarChart/Tooltip/useBarChartTooltipStyles.ts b/centreon/packages/ui/src/Graph/BarChart/Tooltip/useBarChartTooltipStyles.ts new file mode 100644 index 0000000000..ec8a5bdd03 --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/Tooltip/useBarChartTooltipStyles.ts @@ -0,0 +1,28 @@ +import { makeStyles } from 'tss-react/mui'; + +export const useBarChartTooltipStyles = makeStyles()((theme) => ({ + metric: { + alignItems: 'center', + display: 'flex', + gap: theme.spacing(1), + weidth: '100%' + }, + metricColorBox: { + borderRadius: theme.shape.borderRadius, + flexShrink: 0, + height: theme.spacing(1.5), + width: theme.spacing(1.5) + }, + metricName: { + flexGrow: 1 + }, + metrics: { + display: 'flex', + flexDirection: 'column', + marginTop: theme.spacing(0.5), + width: '100%' + }, + tooltipContainer: { + padding: theme.spacing(1) + } +})); diff --git a/centreon/packages/ui/src/Graph/BarChart/atoms.ts b/centreon/packages/ui/src/Graph/BarChart/atoms.ts new file mode 100644 index 0000000000..4f71ab8724 --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/atoms.ts @@ -0,0 +1,5 @@ +import { atom } from 'jotai'; + +import { TooltipData } from './models'; + +export const tooltipDataAtom = atom(null); diff --git a/centreon/packages/ui/src/Graph/BarChart/models.ts b/centreon/packages/ui/src/Graph/BarChart/models.ts new file mode 100644 index 0000000000..0fb0d30582 --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/models.ts @@ -0,0 +1,21 @@ +import { Line } from '../common/timeSeries/models'; + +export type TooltipData = + | { + data: Array<{ + metric: Line; + value: number | null; + }>; + highlightedMetric: number; + index: number; + } + | { + thresholdLabel: string; + }; + +export interface BarStyle { + /** The opacity of the bar between 0 and 1. */ + opacity: number; + /** The radius of a bar between 0 and 0.5. Does not work for stacked bars */ + radius: number; +} diff --git a/centreon/packages/ui/src/Graph/BarChart/useBarChartStyles.tsx b/centreon/packages/ui/src/Graph/BarChart/useBarChartStyles.tsx new file mode 100644 index 0000000000..ae27d66e1f --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/useBarChartStyles.tsx @@ -0,0 +1,5 @@ +import { makeStyles } from 'tss-react/mui'; + +export const useBarChartStyles = makeStyles()({ + tooltipChildren: { height: '100%', width: '100%' } +}); diff --git a/centreon/packages/ui/src/Graph/BarChart/useBarStack.ts b/centreon/packages/ui/src/Graph/BarChart/useBarStack.ts new file mode 100644 index 0000000000..f60265c71c --- /dev/null +++ b/centreon/packages/ui/src/Graph/BarChart/useBarStack.ts @@ -0,0 +1,114 @@ +import { useCallback, useMemo } from 'react'; + +import { scaleOrdinal } from '@visx/scale'; +import { BarStack, BarStackHorizontal } from '@visx/shape'; +import { useSetAtom } from 'jotai'; +import { equals, keys, omit } from 'ramda'; + +import { useDeepMemo } from '../../utils'; +import { Line, TimeValue } from '../common/timeSeries/models'; + +import { tooltipDataAtom } from './atoms'; + +interface HoverBarProps { + barIndex: number; + highlightedMetric: number; +} + +export interface UseBarStackProps { + isHorizontal: boolean; + lines: Array; + timeSeries: Array; + xScale; + yScale; +} + +interface UseBarStackState { + BarStackComponent: typeof BarStack | typeof BarStackHorizontal; + colorScale; + commonBarStackProps; + exitBar: () => void; + hoverBar: (props: HoverBarProps) => () => void; + lineKeys: Array; +} + +export const useBarStack = ({ + timeSeries, + isHorizontal, + lines, + yScale, + xScale +}: UseBarStackProps): UseBarStackState => { + const setTooltipData = useSetAtom(tooltipDataAtom); + + const BarStackComponent = useMemo( + () => (isHorizontal ? BarStack : BarStackHorizontal), + [isHorizontal] + ); + + const lineKeys = useDeepMemo({ + deps: [timeSeries], + variable: keys(omit(['timeTick'], timeSeries[0])) + }); + const colors = useDeepMemo({ + deps: [lineKeys, lines], + variable: lineKeys.map((key) => { + const metric = lines.find(({ metric_id }) => + equals(metric_id, Number(key)) + ); + + return metric?.lineColor || ''; + }) + }); + + const colorScale = useMemo( + () => + scaleOrdinal({ + domain: lineKeys, + range: colors + }), + [...lineKeys, ...colors] + ); + + const commonBarStackProps = isHorizontal + ? { + x: (d) => d.timeTick, + xScale, + yScale + } + : { + xScale: yScale, + y: (d) => d.timeTick, + yScale: xScale + }; + + const hoverBar = useCallback( + ({ highlightedMetric, barIndex }: HoverBarProps) => + (): void => { + setTooltipData({ + data: lines.map((metric) => { + return { + metric, + value: timeSeries[barIndex][metric.metric_id] + }; + }), + highlightedMetric, + index: barIndex + }); + }, + [] + ); + + const exitBar = useCallback((): void => { + setTooltipData(null); + }, []); + + return { + BarStackComponent, + colorScale, + commonBarStackProps, + exitBar, + hoverBar, + lineKeys + }; +}; diff --git a/centreon/packages/ui/src/Graph/BarStack/BarStack.cypress.spec.tsx b/centreon/packages/ui/src/Graph/BarStack/BarStack.cypress.spec.tsx index 36caa8ce6d..8ea667f376 100644 --- a/centreon/packages/ui/src/Graph/BarStack/BarStack.cypress.spec.tsx +++ b/centreon/packages/ui/src/Graph/BarStack/BarStack.cypress.spec.tsx @@ -1,7 +1,7 @@ import numeral from 'numeral'; import BarStack from './BarStack'; -import { BarType, BarStackProps } from './models'; +import { BarStackProps, BarType } from './models'; const defaultData = [ { color: '#88B922', label: 'Ok', value: 148 }, @@ -55,7 +55,7 @@ describe('Bar stack', () => { it('adjusts size based on the provided width and height', () => { initialize({ displayLegend: false, height: '300px', width: '300px' }); - cy.findByTestId('barStack').should('have.css', 'height', '300px'); + cy.findByTestId('barStack').should('have.css', 'height', '270px'); cy.makeSnapshot(); }); diff --git a/centreon/packages/ui/src/Graph/BarStack/BarStack.stories.tsx b/centreon/packages/ui/src/Graph/BarStack/BarStack.stories.tsx index 64a90c226a..acd7614720 100644 --- a/centreon/packages/ui/src/Graph/BarStack/BarStack.stories.tsx +++ b/centreon/packages/ui/src/Graph/BarStack/BarStack.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react'; -import { BarType } from './models'; import ResponsiveBarStack from './ResponsiveBarStack'; +import { BarType } from './models'; import { BarStack } from '.'; @@ -50,6 +50,10 @@ const Template = (args): JSX.Element => { return ; }; +const SmallTemplate = (args): JSX.Element => { + return ; +}; + export const Vertical: Story = { args: { data, title: 'hosts' }, render: Template @@ -123,3 +127,14 @@ export const HorizontalWithoutLegend: Story = { }, render: Template }; + +export const SmallDisplay: Story = { + args: { + TooltipContent, + data, + displayValues: true, + title: 'hosts', + variant: 'horizontal' + }, + render: SmallTemplate +}; diff --git a/centreon/packages/ui/src/Graph/BarStack/BarStack.styles.ts b/centreon/packages/ui/src/Graph/BarStack/BarStack.styles.ts index 8fbecb9dc5..6197d4ba8d 100644 --- a/centreon/packages/ui/src/Graph/BarStack/BarStack.styles.ts +++ b/centreon/packages/ui/src/Graph/BarStack/BarStack.styles.ts @@ -13,12 +13,16 @@ export const useBarStackStyles = makeStyles()((theme) => ({ gap: theme.spacing(1.5), justifyContent: 'center' }, + smallTitle: { + fontSize: theme.typography.body1.fontSize + }, svgContainer: { alignItems: 'center', backgroundColor: theme.palette.background.panelGroups, borderRadius: theme.spacing(1.25), display: 'flex', - justifyContent: 'center' + justifyContent: 'center', + padding: theme.spacing(1) }, svgWrapper: { alignItems: 'center', diff --git a/centreon/packages/ui/src/Graph/BarStack/ResponsiveBarStack.tsx b/centreon/packages/ui/src/Graph/BarStack/ResponsiveBarStack.tsx index 8a28c7541b..d3834eba9d 100644 --- a/centreon/packages/ui/src/Graph/BarStack/ResponsiveBarStack.tsx +++ b/centreon/packages/ui/src/Graph/BarStack/ResponsiveBarStack.tsx @@ -1,19 +1,19 @@ import { useRef } from 'react'; -import { BarStack as BarStackVertical, BarStackHorizontal } from '@visx/shape'; import { Group } from '@visx/group'; -import numeral from 'numeral'; +import { BarStackHorizontal, BarStack as BarStackVertical } from '@visx/shape'; import { Text } from '@visx/text'; +import numeral from 'numeral'; +import { equals, lt } from 'ramda'; import { useTranslation } from 'react-i18next'; -import { equals } from 'ramda'; import { Tooltip } from '../../components'; -import { LegendProps } from '../Legend/models'; import { Legend as LegendComponent } from '../Legend'; +import { LegendProps } from '../Legend/models'; import { getValueByUnit } from '../common/utils'; -import { BarStackProps } from './models'; import { useBarStackStyles } from './BarStack.styles'; +import { BarStackProps } from './models'; import useResponsiveBarStack from './useResponsiveBarStack'; const DefaultLengd = ({ scale, direction }: LegendProps): JSX.Element => ( @@ -33,10 +33,11 @@ const ResponsiveBarStack = ({ unit = 'number', displayValues, variant = 'vertical', - legendDirection = 'column' + legendDirection = 'column', + tooltipProps = {} }: BarStackProps & { height: number; width: number }): JSX.Element => { const { t } = useTranslation(); - const { classes } = useBarStackStyles(); + const { classes, cx } = useBarStackStyles(); const titleRef = useRef(null); const legendRef = useRef(null); @@ -50,7 +51,6 @@ const ResponsiveBarStack = ({ total, xScale, yScale, - svgWrapperWidth, svgContainerSize, isVerticalBar } = useResponsiveBarStack({ @@ -68,24 +68,28 @@ const ResponsiveBarStack = ({ ? BarStackVertical : BarStackHorizontal; + const isSmallHeight = isVerticalBar ? lt(height, 190) : lt(height, 100); + const isSmallWidth = isVerticalBar ? lt(width, 80) : lt(width, 350); + const mustDisplayLegend = isSmallWidth ? false : displayLegend; + return ( -
-
+
+
{title && ( -
+
{`${numeral(total).format('0a').toUpperCase()} `} {t(title)}
)}
) } @@ -147,7 +152,11 @@ const ResponsiveBarStack = ({ isVerticalBar ? 'right-start' : 'bottom-start' } > - + undefined} + >
- {displayLegend && ( + {mustDisplayLegend && (
void; size?: number; title?: string; + tooltipProps?: object; unit?: 'percentage' | 'number'; variant?: 'vertical' | 'horizontal'; }; diff --git a/centreon/packages/ui/src/Graph/BarStack/useResponsiveBarStack.ts b/centreon/packages/ui/src/Graph/BarStack/useResponsiveBarStack.ts index 6b9065c7d9..abb5f37e46 100644 --- a/centreon/packages/ui/src/Graph/BarStack/useResponsiveBarStack.ts +++ b/centreon/packages/ui/src/Graph/BarStack/useResponsiveBarStack.ts @@ -1,8 +1,8 @@ import { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale'; -import { equals, pluck } from 'ramda'; +import { equals, gt, pluck } from 'ramda'; -import { getValueByUnit } from '../common/utils'; import { LegendScale } from '../Legend/models'; +import { getValueByUnit } from '../common/utils'; import { BarType } from './models'; @@ -11,7 +11,7 @@ interface Size { width: number; } -interface useBarStackProps { +interface UseBarStackProps { data: Array; height: number; legendRef; @@ -21,7 +21,7 @@ interface useBarStackProps { variant?: 'vertical' | 'horizontal'; width: number; } -interface useBarStackState { +interface UseBarStackState { barSize: Size; colorScale; input; @@ -29,7 +29,6 @@ interface useBarStackState { keys: Array; legendScale: LegendScale; svgContainerSize: Size; - svgWrapperWidth: number; total: number; xScale; yScale; @@ -44,7 +43,7 @@ const useResponsiveBarStack = ({ titleRef, legendRef, size -}: useBarStackProps): useBarStackState => { +}: UseBarStackProps): UseBarStackState => { const isVerticalBar = equals(variant, 'vertical'); const heightOfTitle = titleRef.current?.offsetHeight || 0; @@ -53,17 +52,15 @@ const useResponsiveBarStack = ({ const horizontalGap = widthOfLegend > 0 ? 12 : 0; const verticalGap = heightOfTitle > 0 ? 8 : 0; - const svgWrapperWidth = isVerticalBar - ? size + 36 - : width - widthOfLegend - horizontalGap; - const svgContainerSize = { height: isVerticalBar ? height - heightOfTitle - verticalGap : size, width: isVerticalBar ? size : width - widthOfLegend - horizontalGap }; const barSize = { - height: svgContainerSize.height - 16, + height: gt(height / 2, svgContainerSize.height - 16) + ? svgContainerSize.height - 16 + : svgContainerSize.height - 46, width: svgContainerSize.width - 16 }; @@ -121,7 +118,6 @@ const useResponsiveBarStack = ({ keys, legendScale, svgContainerSize, - svgWrapperWidth, total, xScale, yScale diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Point.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Point.tsx similarity index 95% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Point.tsx rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Point.tsx index a2dc235859..3744d7858b 100644 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Point.tsx +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Point.tsx @@ -5,7 +5,7 @@ interface Props { radius: number; timeTick: Date; xScale; - yPoint: number; + yPoint: number | null; } const Point = ({ diff --git a/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/RegularLines/index.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/RegularLines/index.tsx new file mode 100644 index 0000000000..c59f194da1 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/RegularLines/index.tsx @@ -0,0 +1,132 @@ +import { memo } from 'react'; + +import { Shape } from '@visx/visx'; +import { ScaleLinear, ScaleTime } from 'd3-scale'; +import { equals, isNil, pick, prop } from 'ramda'; + +import { getTime } from '../../../../common/timeSeries'; +import { TimeValue } from '../../../../common/timeSeries/models'; +import { getStrokeDashArray } from '../../../../common/utils'; +import { getCurveFactory, getFillColor } from '../../../common'; + +interface Props { + areaColor: string; + curve: 'linear' | 'step' | 'natural'; + dashLength?: number; + dashOffset?: number; + dotOffset?: number; + filled: boolean; + graphHeight: number; + highlight?: boolean; + lineColor: string; + lineWidth?: number; + metric_id: number; + shapeAreaClosed?: Record; + shapeLinePath?: Record; + timeSeries: Array; + transparency: number; + unit: string; + xScale: ScaleTime; + yScale: ScaleLinear; +} + +const RegularLine = ({ + filled, + timeSeries, + highlight, + metric_id, + lineColor, + unit, + yScale, + xScale, + areaColor, + transparency, + graphHeight, + curve, + lineWidth, + dotOffset, + dashLength, + dashOffset +}: Props): JSX.Element => { + const curveType = getCurveFactory(curve); + const formattedLineWidth = lineWidth ?? 2; + + const props = { + curve: curveType, + data: timeSeries, + defined: (value): boolean => !isNil(value[metric_id]), + opacity: 1, + stroke: lineColor, + strokeDasharray: getStrokeDashArray({ + dashLength, + dashOffset, + dotOffset, + lineWidth: formattedLineWidth + }), + strokeWidth: highlight + ? Math.ceil((formattedLineWidth || 1) * 1.3) + : formattedLineWidth, + unit, + x: (timeValue): number => xScale(getTime(timeValue)) as number, + y: (timeValue): number => yScale(prop(metric_id, timeValue)) ?? null + }; + + if (filled) { + return ( + + data-metric={metric_id} + fill={getFillColor({ areaColor, transparency })} + fillRule="nonzero" + key={metric_id} + y0={Math.min(yScale(0), graphHeight)} + yScale={yScale} + {...props} + /> + ); + } + + return data-metric={metric_id} {...props} />; +}; + +const memoizedProps = [ + 'curve', + 'lineColor', + 'areaColor', + 'filled', + 'transparency', + 'lineWidth', + 'dotOffset', + 'dashLength', + 'dashOffset' +]; + +export default memo(RegularLine, (prevProps, nextProps) => { + const { + timeSeries: prevTimeSeries, + graphHeight: prevGraphHeight, + highlight: prevHighlight, + xScale: prevXScale, + yScale: prevYScale + } = prevProps; + const { + timeSeries: nextTimeSeries, + graphHeight: nextGraphHeight, + highlight: nextHighlight, + xScale: nextXScale, + yScale: nextYScale + } = nextProps; + + const prevXScaleRange = prevXScale.range(); + const nextXScaleRange = nextXScale.range(); + const prevYScaleDomain = prevYScale.domain(); + const nextYScaleDomain = nextYScale.domain(); + + return ( + equals(prevTimeSeries, nextTimeSeries) && + equals(prevGraphHeight, nextGraphHeight) && + equals(prevHighlight, nextHighlight) && + equals(prevXScaleRange, nextXScaleRange) && + equals(prevYScaleDomain, nextYScaleDomain) && + equals(pick(memoizedProps, prevProps), pick(memoizedProps, nextProps)) + ); +}); diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/RegularLines/useRegularLines.ts b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/RegularLines/useRegularLines.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/RegularLines/useRegularLines.ts rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/RegularLines/useRegularLines.ts index 677fae6fcd..73ba37623c 100644 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/RegularLines/useRegularLines.ts +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/RegularLines/useRegularLines.ts @@ -1,7 +1,7 @@ import { difference } from 'ramda'; -import { Line } from '../../../../common/timeSeries/models'; import { getSortedStackedLines } from '../../../../common/timeSeries'; +import { Line } from '../../../../common/timeSeries/models'; interface RegularLines { regularLines: Array; diff --git a/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx new file mode 100644 index 0000000000..c5aa87bf8a --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx @@ -0,0 +1,140 @@ +import { Shape } from '@visx/visx'; +import { ScaleLinear, ScaleTime } from 'd3-scale'; +import { path, all, equals, isNil, map, not, nth, pipe, prop } from 'ramda'; + +import { getDates, getTime } from '../../../../common/timeSeries'; +import { Line, TimeValue } from '../../../../common/timeSeries/models'; +import { getPointRadius, getStrokeDashArray } from '../../../../common/utils'; +import StackedAnchorPoint, { + getYAnchorPoint +} from '../../../InteractiveComponents/AnchorPoint/StackedAnchorPoint'; +import { StackValue } from '../../../InteractiveComponents/AnchorPoint/models'; +import { getCurveFactory, getFillColor } from '../../../common'; +import Point from '../Point'; + +interface Props { + areaTransparency?: number; + curve: 'linear' | 'step' | 'natural'; + dashLength?: number; + dashOffset?: number; + displayAnchor: boolean; + dotOffset?: number; + lineWidth?: number; + lines: Array; + showArea?: boolean; + showPoints?: boolean; + timeSeries: Array; + xScale: ScaleTime; + yScale: ScaleLinear; +} + +const StackLines = ({ + timeSeries, + lines, + yScale, + xScale, + displayAnchor, + curve, + showPoints, + showArea, + areaTransparency, + lineWidth, + dashLength, + dashOffset, + dotOffset +}: Props): JSX.Element => { + const curveType = getCurveFactory(curve); + + const formattedLineWidth = lineWidth ?? 2; + + return ( + { + return pipe( + map(prop('metric_id')) as unknown as ( + displayedLines + ) => Array, + all((metric_id) => pipe(path(['data', metric_id]), isNil, not)(d)) + )(lines); + }} + keys={map(prop('metric_id'), lines)} + x={(d): number => xScale(getTime(d.data)) ?? 0} + y0={(d): number => yScale(d[0]) ?? 0} + y1={(d): number => yScale(d[1]) ?? 0} + > + {({ stacks, path: linePath }): Array => { + return stacks.map((stack, index) => { + const { areaColor, transparency, lineColor, highlight, metric_id } = + nth(index, lines) as Line; + + const formattedTransparency = isNil(areaTransparency) + ? transparency || 80 + : areaTransparency; + + return ( + + {displayAnchor && ( + } + timeSeries={timeSeries} + transparency={transparency} + xScale={xScale} + yScale={yScale} + /> + )} + {showPoints && + getDates(timeSeries).map((timeTick) => ( + , + timeTick, + yScale + })} + yScale={yScale} + /> + ))} + + + ); + }); + }} + + ); +}; + +export default StackLines; diff --git a/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/StackedLines/useStackedLines.ts b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/StackedLines/useStackedLines.ts new file mode 100644 index 0000000000..cc2c183c36 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/StackedLines/useStackedLines.ts @@ -0,0 +1,67 @@ +import { equals, pluck, uniq } from 'ramda'; + +import { + getInvertedStackedLines, + getNotInvertedStackedLines, + getTimeSeriesForLines +} from '../../../../common/timeSeries'; +import { LinesData } from '../models'; + +interface StackedLinesState { + invertedStackedLinesData: Record; + stackedLinesData: Record; +} + +const useStackedLines = ({ lines, timeSeries }): StackedLinesState => { + const regularStackedLines = getNotInvertedStackedLines(lines); + const regularStackedUnits = uniq(pluck('unit', regularStackedLines)); + const regularStackedLinesTimeSeriesPerUnit = regularStackedUnits.reduce( + (acc, stackedUnit) => { + const relatedLines = regularStackedLines.filter(({ unit }) => + equals(unit, stackedUnit) + ); + + return { + ...acc, + [stackedUnit]: { + lines: relatedLines, + timeSeries: getTimeSeriesForLines({ + lines: relatedLines, + timeSeries + }) + } + }; + }, + {} + ); + + const invertedStackedLines = getInvertedStackedLines(lines); + const invertedStackedUnits = uniq(pluck('unit', invertedStackedLines)); + const invertedStackedLinesTimeSeriesPerUnit = invertedStackedUnits.reduce( + (acc, stackedUnit) => { + const relatedLines = invertedStackedLines.filter(({ unit }) => + equals(unit, stackedUnit) + ); + + return { + ...acc, + [stackedUnit]: { + lines: relatedLines, + timeSeries: getTimeSeriesForLines({ + invert: true, + lines: relatedLines, + timeSeries + }) + } + }; + }, + {} + ); + + return { + invertedStackedLinesData: invertedStackedLinesTimeSeriesPerUnit, + stackedLinesData: regularStackedLinesTimeSeriesPerUnit + }; +}; + +export default useStackedLines; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/BasicThreshold.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/BasicThreshold.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/BasicThreshold.tsx rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/BasicThreshold.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/Circle.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/Circle.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/Circle.tsx rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/Circle.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/ThresholdWithPatternLines.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/ThresholdWithPatternLines.tsx similarity index 91% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/ThresholdWithPatternLines.tsx rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/ThresholdWithPatternLines.tsx index 09f136bf21..a2efa7397a 100644 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/ThresholdWithPatternLines.tsx +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/ThresholdWithPatternLines.tsx @@ -3,9 +3,9 @@ import { ScaleLinear } from 'd3-scale'; import { useTheme } from '@mui/material/styles'; +import { LineChartData } from '../../../../common/models'; import { adjustGraphData } from '../../../helpers/index'; import { PatternOrientation } from '../../../models'; -import { LineChartData } from '../../../../common/models'; import BasicThreshold from './BasicThreshold'; import useScaleThreshold from './useScaleThreshold'; @@ -15,20 +15,18 @@ interface Props { data: LineChartData; graphHeight: number; id: string; - leftScale: ScaleLinear; orientation?: Array; - rightScale: ScaleLinear; xScale: ScaleLinear; + yScalesPerUnit: Record>; } const ThresholdWithPatternLines = ({ graphHeight, data, orientation = ['diagonal'], - leftScale, - rightScale, xScale, id, + yScalesPerUnit, curve }: Props): JSX.Element | null => { const theme = useTheme(); @@ -36,10 +34,9 @@ const ThresholdWithPatternLines = ({ const { lines, timeSeries } = adjustGraphData(data); const result = useScaleThreshold({ - leftScale, lines, - rightScale, - xScale + xScale, + yScalesPerUnit }); if (!result) { return null; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/ThresholdWithVariation.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/ThresholdWithVariation.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/ThresholdWithVariation.tsx rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/ThresholdWithVariation.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/helpers/index.ts b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/helpers/index.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/helpers/index.ts rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/helpers/index.ts diff --git a/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/index.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/index.tsx new file mode 100644 index 0000000000..808246cdcf --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/index.tsx @@ -0,0 +1,138 @@ +import { equals, isNil } from 'ramda'; + +import { TimeValue } from '../../../../common/timeSeries/models'; +import { displayArea } from '../../../helpers/index'; +import { + PatternThreshold, + ThresholdType, + VariationThreshold +} from '../../../models'; + +import BasicThreshold from './BasicThreshold'; +import Circle from './Circle'; +import ThresholdWithPatternLines from './ThresholdWithPatternLines'; +import ThresholdWithVariation from './ThresholdWithVariation'; +import { WrapperThresholdLinesModel } from './models'; +import useScaleThreshold from './useScaleThreshold'; + +interface Props extends WrapperThresholdLinesModel { + curve: 'linear' | 'natural' | 'step'; + graphHeight: number; + timeSeries: Array; +} + +const WrapperThresholdLines = ({ + areaThresholdLines, + graphHeight, + lines, + timeSeries, + xScale, + curve, + yScalesPerUnit +}: Props): JSX.Element | null => { + const data = useScaleThreshold({ + areaThresholdLines, + lines, + xScale, + yScalesPerUnit + }); + + if (!data) { + return null; + } + + const { getX, getY0, getY1, lineColorY0, lineColorY1, ...rest } = data; + + const commonProps = { + curve, + fillAboveArea: lineColorY0, + fillBelowArea: lineColorY1, + getX, + graphHeight, + timeSeries + }; + + const thresholdLines = areaThresholdLines?.map((item, index) => { + const { type, id } = item; + + if (equals(type, ThresholdType.basic)) { + return [ + { + Component: BasicThreshold, + key: index, + props: { ...commonProps, getY0, getY1, id } + } + ]; + } + if (equals(type, ThresholdType.variation)) { + const dataVariation = item as VariationThreshold; + if (!rest?.getY0Variation || !rest.getY1Variation || !rest.getYOrigin) { + return null; + } + + return [ + { + Component: ThresholdWithVariation, + key: index, + props: { + factors: dataVariation.factors, + ...commonProps, + ...rest + } + }, + { + Component: Circle, + key: 'circle', + props: { + ...rest, + getCountDisplayedCircles: dataVariation?.getCountDisplayedCircles, + getX, + timeSeries + } + } + ]; + } + if (equals(type, ThresholdType.pattern)) { + const dataPattern = item as PatternThreshold; + + if (!displayArea(dataPattern?.data)) { + return null; + } + + const { data: pattern } = dataPattern; + + return pattern.map((element, ind) => ({ + Component: ThresholdWithPatternLines, + key: ind, + props: { + data: element, + graphHeight, + key: ind, + orientation: dataPattern?.orientation, + xScale, + yScalesPerUnit + } + })); + } + + return null; + }); + + const filteredThresholdLines = thresholdLines?.filter((item) => !isNil(item)); + + if (!filteredThresholdLines) { + return null; + } + + return ( + + {filteredThresholdLines.map((element) => + element?.map(({ Component, props, key }) => ( + + )) + )} + + ); +}; + +export default WrapperThresholdLines; diff --git a/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/models.ts b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/models.ts new file mode 100644 index 0000000000..5d2cc743f0 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/models.ts @@ -0,0 +1,104 @@ +import { ScaleLinear } from 'd3-scale'; +import { equals, reject } from 'ramda'; + +import { Line, TimeValue } from '../../../../common/timeSeries/models'; +import { GlobalAreaLines, ThresholdType } from '../../../models'; + +export interface Data { + lineColor: string; + metric: string; + yScale: ScaleLinear; +} + +export interface Point { + x: number; + y: number; +} + +export interface ArePointsOnline { + pointLower: Point; + pointOrigin: Point; + pointUpper: Point; +} +export interface Online extends ArePointsOnline { + maxDistance?: number; +} + +export interface FactorsVariation { + currentFactorMultiplication: number; + simulatedFactorMultiplication: number; +} + +export interface Result { + getX: (timeValue: TimeValue) => number; + getY0: (timeValue: TimeValue) => number; + getY1: (timeValue: TimeValue) => number; + lineColorY0: string; + lineColorY1: string; +} + +export interface EnvelopeVariationFormula { + factorsData: FactorsVariation; + lowerRealValue: number; + upperRealValue: number; +} + +export interface ThresholdLinesModel { + dataY0: Data; + dataY1: Data; + graphHeight: number; + timeSeries: Array; + xScale: ScaleLinear; +} + +export interface LinesThreshold { + lineLower: Line; + lineOrigin: Line; + lineUpper: Line; +} + +export interface WrapperThresholdLinesModel { + areaThresholdLines?: GlobalAreaLines['areaThresholdLines']; + lines: Array; + xScale: ScaleLinear; + yScalesPerUnit: Record>; +} + +export interface ScaleVariationThreshold { + getY0Variation: (timeValue: TimeValue) => number; + getY1Variation: (timeValue: TimeValue) => number; + getYOrigin: (timeValue: TimeValue) => number; +} + +export interface Circle extends ScaleVariationThreshold { + getCountDisplayedCircles?: (value: number) => void; + getX: (timeValue: TimeValue) => number; + timeSeries: Array; +} + +export const lowerLineName = 'Lower Threshold'; +export const upperLineName = 'Upper Threshold'; + +// upper,lower and origin +export const requiredNumberLinesThreshold = 3; + +export const findLineOfOriginMetricThreshold = ( + lines: Array +): Array => { + const metrics = lines.map((line) => { + const { metric } = line; + + return metric.includes('_upper_thresholds') + ? metric.replace('_upper_thresholds', '') + : null; + }); + + const originMetric = metrics.find((element) => element); + + return reject((line: Line) => !equals(line.name, originMetric), lines); +}; + +export const canDisplayThreshold = ( + areaThresholdLines: GlobalAreaLines['areaThresholdLines'] +): boolean => + !!areaThresholdLines?.find((item) => item && item.type in ThresholdType); diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/useCoordinateCircle.ts b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/useCoordinateCircle.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/useCoordinateCircle.ts rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/useCoordinateCircle.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/useScaleThreshold.ts b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/useScaleThreshold.ts similarity index 88% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/useScaleThreshold.ts rename to centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/useScaleThreshold.ts index e9efcdb8c7..ba4e28ff94 100644 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/useScaleThreshold.ts +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/Threshold/useScaleThreshold.ts @@ -1,9 +1,9 @@ import { equals, isNil, prop } from 'ramda'; -import { ThresholdType, VariationThreshold } from '../../../models'; +import { getTime, getYScale } from '../../../../common/timeSeries'; import { TimeValue } from '../../../../common/timeSeries/models'; -import { getTime, getUnits, getYScale } from '../../../../common/timeSeries'; import { displayArea } from '../../../helpers/index'; +import { ThresholdType, VariationThreshold } from '../../../models'; import { envelopeVariationFormula } from './helpers'; import { @@ -26,8 +26,7 @@ interface Result extends Partial { const useScaleThreshold = ({ lines, areaThresholdLines, - leftScale, - rightScale, + yScalesPerUnit, xScale }: WrapperThresholdLinesModel): Result | null => { const getLinesThreshold = (): LinesThreshold | null => { @@ -50,8 +49,6 @@ const useScaleThreshold = ({ const { lineUpper, lineLower, lineOrigin } = linesThreshold; - const [, secondUnit, thirdUnit] = getUnits(lines); - const { metric_id: metricY1, unit: unitY1, @@ -73,30 +70,21 @@ const useScaleThreshold = ({ } = lineOrigin; const y1Scale = getYScale({ - hasMoreThanTwoUnits: !isNil(thirdUnit), invert: invertY1, - leftScale, - rightScale, - secondUnit, - unit: unitY1 + unit: unitY1, + yScalesPerUnit }); const y0Scale = getYScale({ - hasMoreThanTwoUnits: !isNil(thirdUnit), invert: invertY0, - leftScale, - rightScale, - secondUnit, - unit: unitY0 + unit: unitY0, + yScalesPerUnit }); const yScale = getYScale({ - hasMoreThanTwoUnits: !isNil(thirdUnit), invert: invertYOrigin, - leftScale, - rightScale, - secondUnit, - unit: unitYOrigin + unit: unitYOrigin, + yScalesPerUnit }); const getX = (timeValue: TimeValue): number => { diff --git a/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/index.tsx b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/index.tsx new file mode 100644 index 0000000000..77c8501fa8 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/index.tsx @@ -0,0 +1,262 @@ +import { MutableRefObject } from 'react'; + +import { ScaleLinear } from 'd3-scale'; +import { isNil } from 'ramda'; + +import { + getDates, + getTimeSeriesForLines, + getYScale +} from '../../../common/timeSeries'; +import { Line, TimeValue } from '../../../common/timeSeries/models'; +import { getPointRadius } from '../../../common/utils'; +import GuidingLines from '../../InteractiveComponents/AnchorPoint/GuidingLines'; +import RegularAnchorPoint, { + getYAnchorPoint +} from '../../InteractiveComponents/AnchorPoint/RegularAnchorPoint'; +import { displayArea } from '../../helpers/index'; +import { DisplayAnchor, GlobalAreaLines } from '../../models'; + +import Point from './Point'; +import RegularLine from './RegularLines'; +import useRegularLines from './RegularLines/useRegularLines'; +import StackedLines from './StackedLines'; +import useStackedLines from './StackedLines/useStackedLines'; +import WrapperThresholdLines from './Threshold'; +import { + canDisplayThreshold, + requiredNumberLinesThreshold +} from './Threshold/models'; + +interface Props extends GlobalAreaLines { + areaTransparency?: number; + curve: 'linear' | 'step' | 'natural'; + dashLength?: number; + dashOffset?: number; + displayAnchor?: DisplayAnchor; + displayedLines: Array; + dotOffset?: number; + graphSvgRef: MutableRefObject; + height: number; + lineWidth?: number; + scale?: 'linear' | 'logarithmic'; + scaleLogarithmicBase?: number; + showArea?: boolean; + showPoints?: boolean; + timeSeries: Array; + width: number; + xScale: ScaleLinear; + yScalesPerUnit: Record>; +} + +const Lines = ({ + areaTransparency, + height, + graphSvgRef, + width, + displayAnchor, + curve, + yScalesPerUnit, + xScale, + timeSeries, + displayedLines, + areaThresholdLines, + areaStackedLines, + areaRegularLines, + showArea, + showPoints, + lineWidth, + dotOffset, + dashLength, + dashOffset, + scale, + scaleLogarithmicBase +}: Props): JSX.Element => { + const { stackedLinesData, invertedStackedLinesData } = useStackedLines({ + lines: displayedLines, + timeSeries + }); + + const { regularLines } = useRegularLines({ lines: displayedLines }); + + const displayThresholdArea = + displayedLines?.length >= requiredNumberLinesThreshold && + canDisplayThreshold(areaThresholdLines); + + const displayAreaRegularLines = + (areaRegularLines?.display ?? true) && displayArea(regularLines); + + const displayGuidingLines = displayAnchor?.displayGuidingLines ?? true; + const commonStackedLinesProps = { + areaTransparency, + curve, + dashLength, + dashOffset, + displayAnchor: displayGuidingLines, + dotOffset, + graphHeight: height, + graphSvgRef, + graphWidth: width, + lineWidth, + showArea, + showPoints, + xScale + }; + + return ( + + {displayGuidingLines && ( + + )} + + {(areaStackedLines?.display ?? true) && ( + <> + {Object.entries(stackedLinesData).map( + ([unit, { lines, timeSeries: stackedTimeSeries }]) => ( + + ) + )} + {Object.entries(invertedStackedLinesData).map( + ([unit, { lines, timeSeries: stackedTimeSeries }]) => ( + + ) + )} + + )} + + {displayThresholdArea && ( + + )} + + {displayAreaRegularLines + ? regularLines.map( + ({ + areaColor, + transparency, + lineColor, + filled, + unit, + highlight, + invert, + metric_id, + ...rest + }) => { + const yScale = getYScale({ + invert, + scale, + scaleLogarithmicBase, + unit, + yScalesPerUnit + }); + const relatedTimeSeries = getTimeSeriesForLines({ + invert, + lines: [ + { + areaColor, + filled, + highlight, + invert, + lineColor, + metric_id, + transparency, + unit, + ...rest + } + ], + timeSeries + }); + + return ( + + {displayGuidingLines && ( + + )} + {showPoints && + getDates(relatedTimeSeries).map((timeTick) => ( + + ))} + + + ); + } + ) + : null} + + ); +}; + +export default Lines; diff --git a/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/models.ts b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/models.ts new file mode 100644 index 0000000000..479962a3f4 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/BasicComponents/Lines/models.ts @@ -0,0 +1,42 @@ +import { ScaleLinear } from 'd3-scale'; + +import { LineChartData } from '../../../common/models'; +import { Line, TimeValue } from '../../../common/timeSeries/models'; + +import { FactorsVariation } from './Threshold/models'; + +export interface ShapeGraphData { + [x: string]: unknown; + display: boolean; + leftScale?: ScaleLinear; + rightScale?: ScaleLinear; + xScale?: ScaleLinear; + yScale?: ScaleLinear; +} + +export interface LinesData { + lines: Array; + timeSeries: Array; +} + +export interface AreaStackedLines extends ShapeGraphData { + invertedStackedLinesData: LinesData; + stackedLinesData: LinesData; +} + +export interface AreaRegularLines extends ShapeGraphData { + lines: Array; + timeSeries: Array; +} + +export interface AreaThreshold extends AreaRegularLines { + dataExclusionPeriods?: Array; + factors?: FactorsVariation; + getCountDisplayedCircles?: (value: number) => void; +} + +export interface Shape { + areaRegularLines: AreaRegularLines; + areaStackedLines: AreaStackedLines; + areaThreshold: AreaThreshold; +} diff --git a/centreon/packages/ui/src/Graph/Chart/Chart.cypress.spec.tsx b/centreon/packages/ui/src/Graph/Chart/Chart.cypress.spec.tsx new file mode 100644 index 0000000000..76f5863bde --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/Chart.cypress.spec.tsx @@ -0,0 +1,701 @@ +import { useState } from 'react'; + +import { Provider, createStore } from 'jotai'; + +import { userAtom } from '@centreon/ui-context'; + +import { LineChartData } from '../common/models'; +import dataCurvesWithSameColor from '../mockedData/curvesWithSameColor.json'; +import dataLastDay from '../mockedData/lastDay.json'; +import dataLastDayWithIncompleteValues from '../mockedData/lastDayWithIncompleteValues.json'; +import dataLastDayWithNullValues from '../mockedData/lastDayWithNullValues.json'; +import dataPingServiceLinesBars from '../mockedData/pingServiceLinesBars.json'; +import dataPingServiceLinesBarsMixed from '../mockedData/pingServiceLinesBarsMixed.json'; +import dataPingServiceLinesBarsStacked from '../mockedData/pingServiceLinesBarsStacked.json'; + +import { args as argumentsData } from './helpers/doc'; +import { LineChartProps } from './models'; + +import WrapperChart from '.'; + +interface Props + extends Pick { + data?: LineChartData; +} + +const checkLegendInformation = (): void => { + cy.contains('hitratio').should('be.visible'); + cy.contains('querytime').should('be.visible'); + cy.contains('connTime').should('be.visible'); + cy.contains('Min: 70.31').should('be.visible'); + cy.contains('Min: 0.03').should('be.visible'); + cy.contains('Max: 88.03').should('be.visible'); + cy.contains('Max: 0.98').should('be.visible'); + cy.contains('Max: 0.97').should('be.visible'); + cy.contains('Avg: 78.07').should('be.visible'); + cy.contains('Avg: 0.5').should('be.visible'); + cy.contains('Avg: 0.51').should('be.visible'); +}; + +const CustomUnitComponent = (props): JSX.Element => { + const [leftUnit, setLeftUnit] = useState('%'); + const [rightUnit, setRightUnit] = useState('ms'); + + return ( + + ); +}; + +const initialize = ({ + data = dataLastDay, + tooltip, + legend, + axis, + lineStyle +}: Props): void => { + cy.adjustViewport(); + + const store = createStore(); + store.set(userAtom, { + alias: 'admin', + locale: 'en', + name: 'admin', + timezone: 'Europe/Paris' + }); + + cy.mount({ + Component: ( + + + + ) + }); + + cy.viewport('macbook-13'); +}; + +const initializeCustomUnits = ({ + data = dataLastDay, + tooltip, + legend, + axis, + lineStyle +}: Props): void => { + cy.adjustViewport(); + + const store = createStore(); + store.set(userAtom, { + alias: 'admin', + locale: 'en', + name: 'admin', + timezone: 'Europe/Paris' + }); + + cy.mount({ + Component: ( + + + + ) + }); + + cy.viewport('macbook-13'); +}; + +const checkGraphWidth = (): void => { + cy.findByTestId('graph-interaction-zone') + .should('have.attr', 'width') + .and('equal', '1170'); + + cy.findByTestId('graph-interaction-zone') + .should('have.attr', 'height') + .and('equal', '393'); +}; + +describe('Line chart', () => { + describe('Tooltip', () => { + it('displays a tooltip when the graph is hovered', () => { + initialize({}); + + checkGraphWidth(); + + cy.contains('oracle-buffer-hit-ratio graph on srv-oracle-users').should( + 'be.visible' + ); + cy.contains('hitratio').should('be.visible'); + cy.contains('querytime').should('be.visible'); + cy.contains('connTime').should('be.visible'); + cy.contains('Min: 70.31').should('be.visible'); + + cy.findByTestId('graph-interaction-zone').realMouseMove(250, 70); + + cy.contains('06/18/2023').should('be.visible'); + + cy.contains('0.45 s').should('be.visible'); + cy.contains('75.93%').should('be.visible'); + cy.contains('0.43 s').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays a metric highlighted when the graph is hovered and the metric is the nearest point', () => { + initialize({}); + + checkGraphWidth(); + + cy.contains('Min: 70.31').should('be.visible'); + + cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); + + cy.get('[data-metric="querytime"]').should( + 'have.attr', + 'data-highlight', + 'false' + ); + cy.get('[data-metric="connTime"]').should( + 'have.attr', + 'data-highlight', + 'true' + ); + + cy.makeSnapshot(); + }); + + it('does not display the tooltip when null values are hovered', () => { + initialize({ data: dataLastDayWithNullValues }); + + checkGraphWidth(); + + cy.contains('Min: 70.31').should('be.visible'); + + cy.findByTestId('graph-interaction-zone').realMouseMove(1185, 100); + + cy.get('[data-metric="querytime"]').should('not.exist'); + + cy.makeSnapshot(); + }); + + it('displays the tooltip with defined values when the graph is hovered', () => { + initialize({ data: dataLastDayWithIncompleteValues }); + + checkGraphWidth(); + + cy.contains('Min: 70.31').should('be.visible'); + + cy.findByTestId('graph-interaction-zone').realMouseMove(1152, 100); + + cy.get('[data-metric="querytime"]').should('be.visible'); + cy.get('[data-metric="hitratio"]').should('not.exist'); + + cy.makeSnapshot(); + }); + + it('displays the tooltip a single metric when the corresponding prop is set', () => { + initialize({ tooltip: { mode: 'single', sortOrder: 'name' } }); + + checkGraphWidth(); + + cy.contains('Min: 70.31').should('be.visible'); + + cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); + + cy.get('[data-metric="connTime"]').should( + 'have.attr', + 'data-highlight', + 'true' + ); + cy.get('[data-metric="hitratio"]').should('not.exist'); + + cy.makeSnapshot(); + }); + + it('does not display the tooltip when the corresponding prop is set', () => { + initialize({ tooltip: { mode: 'hidden', sortOrder: 'name' } }); + + checkGraphWidth(); + + cy.contains('Min: 70.31').should('be.visible'); + + cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); + + cy.get('[data-metric="querytime"]').should('not.exist'); + cy.get('[data-metric="connTime"]').should('not.exist'); + + cy.makeSnapshot(); + }); + + it('sorts metrics by their value is ascending when the corresponding prop is set', () => { + initialize({ tooltip: { mode: 'all', sortOrder: 'ascending' } }); + + checkGraphWidth(); + + cy.contains('Min: 70.31').should('be.visible'); + + cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); + + cy.get('[data-metric="querytime"]').should('be.visible'); + cy.get('[data-metric="connTime"]').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('sorts metrics by their value is descending when the corresponding prop is set', () => { + initialize({ tooltip: { mode: 'all', sortOrder: 'descending' } }); + + checkGraphWidth(); + + cy.contains('Min: 70.31').should('be.visible'); + + cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); + + cy.get('[data-metric="querytime"]').should('be.visible'); + cy.get('[data-metric="connTime"]').should('be.visible'); + + cy.makeSnapshot(); + }); + }); + + it('displays the curves with different shades when curves have same color', () => { + initialize({ data: dataCurvesWithSameColor }); + + cy.findByTestId('graph-interaction-zone') + .should('have.attr', 'width') + .and('equal', '1212'); + + cy.findByLabelText('Centreon-Server: Round-Trip Average Time') + .find('[data-icon="true"]') + .should('have.css', 'background-color', 'rgb(41, 175, 238)'); + cy.findByLabelText('Centreon-Server_5: Round-Trip Average Time') + .find('[data-icon="true"]') + .should('have.css', 'background-color', 'rgb(83, 191, 241)'); + cy.findByLabelText('Centreon-Server_4: Round-Trip Average Time') + .find('[data-icon="true"]') + .should('have.css', 'background-color', 'rgb(8, 34, 47)'); + cy.findByLabelText('Centreon-Server_3: Round-Trip Average Time') + .find('[data-icon="true"]') + .should('have.css', 'background-color', 'rgb(16, 70, 95)'); + cy.findByLabelText('Centreon-Server_2: Round-Trip Average Time') + .find('[data-icon="true"]') + .should('have.css', 'background-color', 'rgb(24, 105, 142)'); + cy.findByLabelText('Centreon-Server_1: Round-Trip Average Time') + .find('[data-icon="true"]') + .should('have.css', 'background-color', 'rgb(32, 140, 190)'); + + cy.get('[data-metric="1"]').should( + 'have.attr', + 'stroke', + 'rgb(41, 175, 238)' + ); + cy.get('[data-metric="21"]').should( + 'have.attr', + 'stroke', + 'rgb(32, 140, 190)' + ); + cy.get('[data-metric="17"]').should( + 'have.attr', + 'stroke', + 'rgb(24, 105, 142)' + ); + cy.get('[data-metric="13"]').should( + 'have.attr', + 'stroke', + 'rgb(16, 70, 95)' + ); + cy.get('[data-metric="9"]').should('have.attr', 'stroke', 'rgb(8, 34, 47)'); + cy.get('[data-metric="5"]').should( + 'have.attr', + 'stroke', + 'rgb(83, 191, 241)' + ); + + cy.makeSnapshot(); + }); + + describe('Legend', () => { + it('displays the legend in list mode when the corresponding props is set', () => { + initialize({ legend: { mode: 'list', placement: 'bottom' } }); + + cy.contains('Min:').should('not.exist'); + cy.contains('Max:').should('not.exist'); + cy.contains('Avg:').should('not.exist'); + + cy.get('[data-display-side="false"]').should('exist'); + cy.get('[data-as-list="true"]').should('exist'); + + cy.contains(':00 AM').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays the legend on the left side of the graph when the corresponding prop is set', () => { + initialize({ + legend: { mode: 'grid', placement: 'left' } + }); + + cy.get('[data-display-side="true"]').should('exist'); + cy.get('[data-as-list="true"]').should('exist'); + + cy.contains(':00 AM').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays the legend on the right side of the graph as list when the corresponding props are set', () => { + initialize({ legend: { mode: 'list', placement: 'right' } }); + + cy.get('[data-display-side="true"]').should('exist'); + cy.get('[data-as-list="true"]').should('exist'); + + cy.contains(':00 AM').should('be.visible'); + + cy.makeSnapshot(); + }); + }); + + describe('Axis', () => { + it('does not display axis borders when the prop is set', () => { + initialize({ axis: { showBorder: false } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + + cy.get('line[class*="visx-axis-line"]') + .eq(0) + .should('have.attr', 'stroke-width') + .and('equal', '0'); + cy.get('line[class*="visx-axis-line"]') + .eq(1) + .should('have.attr', 'stroke-width') + .and('equal', '0'); + cy.get('line[class*="visx-axis-line"]') + .eq(2) + .should('have.attr', 'stroke-width') + .and('equal', '0'); + + cy.makeSnapshot(); + }); + + it('does not display grids when the prop is set', () => { + initialize({ axis: { showGridLines: false } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + + cy.get('g[class="visx-group visx-rows"]').should('not.exist'); + cy.get('g[class="visx-group visx-columns"]').should('not.exist'); + + cy.makeSnapshot(); + }); + + it('displays only horizontal lines when the prop is set', () => { + initialize({ axis: { gridLinesType: 'horizontal' } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + + cy.get('g[class="visx-group visx-rows"]').should('be.visible'); + cy.get('g[class="visx-group visx-columns"]').should('not.exist'); + + cy.makeSnapshot(); + }); + + it('displays only vertical lines when the prop is set', () => { + initialize({ axis: { gridLinesType: 'vertical' } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + + cy.get('g[class="visx-group visx-rows"]').should('not.exist'); + cy.get('g[class="visx-group visx-columns"]').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('rotates the tick label when the props is set', () => { + initialize({ axis: { yAxisTickLabelRotation: -35 } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + + cy.get('text[transform="rotate(-35, -2, 312.508173777963)"]').should( + 'be.visible' + ); + + cy.makeSnapshot(); + }); + + it('displays as centered to zero when the prop is set', () => { + initialize({ axis: { isCenteredZero: true } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + + cy.contains('0.9').should('be.visible'); + cy.contains('-0.9').should('be.visible'); + + cy.makeSnapshot(); + }); + }); + + describe('Line style', () => { + it('displays the curve in a natural style when the prop is set', () => { + initialize({ lineStyle: { curve: 'natural' } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + cy.get('[data-metric="13536"]').should('be.visible'); + cy.get('[data-metric="13534"]').should('be.visible'); + cy.get('[data-metric="13535"]').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays the curve in a step style when the prop is set', () => { + initialize({ lineStyle: { curve: 'step' } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + cy.get('[data-metric="13536"]').should('be.visible'); + cy.get('[data-metric="13534"]').should('be.visible'); + cy.get('[data-metric="13535"]').should('be.visible'); + checkLegendInformation(); + + cy.makeSnapshot(); + }); + + it('shows the area when the prop is set', () => { + initialize({ lineStyle: { showArea: true } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + cy.get('path[fill="rgba(102, 153, 204, 0.19999999999999996)"]').should( + 'be.visible' + ); + + cy.get('[data-metric="13536"]').should('be.visible'); + cy.get('[data-metric="13534"]').should('be.visible'); + cy.get('[data-metric="13535"]').should('be.visible'); + + checkLegendInformation(); + + cy.makeSnapshot(); + }); + + it('shows the area with a custom transparency when props are set', () => { + initialize({ lineStyle: { areaTransparency: 20, showArea: true } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + cy.get('path[fill="rgba(102, 153, 204, 0.8)"]').should('be.visible'); + }); + + it('shows points when the prop is set', () => { + initialize({ lineStyle: { showPoints: true } }); + + checkGraphWidth(); + cy.contains(':00 AM').should('be.visible'); + cy.get('circle[cx="4.0625"]').should('be.visible'); + cy.get('circle[cy="105.21757370835121"]').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays lines with a custom line width when the prop is set', () => { + initialize({ lineStyle: { lineWidth: 6 } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + cy.get('path[stroke-width="6"]').should('have.length', 3); + + cy.makeSnapshot(); + }); + + it('displays lines with dots width when the prop is set', () => { + initialize({ lineStyle: { dotOffset: 10, lineWidth: 4 } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + cy.get('path[stroke-width="4"]') + .should('have.attr', 'stroke-dasharray') + .and('equals', '4 10'); + }); + + it('displays lines with dots width when the prop is set', () => { + initialize({ lineStyle: { dashLength: 5, dashOffset: 8 } }); + + checkGraphWidth(); + + cy.contains(':00 AM').should('be.visible'); + cy.get('path[stroke-width="2"]') + .should('have.attr', 'stroke-dasharray') + .and('equals', '5 8'); + }); + }); +}); + +describe('Lines and bars', () => { + it('displays lines and bars in the same chart', () => { + initialize({ + data: dataPingServiceLinesBars + }); + + checkGraphWidth(); + + cy.get('path[data-metric="1"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.findByTestId('stacked-bar-10-0-7650.368581547736').should('be.visible'); + cy.findByTestId('stacked-bar-2-0-10').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays stacked lines and bars in the same chart', () => { + initialize({ + data: dataPingServiceLinesBarsStacked + }); + + checkGraphWidth(); + + cy.get('path[data-metric="1"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.findByTestId('stacked-bar-2-0-6835').should('be.visible'); + cy.findByTestId('stacked-bar-10-0-14920.328518673756').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays mixed lines and bars in the same chart', () => { + initialize({ + data: dataPingServiceLinesBarsMixed + }); + + checkGraphWidth(); + + cy.get('path[data-metric="1"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.findByTestId('stacked-bar-10-0-7650.368581547736').should('be.visible'); + cy.findByTestId('stacked-bar-2-0-10').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays lines and bars in the same chart centered in zero', () => { + initialize({ + axis: { + isCenteredZero: true + }, + data: dataPingServiceLinesBars + }); + + checkGraphWidth(); + + cy.get('path[data-metric="1"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.findByTestId('stacked-bar-10-0-7650.368581547736').should('be.visible'); + cy.findByTestId('stacked-bar-2-0-10').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays stacked lines and bars in the same chart centered in zero', () => { + initialize({ + axis: { + isCenteredZero: true + }, + data: dataPingServiceLinesBarsStacked + }); + + checkGraphWidth(); + + cy.get('path[data-metric="1"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.findByTestId('stacked-bar-2-0-6835').should('be.visible'); + cy.findByTestId('stacked-bar-10-0-14920.328518673756').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('displays mixed lines and bars in the same chart centered in zero', () => { + initialize({ + axis: { + isCenteredZero: true + }, + data: dataPingServiceLinesBarsMixed + }); + + checkGraphWidth(); + + cy.get('path[data-metric="1"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.get('path[data-metric="3"]').should('be.visible'); + cy.findByTestId('stacked-bar-10-0-7650.368581547736').should('be.visible'); + cy.findByTestId('stacked-bar-2-0-10').should('be.visible'); + + cy.makeSnapshot(); + }); + + it('changes the unit on the left or right scales when a new unit is selected', () => { + initializeCustomUnits({ + data: dataPingServiceLinesBarsMixed + }); + + checkGraphWidth(); + + cy.findAllByTestId('unit-selector').eq(0).parent().click(); + cy.findByLabelText('B').click(); + + cy.findAllByTestId('unit-selector').eq(0).should('have.value', 'B'); + cy.contains('8.79 KB').should('be.visible'); + + cy.findAllByTestId('unit-selector').eq(1).parent().click(); + cy.findByLabelText('%').click(); + + cy.findAllByTestId('unit-selector').eq(1).should('have.value', '%'); + cy.contains('20').should('be.visible'); + + cy.makeSnapshot(); + }); +}); diff --git a/centreon/packages/ui/src/Graph/Chart/Chart.stories.tsx b/centreon/packages/ui/src/Graph/Chart/Chart.stories.tsx new file mode 100644 index 0000000000..5dbc2e603d --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/Chart.stories.tsx @@ -0,0 +1,697 @@ +import { useEffect, useState } from 'react'; + +import { Meta, StoryObj } from '@storybook/react'; + +import { Button } from '@mui/material'; +import ButtonGroup from '@mui/material/ButtonGroup'; +import Switch from '@mui/material/Switch'; +import Tooltip from '@mui/material/Tooltip'; + +import { useLocaleDateTimeFormat } from '@centreon/ui'; + +import TimePeriod from '../../TimePeriods'; +import { LineChartData } from '../common/models'; +import annotationData from '../mockedData/annotationData.json'; +import dataCurvesSameColor from '../mockedData/curvesWithSameColor.json'; +import exclusionPeriodFirstPeriod from '../mockedData/exclusionPeriodFirstPeriod.json'; +import exclusionPeriodSecondPeriod from '../mockedData/exclusionPeriodSecondPeriod.json'; +import exclusionPeriodThirdPeriod from '../mockedData/exclusionPeriodThirdPeriod.json'; +import dataLastDay from '../mockedData/lastDay.json'; +import dataLastDayForword from '../mockedData/lastDayForward.json'; +import dataLastDayThreshold from '../mockedData/lastDayThreshold.json'; +import dataLastDayWithLotOfUnits from '../mockedData/lastDayWithLotOfUnits.json'; +import dataLastMonth from '../mockedData/lastMonth.json'; +import dataLastWeek from '../mockedData/lastWeek.json'; +import dataPingServiceLinesBars from '../mockedData/pingServiceLinesBars.json'; +import dataPingServiceLinesBarsMixed from '../mockedData/pingServiceLinesBarsMixed.json'; +import dataPingServiceLinesBarsStacked from '../mockedData/pingServiceLinesBarsStacked.json'; +import dataZoomPreview from '../mockedData/zoomPreview.json'; + +import { dateTimeFormat } from './common'; +import { + argTypes, + args as argumentsData, + defaultEnd, + defaultLast7days, + defaultLastMonth, + defaultStart, + lastDayForwardDate, + zoomPreviewDate +} from './helpers/doc'; +import { Interval, ThresholdType, TooltipData } from './models'; + +import WrapperChart from '.'; + +const meta: Meta = { + component: WrapperChart +}; +export default meta; + +type Story = StoryObj; + +interface Random { + max: number; + min: number; +} + +const Threshold = (args): JSX.Element => { + const [currentFactorMultiplication, setCurrentFactorMultiplication] = + useState(2.5); + const [countedCircles, setCountedCircles] = useState(); + + const getRandomInt = ({ min, max }: Random): number => { + return Math.floor(Math.random() * (max - min) + min); + }; + + const handleClick = (): void => { + setCurrentFactorMultiplication(getRandomInt({ max: 5, min: 1 })); + }; + + const getCountDisplayedCircles = (value: number): void => { + setCountedCircles(value); + }; + + return ( + <> + + + + + + + ); +}; + +const ExternalComponent = (tooltipData): JSX.Element => { + const { hideTooltip, data } = tooltipData; + const { format } = useLocaleDateTimeFormat(); + + return ( + <> + External component +
+
+ {format({ + date: data, + formatString: dateTimeFormat + })} +
+
+ + + ); +}; + +const LineChartAndCLS = (args): JSX.Element => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + setTimeout(() => { + setLoading(false); + setData(dataLastDayThreshold as unknown as LineChartData); + }, 100000); + }, []); + + return ( + + ); +}; + +interface TimePeriodSwitchProps { + getDataSwitch: (value: boolean) => void; +} + +const TimePeriodSwitch = ({ + getDataSwitch +}: TimePeriodSwitchProps): JSX.Element => { + const [checked, setChecked] = useState(false); + + const handleChange = (event: React.ChangeEvent): void => { + setChecked(event.target.checked); + }; + + useEffect(() => { + getDataSwitch?.(checked); + }, [checked]); + + return ( + + ); +}; + +const LineChartAndTimePeriod = (args): JSX.Element => { + const [currentData, setCurrentData] = useState(); + const [start, setStart] = useState(); + const [end, setEnd] = useState(); + const [displayAnnotation, setDisplayAnnotation] = useState(); + const [adjustedTimePeriodInterval, setAdjustedTimePeriodInterval] = + useState(); + + const getParameters = (interval): void => { + setStart(interval.start); + setEnd(interval.end); + }; + + useEffect(() => { + if (!start || !end) { + return; + } + if (start.includes(lastDayForwardDate)) { + setCurrentData(dataLastDayForword as unknown as LineChartData); + + return; + } + + if (start.includes(`${defaultStart.split('T')[0]}`)) { + setCurrentData(dataLastDayThreshold as unknown as LineChartData); + + return; + } + if (start.includes(defaultLast7days.split('T')[0])) { + setCurrentData(dataLastWeek as unknown as LineChartData); + + return; + } + if (start.includes(defaultLastMonth.split('T')[0])) { + setCurrentData(dataLastMonth as unknown as LineChartData); + + return; + } + if (start.includes(zoomPreviewDate)) { + setCurrentData(dataZoomPreview as unknown as LineChartData); + } + }, [start, end, adjustedTimePeriodInterval]); + + const getInterval = (interval: Interval): void => { + setAdjustedTimePeriodInterval(interval); + }; + + const getDataSwitch = (value): void => { + setDisplayAnnotation(value); + }; + + const annotationEventData = displayAnnotation && { + data: annotationData.result + }; + + return ( + <> + + } + /> + ( + + ) + }} + zoomPreview={{ enable: true, getInterval }} + /> + + ); +}; + +const LineChartAndExclusionPeriod = (args): JSX.Element => { + const [dataExclusionPeriods, setDataExclusionPeriods] = useState< + Array + >([exclusionPeriodFirstPeriod as unknown as LineChartData]); + + const handleClick = (data): void => { + setDataExclusionPeriods([...dataExclusionPeriods, data]); + }; + + return ( + <> +
Add exclusion periods:
+ + + + + + + ); +}; + +const Template: Story = { + render: (args) => ( + + ) +}; + +const WithTimePeriod = { + render: (args): JSX.Element => +}; + +const LineChartWithExclusionPeriod: Story = { + render: (args) => +}; + +const LineChartWithEnvelopVariation: Story = { + render: (args) => +}; + +const LineChartWithCLS: Story = { + render: (args) => +}; + +export const LineChart: Story = { + ...Template, + argTypes, + args: argumentsData +}; + +export const LineChartWithStepCurve: Story = { + ...Template, + argTypes, + args: { + ...argumentsData, + lineStyle: { + curve: 'step' + } + } +}; + +export const LineChartWithTimePeriod: Story = { + ...WithTimePeriod, + args: { + end: defaultEnd, + height: 500, + start: defaultStart + }, + parameters: { + chromatic: { disableSnapshot: true } + } +}; + +export const WithEnvelopVariation: Story = { + ...LineChartWithEnvelopVariation, + args: { + end: defaultEnd, + height: 500, + start: defaultStart + } +}; + +export const withExclusionPeriods: Story = { + ...LineChartWithExclusionPeriod, + args: { + end: defaultEnd, + height: 500, + start: defaultStart + } +}; + +export const withCLS: Story = { + ...LineChartWithCLS, + args: { + end: defaultEnd, + height: 500, + start: defaultStart + } +}; + +export const withThresholds: Story = { + argTypes, + args: { + ...argumentsData, + thresholds: { + critical: [ + { + label: 'critical', + value: 350 + } + ], + enabled: true, + warning: [ + { + label: 'warning', + value: 300 + } + ] + } + }, + render: (args) => ( + + ) +}; + +export const withThresholdsAndUnit: Story = { + argTypes, + args: { + ...argumentsData, + thresholdUnit: '%', + thresholds: { + critical: [ + { + label: 'critical', + value: 79 + } + ], + enabled: true, + warning: [ + { + label: 'warning', + value: 65 + } + ] + } + }, + render: (args) => ( + + ) +}; + +export const thresholdsRange: Story = { + argTypes, + args: { + ...argumentsData, + thresholdUnit: '%', + thresholds: { + critical: [ + { + label: 'critical 1', + value: 60 + }, + { + label: 'critical 2', + value: 79 + } + ], + enabled: true, + warning: [ + { + label: 'warning 1', + value: 20 + }, + { + label: 'warning 2', + value: 30 + } + ] + } + }, + render: (args) => ( + + ) +}; + +export const LineChartWithSameColorCurves: Story = { + ...Template, + argTypes, + args: argumentsData, + render: (args) => ( + + ) +}; + +export const zeroCentered: Story = { + argTypes, + args: { + ...argumentsData, + axis: { + isCenteredZero: true + } + }, + render: (args) => ( + + ) +}; + +export const customLines: Story = { + argTypes, + args: { + ...argumentsData, + lineStyle: { + areaTransparency: 10, + dashLength: 10, + dashOffset: 10, + lineWidth: 3, + showArea: true, + showPoints: true + } + }, + render: (args) => ( + + ) +}; + +export const customLinesAndBars: Story = { + argTypes, + args: { + ...argumentsData, + barStyle: { + opacity: 0.5, + radius: 0.5 + }, + lineStyle: { + curve: 'natural', + lineWidth: 2, + showPoints: true + } + }, + render: (args) => ( + + ) +}; + +export const multipleUnits: Story = { + argTypes, + args: argumentsData, + render: (args) => ( + + ) +}; + +export const linesAndBars: Story = { + argTypes, + args: { + ...argumentsData, + lineStyle: { + curve: 'natural', + lineWidth: 2, + showPoints: true + } + }, + render: (args) => ( + + ) +}; + +export const linesAndBarsStacked: Story = { + argTypes, + args: { + ...argumentsData, + lineStyle: { + curve: 'natural', + lineWidth: 2, + showPoints: false + } + }, + render: (args) => ( + + ) +}; + +export const linesAndBarsMixed: Story = { + argTypes, + args: { + ...argumentsData, + lineStyle: { + curve: 'natural', + lineWidth: 2, + showPoints: false + } + }, + render: (args) => ( + + ) +}; + +export const linesAndBarsCenteredZero: Story = { + argTypes, + args: { + ...argumentsData, + axis: { + isCenteredZero: true + }, + lineStyle: { + curve: 'natural', + lineWidth: 2, + showPoints: true + } + }, + render: (args) => ( + + ) +}; + +export const linesAndBarsStackedCenteredZero: Story = { + argTypes, + args: { + ...argumentsData, + axis: { + isCenteredZero: true + }, + lineStyle: { + curve: 'natural', + lineWidth: 2, + showPoints: false + } + }, + render: (args) => ( + + ) +}; + +export const linesAndBarsMixedCenteredZero: Story = { + argTypes, + args: { + ...argumentsData, + axis: { + isCenteredZero: true + }, + lineStyle: { + curve: 'natural', + lineWidth: 2, + showPoints: false + } + }, + render: (args) => ( + + ) +}; +const CustomYUnits = (props): JSX.Element => { + const [leftUnit, setLeftUnit] = useState('b'); + const [rightUnit, setRightUnit] = useState('ms'); + + return ( + + ); +}; + +export const customYUnits: Story = { + argTypes, + args: argumentsData, + render: (args) => +}; diff --git a/centreon/packages/ui/src/Graph/Chart/Chart.styles.ts b/centreon/packages/ui/src/Graph/Chart/Chart.styles.ts new file mode 100644 index 0000000000..83ce44de12 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/Chart.styles.ts @@ -0,0 +1,5 @@ +import { makeStyles } from 'tss-react/mui'; + +export const useChartStyles = makeStyles()({ + tooltipChildren: { height: '100%', width: '100%' } +}); diff --git a/centreon/packages/ui/src/Graph/Chart/Chart.tsx b/centreon/packages/ui/src/Graph/Chart/Chart.tsx new file mode 100644 index 0000000000..eb77891938 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/Chart.tsx @@ -0,0 +1,337 @@ +import { MutableRefObject, useEffect, useMemo, useRef, useState } from 'react'; + +import { useAtom } from 'jotai'; +import { equals, flatten, isNil, pluck, reject } from 'ramda'; + +import { ClickAwayListener, Skeleton } from '@mui/material'; + +import { useDeepCompare } from '../../utils'; +import BarGroup from '../BarChart/BarGroup'; +import BaseChart from '../common/BaseChart/BaseChart'; +import ChartSvgWrapper from '../common/BaseChart/ChartSvgWrapper'; +import { useComputeBaseChartDimensions } from '../common/BaseChart/useComputeBaseChartDimensions'; +import Thresholds from '../common/Thresholds/Thresholds'; +import { Thresholds as ThresholdsModel } from '../common/models'; +import { + getUnits, + getXScale, + getXScaleBand, + getYScalePerUnit +} from '../common/timeSeries'; +import { Line } from '../common/timeSeries/models'; + +import Lines from './BasicComponents/Lines'; +import { + canDisplayThreshold, + findLineOfOriginMetricThreshold, + lowerLineName, + upperLineName +} from './BasicComponents/Lines/Threshold/models'; +import { useChartStyles } from './Chart.styles'; +import InteractionWithGraph from './InteractiveComponents'; +import GraphValueTooltip from './InteractiveComponents/GraphValueTooltip/GraphValueTooltip'; +import GraphTooltip from './InteractiveComponents/Tooltip'; +import useGraphTooltip from './InteractiveComponents/Tooltip/useGraphTooltip'; +import { margin } from './common'; +import { thresholdTooltipAtom } from './graphAtoms'; +import { Data, GlobalAreaLines, GraphInterval, LineChartProps } from './models'; +import { useIntersection } from './useChartIntersection'; + +interface Props extends LineChartProps { + graphData: Data; + graphInterval: GraphInterval; + graphRef: MutableRefObject; + limitLegend?: false | number; + shapeLines?: GlobalAreaLines; + thresholdUnit?: string; + thresholds?: ThresholdsModel; +} + +const filterLines = (lines: Array, displayThreshold): Array => { + if (!displayThreshold) { + return lines; + } + const lineOriginMetric = findLineOfOriginMetricThreshold(lines); + + const findLinesUpperLower = lines.map((line) => + equals(line.name, lowerLineName) || equals(line.name, upperLineName) + ? line + : null + ); + + const linesUpperLower = reject((element) => !element, findLinesUpperLower); + + return [...lineOriginMetric, ...linesUpperLower] as Array; +}; + +const Chart = ({ + graphData, + height = 500, + width, + shapeLines, + axis, + displayAnchor, + zoomPreview, + graphInterval, + timeShiftZones, + annotationEvent, + tooltip, + legend, + graphRef, + header, + lineStyle, + barStyle = { + opacity: 1, + radius: 0.2 + }, + thresholds, + thresholdUnit, + limitLegend +}: Props): JSX.Element => { + const { classes } = useChartStyles(); + + const { title, timeSeries, baseAxis, lines } = graphData; + + const [linesGraph, setLinesGraph] = useState>( + filterLines(lines, canDisplayThreshold(shapeLines?.areaThresholdLines)) + ); + const graphSvgRef = useRef(null); + + const [thresholdTooltip, setThresholdTooltip] = useAtom(thresholdTooltipAtom); + + const { isInViewport } = useIntersection({ element: graphRef?.current }); + + const thresholdValues = flatten([ + pluck('value', thresholds?.warning || []), + pluck('value', thresholds?.critical || []) + ]); + + const displayedLines = useMemo( + () => linesGraph.filter(({ display }) => display), + [linesGraph] + ); + const [firstUnit, secondUnit] = useMemo( + () => getUnits(displayedLines), + [displayedLines] + ); + + const { legendRef, graphWidth, graphHeight } = useComputeBaseChartDimensions({ + hasSecondUnit: Boolean(secondUnit), + height, + legendDisplay: legend?.display, + legendHeight: legend?.height, + legendPlacement: legend?.placement, + width + }); + + const xScale = useMemo( + () => + getXScale({ + dataTime: timeSeries, + valueWidth: graphWidth + }), + [timeSeries, graphWidth] + ); + + const xScaleBand = useMemo( + () => + getXScaleBand({ + dataTime: timeSeries, + valueWidth: graphWidth + }), + [timeSeries, graphWidth, graphHeight] + ); + + const yScalesPerUnit = useMemo( + () => + getYScalePerUnit({ + dataLines: linesGraph, + dataTimeSeries: timeSeries, + isCenteredZero: axis?.isCenteredZero, + scale: axis?.scale, + scaleLogarithmicBase: axis?.scaleLogarithmicBase, + thresholdUnit, + thresholds: (thresholds?.enabled && thresholdValues) || [], + valueGraphHeight: graphHeight - margin.bottom + }), + [ + linesGraph, + timeSeries, + graphHeight, + thresholdValues, + thresholds?.enabled, + axis?.isCenteredZero, + axis?.scale, + axis?.scaleLogarithmicBase + ] + ); + + const leftScale = yScalesPerUnit[axis?.axisYLeft?.unit ?? firstUnit]; + const rightScale = yScalesPerUnit[axis?.axisYRight?.unit ?? secondUnit]; + + const linesDisplayedAsLine = useMemo( + () => + displayedLines.filter( + ({ displayAs }) => isNil(displayAs) || equals(displayAs, 'line') + ), + [displayedLines] + ); + + const linesDisplayedAsBar = useMemo( + () => displayedLines.filter(({ displayAs }) => equals(displayAs, 'bar')), + [displayedLines] + ); + + const allUnits = getUnits(linesGraph); + + useEffect( + () => { + setLinesGraph( + filterLines(lines, canDisplayThreshold(shapeLines?.areaThresholdLines)) + ); + }, + useDeepCompare([lines]) + ); + + const graphTooltipData = useGraphTooltip({ + graphWidth, + timeSeries, + xScale + }); + + const displayLegend = legend?.display ?? true; + const displayTooltip = !isNil(tooltip?.renderComponent); + + const showGridLines = useMemo( + () => isNil(axis?.showGridLines) || axis?.showGridLines, + [axis?.showGridLines] + ); + + if (!isInViewport) { + return ( + + ); + } + + return ( + + <> + + +
+ + <> + + + + {thresholds?.enabled && ( + setThresholdTooltip(null)} + showTooltip={({ tooltipData: thresholdLabel }) => + setThresholdTooltip({ + thresholdLabel + }) + } + thresholdUnit={thresholdUnit} + thresholds={thresholds as ThresholdsModel} + width={graphWidth} + yScalesPerUnit={yScalesPerUnit} + /> + )} + + +
+
+
+ {displayTooltip && } + +
+ ); +}; + +export default Chart; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/GuidingLines.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/GuidingLines.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/GuidingLines.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/GuidingLines.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx similarity index 93% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx index a7e596a3cc..ca230275d1 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx @@ -4,8 +4,8 @@ import { isNil, prop } from 'ramda'; import { bisectDate, getDates } from '../../../common/timeSeries'; import { TimeValue } from '../../../common/timeSeries/models'; -import useTickGraph from './useTickGraph'; import { GetYAnchorPoint } from './models'; +import useTickGraph from './useTickGraph'; import AnchorPoint from '.'; @@ -22,10 +22,14 @@ export const getYAnchorPoint = ({ timeSeries, yScale, metric_id -}: GetYAnchorPoint): number => { +}: GetYAnchorPoint): number | null => { const index = bisectDate(getDates(timeSeries), timeTick); const timeValue = timeSeries[index]; + if (isNil(timeValue)) { + return null; + } + return yScale(prop(metric_id, timeValue) as number); }; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx similarity index 92% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx index 4729cabc83..fa7918c61f 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx @@ -34,9 +34,14 @@ export const getYAnchorPoint = ({ timeTick, stackValues, yScale -}: GetYAnchorPoint): number => { +}: GetYAnchorPoint): number | null => { const index = bisectDate(getStackedDates(stackValues), timeTick); const timeValue = stackValues[index]; + const { key } = stackValues; + + if (isNil(timeValue.data[key])) { + return null; + } return yScale(timeValue[1] as number); }; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/index.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/index.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/index.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/index.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/models.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/models.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/models.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/models.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/useTickGraph.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts similarity index 97% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/useTickGraph.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts index c4e4f2ecf0..c35467d2f1 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/AnchorPoint/useTickGraph.ts +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts @@ -3,10 +3,10 @@ import { useEffect, useState } from 'react'; import { ScaleLinear } from 'd3-scale'; import { useAtomValue } from 'jotai'; -import useAxisY from '../../BasicComponents/Axes/useAxisY'; -import { margin } from '../../common'; +import useAxisY from '../../../common/Axes/useAxisY'; import { getTimeValue } from '../../../common/timeSeries'; import { Line, TimeValue } from '../../../common/timeSeries/models'; +import { margin } from '../../common'; import { mousePositionAtom } from '../interactionWithGraphAtoms'; interface AnchorPointResult { diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/Area.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/Area.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/Area.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/Area.tsx index 19ac579a98..785232d320 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/Area.tsx +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/Area.tsx @@ -1,7 +1,7 @@ import { Shape } from '@visx/visx'; import { ScaleTime } from 'd3-scale'; -import { max, pick, prop } from 'ramda'; import { useAtom, useAtomValue } from 'jotai'; +import { max, pick, prop } from 'ramda'; import { makeStyles } from 'tss-react/mui'; import { useLocaleDateTimeFormat, useMemoComponent } from '@centreon/ui'; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/Line.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/Line.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/Line.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/Line.tsx index 59629717d9..a0f89766d5 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/Line.tsx +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/Line.tsx @@ -1,7 +1,7 @@ import { Shape } from '@visx/visx'; import { ScaleTime } from 'd3-scale'; -import { pick } from 'ramda'; import { useAtomValue } from 'jotai'; +import { pick } from 'ramda'; import { makeStyles } from 'tss-react/mui'; import { useLocaleDateTimeFormat, useMemoComponent } from '@centreon/ui'; diff --git a/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/index.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/index.tsx new file mode 100644 index 0000000000..48c88572df --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/index.tsx @@ -0,0 +1,81 @@ +import { useSetAtom } from 'jotai'; +import { useTranslation } from 'react-i18next'; +import { makeStyles } from 'tss-react/mui'; + +import { Paper, Tooltip, Typography } from '@mui/material'; + +import { truncate } from '../../../helpers'; +import { labelBy } from '../../../translatedLabels'; +import { annotationHoveredAtom } from '../annotationsAtoms'; +import { TimelineEvent } from '../models'; + +const yMargin = -32; +const iconSize = 20; + +const useStyles = makeStyles()((theme) => ({ + tooltip: { + backgroundColor: 'transparent' + }, + tooltipContent: { + padding: theme.spacing(1) + } +})); + +export interface Props { + annotationHoveredId: number; + event: TimelineEvent; + header: string; + icon: JSX.Element; + marker: JSX.Element; + xIcon: number; +} + +const Annotation = ({ + icon, + header, + event, + xIcon, + marker, + annotationHoveredId +}: Props): JSX.Element => { + const { classes } = useStyles(); + const { t } = useTranslation(); + + const setAnnotationHovered = useSetAtom(annotationHoveredAtom); + + const content = `${truncate(event.content)} (${t(labelBy)} ${ + event.contact?.name + })`; + + return ( + + + {header} + {content} + + } + > + + setAnnotationHovered(() => ({ annotationHoveredId, event })) + } + onMouseLeave={(): void => setAnnotationHovered(() => undefined)} + > + + {icon} + + + {marker} + + ); +}; + +export default Annotation; +export { yMargin, iconSize }; diff --git a/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Area/Downtime.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Area/Downtime.tsx new file mode 100644 index 0000000000..53de30d729 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Area/Downtime.tsx @@ -0,0 +1,27 @@ +import { useTranslation } from 'react-i18next'; + +import { useTheme } from '@mui/material'; + +import { DowntimeIcon } from '../../../../../Icon'; +import { labelDowntime } from '../../../translatedLabels'; +import EventAnnotations from '../EventAnnotations'; +import { Args } from '../models'; + +const DowntimeAnnotations = (props: Args): JSX.Element => { + const { t } = useTranslation(); + const theme = useTheme(); + + const color = theme.palette.action.inDowntime; + + return ( + + ); +}; + +export default DowntimeAnnotations; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/EventAnnotations.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/EventAnnotations.tsx similarity index 96% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/EventAnnotations.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/EventAnnotations.tsx index 9cc5ba3bf2..e9ba4754ce 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/EventAnnotations.tsx +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/EventAnnotations.tsx @@ -1,9 +1,9 @@ -import { filter, propEq, isNil } from 'ramda'; import { ScaleTime } from 'd3-scale'; +import { filter, isNil, propEq } from 'ramda'; -import { TimelineEvent } from './models'; -import LineAnnotation from './Annotation/Line'; import AreaAnnotation from './Annotation/Area'; +import LineAnnotation from './Annotation/Line'; +import { TimelineEvent } from './models'; interface Props { Icon: (props) => JSX.Element | null; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Line/Acknowledgement.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Line/Acknowledgement.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Line/Acknowledgement.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Line/Acknowledgement.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Line/Comments.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Line/Comments.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Line/Comments.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Line/Comments.tsx index 15588c803f..d76151cd99 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Line/Comments.tsx +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/Line/Comments.tsx @@ -1,7 +1,7 @@ import { useTranslation } from 'react-i18next'; -import { useTheme } from '@mui/material'; import IconComment from '@mui/icons-material/Comment'; +import { useTheme } from '@mui/material'; import { labelComment } from '../../../translatedLabels'; import EventAnnotations from '../EventAnnotations'; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/annotationsAtoms.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/annotationsAtoms.ts similarity index 99% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/annotationsAtoms.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/annotationsAtoms.ts index 5d1f2946bf..98b43d3bfd 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/annotationsAtoms.ts +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/annotationsAtoms.ts @@ -1,6 +1,9 @@ import { ScaleTime } from 'd3-scale'; import { atom } from 'jotai'; import { + Pred, + T, + __, always, both, cond, @@ -14,10 +17,7 @@ import { lte, not, or, - pipe, - Pred, - T, - __ + pipe } from 'ramda'; import { alpha } from '@mui/material'; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/index.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/index.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/index.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/index.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/models.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/models.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/models.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/models.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/useAnnotation.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/useAnnotation.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/useAnnotation.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Annotations/useAnnotation.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Bar.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Bar.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Bar.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Bar.tsx index 89b881c612..b4fc3a78e6 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Bar.tsx +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Bar.tsx @@ -1,5 +1,5 @@ -import { Shape } from '@visx/visx'; import { AddSVGProps } from '@visx/shape/lib/types'; +import { Shape } from '@visx/visx'; interface BarProps { className?: string; diff --git a/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/GraphValueTooltip.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/GraphValueTooltip.tsx new file mode 100644 index 0000000000..2c84f106fa --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/GraphValueTooltip.tsx @@ -0,0 +1,61 @@ +import { equals } from 'ramda'; + +import { Typography } from '@mui/material'; + +import { Tooltip as MuiTooltip } from '../../../../components/Tooltip'; +import { useTooltipStyles } from '../../../common/useTooltipStyles'; +import { ThresholdTooltip, Tooltip } from '../../models'; + +import GraphValueTooltipContent from './GraphValueTooltipContent'; + +interface Props { + baseAxis: number; + children: JSX.Element; + thresholdTooltip: ThresholdTooltip | null; + tooltip?: Tooltip; +} + +const GraphValueTooltip = ({ + children, + tooltip, + baseAxis, + thresholdTooltip +}: Props): JSX.Element => { + const { classes, cx } = useTooltipStyles(); + + if (thresholdTooltip) { + return ( + {thresholdTooltip?.thresholdLabel}} + > + {children} + + ); + } + + return ( + + ) + } + > + {children} + + ); +}; + +export default GraphValueTooltip; diff --git a/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/GraphValueTooltipContent.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/GraphValueTooltipContent.tsx new file mode 100644 index 0000000000..128a77e89e --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/GraphValueTooltipContent.tsx @@ -0,0 +1,74 @@ +import { useAtomValue } from 'jotai'; +import { equals, isNil } from 'ramda'; + +import { Box, Typography } from '@mui/material'; + +import { formatMetricValueWithUnit } from '../../../common/timeSeries'; +import { Tooltip } from '../../models'; +import { mousePositionAtom } from '../interactionWithGraphAtoms'; + +import { useGraphValueTooltip } from './useGraphValueTooltip'; +import { useGraphValueTooltipStyles } from './useGraphValueTooltipStyles'; + +interface Props extends Pick { + base: number; + isSingleMode: boolean; +} + +const GraphValueTooltipContent = ({ + base, + isSingleMode, + sortOrder +}: Props): JSX.Element | null => { + const { classes } = useGraphValueTooltipStyles(); + const mousePosition = useAtomValue(mousePositionAtom); + + const graphValue = useGraphValueTooltip({ isSingleMode, sortOrder }); + + if (isNil(graphValue) || isNil(mousePosition)) { + return null; + } + + return ( +
+ {graphValue.dateTime} +
+ {graphValue.metrics.map(({ unit, color, id, value, name }) => { + const isMetricHighlighted = equals( + id, + graphValue.highlightedMetricId + ); + + return ( +
+ + + {name} + + + {formatMetricValueWithUnit({ + base, + unit, + value + })} + +
+ ); + })} +
+
+ ); +}; + +export default GraphValueTooltipContent; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts similarity index 93% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts index d74443b869..7ad0fe89fe 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts @@ -1,5 +1,6 @@ import { useAtomValue } from 'jotai'; import { + T, always, cond, equals, @@ -10,9 +11,9 @@ import { sortBy } from 'ramda'; -import { graphTooltipDataAtom } from '../interactionWithGraphAtoms'; import { useLocaleDateTimeFormat } from '../../../../utils'; import { GraphTooltipData, Tooltip } from '../../models'; +import { graphTooltipDataAtom } from '../interactionWithGraphAtoms'; interface UseGraphValueTooltipState extends Omit { dateTime: string; @@ -29,7 +30,7 @@ export const useGraphValueTooltip = ({ const { toDate, toTime } = useLocaleDateTimeFormat(); const graphTooltipData = useAtomValue(graphTooltipDataAtom); - if (isNil(graphTooltipData)) { + if (isNil(graphTooltipData) || isNil(graphTooltipData.metrics)) { return null; } @@ -48,7 +49,8 @@ export const useGraphValueTooltip = ({ [ equals('descending'), always(reverse(sortBy(prop('value'), filteredMetrics))) - ] + ], + [T, always(filteredMetrics)] ])(sortOrder); return { diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltipStyles.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltipStyles.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltipStyles.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltipStyles.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/TimeShiftIcon.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/TimeShiftIcon.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/TimeShiftIcon.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/TimeShiftIcon.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/TimeShiftZone.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/TimeShiftZone.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/TimeShiftZone.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/TimeShiftZone.tsx diff --git a/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/index.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/index.tsx new file mode 100644 index 0000000000..ceec039449 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/index.tsx @@ -0,0 +1,84 @@ +import { useState } from 'react'; + +import { equals, isNil, negate } from 'ramda'; + +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; +import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos'; + +import { margin } from '../../common'; +import { GraphInterval, Interval } from '../../models'; + +import TimeShiftIcon, { timeShiftIconSize } from './TimeShiftIcon'; +import TimeShiftZone from './TimeShiftZone'; +import { TimeShiftDirection } from './models'; + +interface Props { + getInterval?: (args: Interval) => void; + graphHeight: number; + graphInterval: GraphInterval; + graphWidth: number; +} + +const TimeShiftZones = ({ + graphHeight, + graphWidth, + getInterval, + graphInterval +}: Props): JSX.Element => { + const [directionHovered, setDirectionHovered] = + useState(null); + + const marginLeft = margin.left; + + const isBackward = equals(directionHovered, TimeShiftDirection.backward); + const displayIcon = !isNil(directionHovered); + const propsIcon = { color: 'primary' as const }; + + const xIcon = isBackward + ? negate(marginLeft) + : graphWidth + timeShiftIconSize / 2; + + const yIcon = graphHeight / 2 - timeShiftIconSize / 2; + + const Icon = isBackward ? ( + + ) : ( + + ); + const ariaLabelIcon = isBackward ? 'labelBackward' : 'labelForward'; + + const commonData = { + getInterval, + graphHeight, + graphInterval, + graphWidth + }; + + return ( + <> + + + {displayIcon && ( + + )} + + ); +}; + +export default TimeShiftZones; diff --git a/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/models.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/models.ts new file mode 100644 index 0000000000..7c75ac2828 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/models.ts @@ -0,0 +1,12 @@ +import { GraphInterval, GraphIntervalProperty } from '../../models'; + +export enum TimeShiftDirection { + backward = 0, + forward = 1 +} + +export interface GetShiftDate { + property: GraphIntervalProperty; + timePeriod: GraphInterval; + timeShiftDirection: TimeShiftDirection; +} diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/useTimeShiftZones.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/useTimeShiftZones.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/useTimeShiftZones.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/TimeShiftZones/useTimeShiftZones.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Tooltip/index.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Tooltip/index.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Tooltip/index.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Tooltip/index.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Tooltip/models.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Tooltip/models.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Tooltip/models.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Tooltip/models.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Tooltip/useGraphTooltip.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Tooltip/useGraphTooltip.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Tooltip/useGraphTooltip.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Tooltip/useGraphTooltip.ts index e4224ba058..67894615f5 100644 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Tooltip/useGraphTooltip.ts +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/Tooltip/useGraphTooltip.ts @@ -4,8 +4,8 @@ import { Event, Tooltip } from '@visx/visx'; import { ScaleLinear } from 'd3-scale'; import { useAtomValue } from 'jotai'; -import { getDate } from '../../helpers/index'; import { TimeValue } from '../../../common/timeSeries/models'; +import { getDate } from '../../helpers/index'; import { applyingZoomAtomAtom } from '../ZoomPreview/zoomPreviewAtoms'; import { eventMouseUpAtom } from '../interactionWithGraphAtoms'; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/ZoomPreview/index.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/ZoomPreview/index.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/ZoomPreview/index.tsx rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/ZoomPreview/index.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/ZoomPreview/models.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/ZoomPreview/models.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/ZoomPreview/models.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/ZoomPreview/models.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/ZoomPreview/useZoomPreview.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/ZoomPreview/useZoomPreview.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/ZoomPreview/useZoomPreview.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/ZoomPreview/useZoomPreview.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/ZoomPreview/zoomPreviewAtoms.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/ZoomPreview/zoomPreviewAtoms.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/ZoomPreview/zoomPreviewAtoms.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/ZoomPreview/zoomPreviewAtoms.ts diff --git a/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/index.tsx b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/index.tsx new file mode 100644 index 0000000000..a70ef93eac --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/index.tsx @@ -0,0 +1,279 @@ +import { MutableRefObject } from 'react'; + +import { Event } from '@visx/visx'; +import { ScaleLinear, ScaleTime } from 'd3-scale'; +import { useSetAtom } from 'jotai'; +import { + all, + equals, + find, + isEmpty, + isNil, + keys, + map, + negate, + pick, + pipe, + pluck, + reduce, + toPairs, + values +} from 'ramda'; +import { makeStyles } from 'tss-react/mui'; + +import { + formatMetricName, + getLineForMetric, + getLinesForMetrics, + getTimeValue, + getYScale +} from '../../common/timeSeries'; +import { Line, TimeValue } from '../../common/timeSeries/models'; +import { margin } from '../common'; +import { + AnnotationEvent, + GraphInterval, + InteractedZone, + InteractedZone as ZoomPreviewModel +} from '../models'; + +import Annotations from './Annotations'; +import { TimelineEvent } from './Annotations/models'; +import Bar from './Bar'; +import TimeShiftZones from './TimeShiftZones'; +import ZoomPreview from './ZoomPreview'; +import { + MousePosition, + changeMousePositionDerivedAtom, + eventMouseDownAtom, + eventMouseLeaveAtom, + eventMouseUpAtom, + graphTooltipDataAtom +} from './interactionWithGraphAtoms'; + +const useStyles = makeStyles()(() => ({ + overlay: { + cursor: 'crosshair' + } +})); + +interface CommonData { + graphHeight: number; + graphSvgRef: MutableRefObject; + graphWidth: number; + lines; + timeSeries: Array; + xScale: ScaleTime; + yScalesPerUnit: Record>; +} + +interface TimeShiftZonesData extends InteractedZone { + graphInterval: GraphInterval; +} + +interface Props { + annotationData?: AnnotationEvent; + commonData: CommonData; + timeShiftZonesData: TimeShiftZonesData; + zoomData: ZoomPreviewModel; +} + +const InteractionWithGraph = ({ + zoomData, + commonData, + annotationData, + timeShiftZonesData +}: Props): JSX.Element => { + const { classes } = useStyles(); + + const setEventMouseDown = useSetAtom(eventMouseDownAtom); + const setEventMouseUp = useSetAtom(eventMouseUpAtom); + const setEventMouseLeave = useSetAtom(eventMouseLeaveAtom); + const changeMousePosition = useSetAtom(changeMousePositionDerivedAtom); + const setGraphTooltipData = useSetAtom(graphTooltipDataAtom); + + const { + graphHeight, + graphWidth, + graphSvgRef, + xScale, + timeSeries, + lines, + yScalesPerUnit + } = commonData; + + const displayZoomPreview = zoomData?.enable ?? true; + + const displayEventAnnotations = + !isNil(annotationData?.data) && !isEmpty(annotationData?.data); + const displayTimeShiftZones = timeShiftZonesData?.enable ?? true; + + const mouseLeave = (event): void => { + setEventMouseLeave(event); + setEventMouseDown(null); + updateMousePosition(null); + setGraphTooltipData(null); + }; + + const mouseUp = (event): void => { + setEventMouseUp(event); + setEventMouseDown(null); + }; + + const mouseMove = (event): void => { + const mousePoint = Event.localPoint( + graphSvgRef?.current as SVGSVGElement, + event + ); + if (!mousePoint) { + return; + } + updateMousePosition([mousePoint.x, mousePoint.y]); + }; + + const mouseDown = (event): void => { + setEventMouseDown(event); + }; + + const updateMousePosition = (pointPosition: MousePosition): void => { + if (isNil(pointPosition)) { + changeMousePosition({ + position: null + }); + setGraphTooltipData(null); + + return; + } + const timeValue = getTimeValue({ + timeSeries, + x: pointPosition[0], + xScale + }); + + if (isNil(timeValue)) { + changeMousePosition({ + position: null + }); + setGraphTooltipData(null); + + return; + } + + const date = timeValue.timeTick; + const displayedMetricIds = pluck('metric_id', lines); + const filteredMetricsValue = pick(displayedMetricIds, timeValue); + const areAllValuesEmpty = pipe(values, all(isNil))(filteredMetricsValue); + + const linesData = getLinesForMetrics({ + lines, + metricIds: keys(filteredMetricsValue).map(Number) + }); + + if (areAllValuesEmpty) { + changeMousePosition({ position: pointPosition }); + setGraphTooltipData(null); + + return; + } + + const distanceWithPointPositionPerMetric = reduce( + (acc, [metricId, value]) => { + if (isNil(value)) { + return acc; + } + + const lineData = getLineForMetric({ + lines, + metric_id: Number(metricId) + }); + const yScale = getYScale({ + invert: (lineData as Line).invert, + unit: (lineData as Line).unit, + yScalesPerUnit + }); + + const y0 = yScale(value); + + const diffBetweenY0AndPointPosition = Math.abs( + y0 + margin.top - pointPosition[1] + ); + + return { + ...acc, + [metricId]: diffBetweenY0AndPointPosition + }; + }, + {}, + Object.entries(filteredMetricsValue) + ); + + const nearestY0 = Math.min(...values(distanceWithPointPositionPerMetric)); + + const nearestLine = pipe( + toPairs, + find(([, y0]) => equals(y0, nearestY0)) as () => [string, number] + )(distanceWithPointPositionPerMetric); + + changeMousePosition({ position: pointPosition }); + setGraphTooltipData({ + date, + highlightedMetricId: Number(nearestLine[0]), + metrics: map( + ({ metric_id, color, unit, legend, name, invert }) => ({ + color, + id: metric_id, + name: formatMetricName({ legend, name }), + unit, + value: invert + ? negate(timeValue?.[metric_id]) + : timeValue?.[metric_id] + }), + linesData + ).filter(({ value }) => !isNil(value)) + }); + }; + + return ( + + {displayZoomPreview && ( + + )} + {displayEventAnnotations && ( + } + graphHeight={graphHeight} + graphSvgRef={graphSvgRef} + graphWidth={graphWidth} + xScale={xScale} + /> + )} + {displayTimeShiftZones && ( + + )} + + + ); +}; + +export default InteractionWithGraph; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/interactionWithGraphAtoms.ts b/centreon/packages/ui/src/Graph/Chart/InteractiveComponents/interactionWithGraphAtoms.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/interactionWithGraphAtoms.ts rename to centreon/packages/ui/src/Graph/Chart/InteractiveComponents/interactionWithGraphAtoms.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/Legend/Legend.styles.ts b/centreon/packages/ui/src/Graph/Chart/Legend/Legend.styles.ts similarity index 96% rename from centreon/packages/ui/src/Graph/LineChart/Legend/Legend.styles.ts rename to centreon/packages/ui/src/Graph/Chart/Legend/Legend.styles.ts index ecd56836c2..862d5ee7f7 100644 --- a/centreon/packages/ui/src/Graph/LineChart/Legend/Legend.styles.ts +++ b/centreon/packages/ui/src/Graph/Chart/Legend/Legend.styles.ts @@ -16,7 +16,7 @@ export const useStyles = makeStyles()( color: theme.typography.body1.color }, item: { - width: 'max-content' + width: '100%' }, items: { '&[data-as-list="true"]': { @@ -93,10 +93,7 @@ export const useLegendHeaderStyles = makeStyles()( width: theme.spacing(1.5) }, legendName: { - maxWidth: '75%' - }, - legendNameSide: { - maxWidth: '95%' + width: '91%' }, markerAndLegendName: { alignItems: 'center', @@ -113,11 +110,15 @@ export const useLegendHeaderStyles = makeStyles()( text: { fontSize: '0.75rem', fontWeight: theme.typography.fontWeightMedium, - lineHeight: 1 + lineHeight: 1, + maxWidth: '250px' }, textList: { fontSize: '0.75rem', fontWeight: theme.typography.fontWeightMedium + }, + textListBottom: { + width: 'auto' } }) ); diff --git a/centreon/packages/ui/src/Graph/LineChart/Legend/LegendContent.tsx b/centreon/packages/ui/src/Graph/Chart/Legend/LegendContent.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/Legend/LegendContent.tsx rename to centreon/packages/ui/src/Graph/Chart/Legend/LegendContent.tsx diff --git a/centreon/packages/ui/src/Graph/LineChart/Legend/LegendHeader.tsx b/centreon/packages/ui/src/Graph/Chart/Legend/LegendHeader.tsx similarity index 85% rename from centreon/packages/ui/src/Graph/LineChart/Legend/LegendHeader.tsx rename to centreon/packages/ui/src/Graph/Chart/Legend/LegendHeader.tsx index 057f23f37f..3b23f2572a 100644 --- a/centreon/packages/ui/src/Graph/LineChart/Legend/LegendHeader.tsx +++ b/centreon/packages/ui/src/Graph/Chart/Legend/LegendHeader.tsx @@ -5,12 +5,12 @@ import { formatMetricName, formatMetricValue } from '../../..'; -import { Line } from '../../common/timeSeries/models'; import { Tooltip } from '../../../components'; +import { Line } from '../../common/timeSeries/models'; import { useLegendHeaderStyles } from './Legend.styles'; -import { LegendDisplayMode } from './models'; import LegendContent from './LegendContent'; +import { LegendDisplayMode } from './models'; interface Props { color: string; @@ -19,6 +19,7 @@ interface Props { isListMode: boolean; line: Line; minMaxAvg?; + unit: string; value?: string | null; } @@ -29,7 +30,8 @@ const LegendHeader = ({ value, minMaxAvg, isListMode, - isDisplayedOnSide + isDisplayedOnSide, + unit }: Props): JSX.Element => { const { classes, cx } = useLegendHeaderStyles({ color }); @@ -74,10 +76,11 @@ const LegendHeader = ({ className={cx(classes.icon, { [classes.disabled]: disabled })} /> {metricName} + + {unit} +
diff --git a/centreon/packages/ui/src/Graph/Chart/Legend/index.tsx b/centreon/packages/ui/src/Graph/Chart/Legend/index.tsx new file mode 100644 index 0000000000..6cb4b178b8 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/Legend/index.tsx @@ -0,0 +1,209 @@ +import { Dispatch, ReactNode, SetStateAction, useMemo } from 'react'; + +import { equals, lt, prop, slice, sortBy } from 'ramda'; + +import { Box, alpha, useTheme } from '@mui/material'; + +import { useMemoComponent } from '@centreon/ui'; + +import { formatMetricValue } from '../../common/timeSeries'; +import { Line } from '../../common/timeSeries/models'; +import { margin } from '../common'; +import { LegendModel } from '../models'; +import { labelAvg, labelMax, labelMin } from '../translatedLabels'; + +import { useStyles } from './Legend.styles'; +import LegendContent from './LegendContent'; +import LegendHeader from './LegendHeader'; +import { GetMetricValueProps, LegendDisplayMode } from './models'; +import useLegend from './useLegend'; + +interface Props extends Pick { + base: number; + height: number | null; + limitLegend?: false | number; + lines: Array; + renderExtraComponent?: ReactNode; + setLinesGraph: Dispatch | null>>; + shouldDisplayLegendInCompactMode: boolean; + toggable?: boolean; +} + +const MainLegend = ({ + lines, + base, + toggable = true, + limitLegend = false, + renderExtraComponent, + setLinesGraph, + shouldDisplayLegendInCompactMode, + placement, + height, + mode +}: Props): JSX.Element => { + const { classes, cx } = useStyles({ limitLegendRows: Boolean(limitLegend) }); + const theme = useTheme(); + + const { selectMetricLine, clearHighlight, highlightLine, toggleMetricLine } = + useLegend({ lines, setLinesGraph }); + + const sortedData = sortBy(prop('metric_id'), lines); + + const isListMode = useMemo(() => equals(mode, 'list'), [mode]); + + const displayedLines = limitLegend + ? slice(0, limitLegend, sortedData) + : sortedData; + + const getMetricValue = ({ value, unit }: GetMetricValueProps): string => + formatMetricValue({ + base, + unit, + value + }) || 'N/A'; + + const selectMetric = ({ event, metric_id }): void => { + if (!toggable) { + return; + } + + if (event.ctrlKey || event.metaKey) { + toggleMetricLine(metric_id); + + return; + } + + selectMetricLine(metric_id); + }; + + const itemMode = + !isListMode && shouldDisplayLegendInCompactMode + ? LegendDisplayMode.Compact + : LegendDisplayMode.Normal; + + const legendMaxHeight = useMemo(() => { + if (!isListMode || !equals(placement, 'bottom')) { + return 'none'; + } + + if (lt(height || 0, 220)) { + return 40; + } + + return 90; + }, [height, isListMode, placement]); + + const overflow = equals(legendMaxHeight, 'none') ? 'hidden' : 'auto'; + + return ( +
+
+ {displayedLines.map((line) => { + const { color, display, highlight, metric_id, unit } = line; + + const markerColor = display + ? color + : alpha(theme.palette.text.disabled, 0.2); + + const minMaxAvg = [ + { + label: labelMin, + value: line.minimum_value + }, + { + label: labelMax, + value: line.maximum_value + }, + { + label: labelAvg, + value: line.average_value + } + ]; + + return ( + selectMetric({ event, metric_id })} + onMouseEnter={(): void => highlightLine(metric_id)} + onMouseLeave={(): void => clearHighlight()} + > + + {!shouldDisplayLegendInCompactMode && !isListMode && ( +
+
+ {minMaxAvg.map(({ label, value }) => ( + + ))} +
+
+ )} +
+ ); + })} +
+ {renderExtraComponent} +
+ ); +}; + +const Legend = (props: Props): JSX.Element => { + const { + toggable, + limitLegend, + lines, + base, + shouldDisplayLegendInCompactMode, + placement, + height, + mode + } = props; + + return useMemoComponent({ + Component: , + memoProps: [ + lines, + base, + toggable, + limitLegend, + shouldDisplayLegendInCompactMode, + placement, + height, + mode + ] + }); +}; + +export default Legend; diff --git a/centreon/packages/ui/src/Graph/LineChart/Legend/models.ts b/centreon/packages/ui/src/Graph/Chart/Legend/models.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/Legend/models.ts rename to centreon/packages/ui/src/Graph/Chart/Legend/models.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/Legend/useLegend.ts b/centreon/packages/ui/src/Graph/Chart/Legend/useLegend.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/Legend/useLegend.ts rename to centreon/packages/ui/src/Graph/Chart/Legend/useLegend.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/LoadingSkeleton.tsx b/centreon/packages/ui/src/Graph/Chart/LoadingSkeleton.tsx similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/LoadingSkeleton.tsx rename to centreon/packages/ui/src/Graph/Chart/LoadingSkeleton.tsx diff --git a/centreon/packages/ui/src/Graph/Chart/common/index.ts b/centreon/packages/ui/src/Graph/Chart/common/index.ts new file mode 100644 index 0000000000..40aa7ccf12 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/common/index.ts @@ -0,0 +1,52 @@ +import { always, cond, equals, isNil } from 'ramda'; + +import { alpha } from '@mui/material'; +import { curveCatmullRom, curveLinear, curveStep } from '@visx/curve'; + +const commonTickLabelProps = { + fontFamily: 'Roboto, sans-serif', + fontSize: 10, + textAnchor: 'middle' +}; + +const margin = { bottom: 30, left: 50, right: 50, top: 30 }; + +interface FillColor { + areaColor: string; + transparency: number; +} + +const getFillColor = ({ + transparency, + areaColor +}: FillColor): string | undefined => { + return !isNil(transparency) + ? alpha(areaColor, 1 - transparency * 0.01) + : undefined; +}; + +const dateFormat = 'L'; +const timeFormat = 'LT'; +const dateTimeFormat = `${dateFormat} ${timeFormat}`; +const maxLinesDisplayedLegend = 11; + +const getCurveFactory = ( + curve: 'linear' | 'step' | 'natural' +): typeof curveLinear => { + return cond([ + [equals('linear'), always(curveLinear)], + [equals('step'), always(curveStep)], + [equals('natural'), always(curveCatmullRom)] + ])(curve); +}; + +export { + commonTickLabelProps, + margin, + getFillColor, + dateFormat, + timeFormat, + dateTimeFormat, + maxLinesDisplayedLegend, + getCurveFactory +}; diff --git a/centreon/packages/ui/src/Graph/Chart/graphAtoms.ts b/centreon/packages/ui/src/Graph/Chart/graphAtoms.ts new file mode 100644 index 0000000000..77e07700a6 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/graphAtoms.ts @@ -0,0 +1,6 @@ +import { atom } from 'jotai'; + +import { ThresholdTooltip } from './models'; + +export const timeTickGraphAtom = atom(null); +export const thresholdTooltipAtom = atom(null); diff --git a/centreon/packages/ui/src/Graph/LineChart/helpers/doc.ts b/centreon/packages/ui/src/Graph/Chart/helpers/doc.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/helpers/doc.ts rename to centreon/packages/ui/src/Graph/Chart/helpers/doc.ts diff --git a/centreon/packages/ui/src/Graph/Chart/helpers/index.ts b/centreon/packages/ui/src/Graph/Chart/helpers/index.ts new file mode 100644 index 0000000000..eadeee5f1e --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/helpers/index.ts @@ -0,0 +1,66 @@ +import dayjs from 'dayjs'; +import durationPlugin from 'dayjs/plugin/duration'; +import { gt, gte, isEmpty, isNil, prop, propEq, reject, sortBy } from 'ramda'; + +import { LineChartData } from '../../common/models'; +import { + getLineData, + getTimeSeries, + getTimeValue +} from '../../common/timeSeries'; +import { LinesData } from '../BasicComponents/Lines/models'; +import { dateFormat, timeFormat } from '../common'; +import { GetDate, GraphInterval } from '../models'; + +dayjs.extend(durationPlugin); + +export const adjustGraphData = (graphData: LineChartData): LinesData => { + const lines = getLineData(graphData); + const sortedLines = sortBy(prop('name'), lines); + const displayedLines = reject(propEq(false, 'display'), sortedLines); + + const timeSeries = getTimeSeries(graphData); + + return { lines: displayedLines, timeSeries }; +}; + +export const getXAxisTickFormat = (graphInterval: GraphInterval): string => { + if ( + isNil(graphInterval) || + isNil(graphInterval?.start) || + isNil(graphInterval?.end) + ) { + return timeFormat; + } + const { end, start } = graphInterval; + const numberDays = dayjs.duration(dayjs(end).diff(dayjs(start))).asDays(); + + return gte(numberDays, 2) ? dateFormat : timeFormat; +}; + +export const truncate = (content?: string): string => { + const maxLength = 180; + + if (isNil(content)) { + return ''; + } + + if (gt(content.length, maxLength)) { + return `${content.substring(0, maxLength)}...`; + } + + return content; +}; + +export const displayArea = (data: unknown): boolean => + !isEmpty(data) && !isNil(data); + +export const getDate = ({ positionX, xScale, timeSeries }: GetDate): Date => { + const { timeTick } = getTimeValue({ + timeSeries, + x: positionX, + xScale + }); + + return new Date(timeTick); +}; diff --git a/centreon/packages/ui/src/Graph/Chart/index.tsx b/centreon/packages/ui/src/Graph/Chart/index.tsx new file mode 100644 index 0000000000..f7af208b16 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/index.tsx @@ -0,0 +1,121 @@ +import { MutableRefObject, memo, useRef } from 'react'; + +import dayjs from 'dayjs'; +import 'dayjs/locale/en'; +import 'dayjs/locale/es'; +import 'dayjs/locale/fr'; +import 'dayjs/locale/pt'; +import localizedFormat from 'dayjs/plugin/localizedFormat'; +import timezonePlugin from 'dayjs/plugin/timezone'; +import utcPlugin from 'dayjs/plugin/utc'; +import { equals } from 'ramda'; + +import { ParentSize } from '../..'; +import Loading from '../../LoadingSkeleton'; +import { LineChartData, Thresholds } from '../common/models'; + +import Chart from './Chart'; +import LoadingSkeleton from './LoadingSkeleton'; +import { GlobalAreaLines, LineChartProps } from './models'; +import useChartData from './useChartData'; + +dayjs.extend(localizedFormat); +dayjs.extend(utcPlugin); +dayjs.extend(timezonePlugin); + +interface Props extends Partial { + data?: LineChartData; + end: string; + limitLegend?: false | number; + loading: boolean; + shapeLines?: GlobalAreaLines; + start: string; + thresholdUnit?: string; + thresholds?: Thresholds; +} + +const WrapperChart = ({ + end, + start, + height = 500, + width, + shapeLines, + axis, + displayAnchor, + zoomPreview, + data, + loading, + timeShiftZones, + tooltip = { + mode: 'all', + sortOrder: 'name' + }, + annotationEvent, + legend = { + display: true, + mode: 'grid', + placement: 'bottom' + }, + header, + lineStyle, + barStyle, + thresholds, + thresholdUnit, + limitLegend +}: Props): JSX.Element | null => { + const { adjustedData } = useChartData({ data, end, start }); + const lineChartRef = useRef(null); + + if (loading && !adjustedData) { + return ( + + ); + } + + if (!adjustedData) { + return ; + } + + return ( +
} + style={{ height: '100%', overflow: 'hidden', width: '100%' }} + > + + {({ + height: responsiveHeight, + width: responsiveWidth + }): JSX.Element => { + return ( + + ); + }} + +
+ ); +}; + +export default memo(WrapperChart, equals); diff --git a/centreon/packages/ui/src/Graph/Chart/models.ts b/centreon/packages/ui/src/Graph/Chart/models.ts new file mode 100644 index 0000000000..6abce40b77 --- /dev/null +++ b/centreon/packages/ui/src/Graph/Chart/models.ts @@ -0,0 +1,185 @@ +import { ReactNode } from 'react'; + +import { ScaleLinear } from 'd3-scale'; + +import { BarStyle } from '../BarChart/models'; +import { AxisX, Axis as AxisYLeft, AxisYRight } from '../common/Axes/models'; +import { LineChartData } from '../common/models'; +import { Line, TimeValue } from '../common/timeSeries/models'; + +import { FactorsVariation } from './BasicComponents/Lines/Threshold/models'; +import { + AreaRegularLines, + AreaStackedLines +} from './BasicComponents/Lines/models'; +import { TimelineEvent } from './InteractiveComponents/Annotations/models'; + +export interface LineChartEndpoint { + baseUrl: string; + queryParameters: GraphInterval; +} +export interface Data { + baseAxis: number; + lines: Array; + timeSeries: Array; + title: string; +} + +export enum GraphIntervalProperty { + end = 'end', + start = 'start' +} + +export interface Interval { + end: Date; + start: Date; +} + +export interface GraphInterval { + end?: string; + start?: string; +} + +export interface ShapeLines { + areaRegularLines?: AreaRegularLines; + areaStackedLines?: AreaStackedLines; +} + +export interface ChartAxis { + axisX?: AxisX; + axisYLeft?: AxisYLeft; + axisYRight?: AxisYRight; + gridLinesType?: 'horizontal' | 'vertical' | 'all'; + isCenteredZero?: boolean; + scale?: 'linear' | 'logarithmic'; + scaleLogarithmicBase?: number; + showBorder?: boolean; + showGridLines?: boolean; + yAxisTickLabelRotation?: number; +} + +export interface InteractedZone { + enable?: boolean; + getInterval?: (data: Interval) => void; +} + +export interface TooltipData { + data: Date; + hideTooltip: () => void; + tooltipOpen: boolean; +} +export interface ThresholdTooltip { + thresholdLabel?: string; +} +export interface Tooltip { + mode: 'all' | 'single' | 'hidden'; + renderComponent?: (args: TooltipData) => ReactNode; + sortOrder: 'name' | 'ascending' | 'descending'; +} + +export interface AnnotationEvent { + data?: Array; +} + +export interface LineChartHeader { + displayTitle?: boolean; + extraComponent?: ReactNode; +} + +export interface DisplayAnchor { + displayGuidingLines?: boolean; + displayTooltipsGuidingLines?: boolean; +} + +export interface LineStyle { + areaTransparency?: number; + curve?: 'linear' | 'step' | 'natural'; + dashLength?: number; + dashOffset?: number; + dotOffset?: number; + lineWidth?: number; + pathStyle?: 'solid' | 'dash' | 'dotted'; + showArea?: boolean; + showPoints?: boolean; +} + +export interface LineChartProps { + annotationEvent?: AnnotationEvent; + axis?: ChartAxis; + barStyle?: BarStyle; + displayAnchor?: DisplayAnchor; + header?: LineChartHeader; + height?: number | null; + legend?: LegendModel; + lineStyle?: LineStyle; + timeShiftZones?: InteractedZone; + tooltip?: Tooltip; + width: number; + zoomPreview?: InteractedZone; +} + +export interface Area { + display: boolean; +} + +export type PatternOrientation = + | 'diagonal' + | 'diagonalRightToLeft' + | 'horizontal' + | 'vertical'; + +export enum ThresholdType { + basic = 'basic', + pattern = 'pattern', + variation = 'variation' +} + +export interface PatternThreshold { + data: Array; + orientation?: Array; + type: ThresholdType.pattern; +} +export interface VariationThreshold { + displayCircles?: boolean; + factors: FactorsVariation; + getCountDisplayedCircles?: (value: number) => void; + type: ThresholdType.variation; +} + +export interface BasicThreshold { + id?: string; + type: ThresholdType.basic; +} + +export interface GlobalAreaLines { + areaRegularLines?: Area; + areaStackedLines?: Area; + areaThresholdLines?: Array< + PatternThreshold | VariationThreshold | BasicThreshold + >; +} +export interface LegendModel { + display?: boolean; + height?: number; + mode: 'grid' | 'list'; + placement: 'bottom' | 'left' | 'right'; + renderExtraComponent?: ReactNode; +} + +export interface GetDate { + positionX: number; + timeSeries: Array; + xScale: ScaleLinear; +} + +export interface GraphTooltipData { + date: string; + highlightedMetricId: number | null; + metrics: Array<{ + color: string; + id: number; + name: string; + unit: string; + value: number; + }>; +} diff --git a/centreon/packages/ui/src/Graph/LineChart/translatedLabels.ts b/centreon/packages/ui/src/Graph/Chart/translatedLabels.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/translatedLabels.ts rename to centreon/packages/ui/src/Graph/Chart/translatedLabels.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/useLineChartData.ts b/centreon/packages/ui/src/Graph/Chart/useChartData.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/useLineChartData.ts rename to centreon/packages/ui/src/Graph/Chart/useChartData.ts diff --git a/centreon/packages/ui/src/Graph/LineChart/useLineChartIntersection.ts b/centreon/packages/ui/src/Graph/Chart/useChartIntersection.ts similarity index 100% rename from centreon/packages/ui/src/Graph/LineChart/useLineChartIntersection.ts rename to centreon/packages/ui/src/Graph/Chart/useChartIntersection.ts diff --git a/centreon/packages/ui/src/Graph/Gauge/AnimatedPie.tsx b/centreon/packages/ui/src/Graph/Gauge/AnimatedPie.tsx index 99c68370a9..53ebfb3396 100644 --- a/centreon/packages/ui/src/Graph/Gauge/AnimatedPie.tsx +++ b/centreon/packages/ui/src/Graph/Gauge/AnimatedPie.tsx @@ -1,5 +1,5 @@ +import { animated, to, useTransition } from '@react-spring/web'; import { PieArcDatum, ProvidedProps } from '@visx/shape/lib/shapes/Pie'; -import { useTransition, to, animated } from '@react-spring/web'; import { equals, includes, isNil, pluck } from 'ramda'; import { Typography } from '@mui/material'; @@ -85,7 +85,9 @@ const AnimatedPie = ({ 'label', thresholds[thresholdType as 'warning' | 'critical'] ).map((label) => ( - {label} + + {label} + ))}
), diff --git a/centreon/packages/ui/src/Graph/Gauge/Gauge.cypress.spec.tsx b/centreon/packages/ui/src/Graph/Gauge/Gauge.cypress.spec.tsx index b4eb266ed2..579e793fcd 100644 --- a/centreon/packages/ui/src/Graph/Gauge/Gauge.cypress.spec.tsx +++ b/centreon/packages/ui/src/Graph/Gauge/Gauge.cypress.spec.tsx @@ -1,12 +1,12 @@ -import dataLastWeek from '../LineChart/mockedData/lastWeek.json'; import { criticalThresholds, rangedThresholds, successThresholds, warningThresholds } from '../common/testUtils'; +import dataLastWeek from '../mockedData/lastWeek.json'; -import { Props, Gauge } from './Gauge'; +import { Gauge, Props } from './Gauge'; const initialize = ( args: Omit diff --git a/centreon/packages/ui/src/Graph/Gauge/Gauge.stories.tsx b/centreon/packages/ui/src/Graph/Gauge/Gauge.stories.tsx index 0b9fc970ba..e75e09514d 100644 --- a/centreon/packages/ui/src/Graph/Gauge/Gauge.stories.tsx +++ b/centreon/packages/ui/src/Graph/Gauge/Gauge.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import dataLastWeek from '../LineChart/mockedData/lastWeek.json'; +import dataLastWeek from '../mockedData/lastWeek.json'; import { Gauge } from './Gauge'; @@ -12,8 +12,16 @@ export default meta; type Story = StoryObj; const Template = (props): JSX.Element => ( -
- +
+
+ +
+
+ +
+
+ +
); diff --git a/centreon/packages/ui/src/Graph/Gauge/PieData.tsx b/centreon/packages/ui/src/Graph/Gauge/PieData.tsx index 4cf14fb677..5809e22ebb 100644 --- a/centreon/packages/ui/src/Graph/Gauge/PieData.tsx +++ b/centreon/packages/ui/src/Graph/Gauge/PieData.tsx @@ -6,9 +6,10 @@ import { useTheme } from '@mui/material'; import { getColorFromDataAndTresholds } from '../common/utils'; -import { thresholdThickness } from './Thresholds'; import AnimatedPie from './AnimatedPie'; +import { thresholdThickness } from './Thresholds'; import { GaugeProps } from './models'; +import { angles } from './utils'; const dataThickness = 45; @@ -37,15 +38,19 @@ const PieData = ({ range: [pieColor, 'transparent'] }); + const dataThicknessFactor = radius / dataThickness / 3; + const thresholdThicknessFactor = radius / thresholdThickness / 15; + return ( -1} pieValue={identity} - startAngle={Math.PI / 2} > {(pie) => ( diff --git a/centreon/packages/ui/src/Graph/Gauge/ResponsiveGauge.tsx b/centreon/packages/ui/src/Graph/Gauge/ResponsiveGauge.tsx index 6eb963674a..fa0f453731 100644 --- a/centreon/packages/ui/src/Graph/Gauge/ResponsiveGauge.tsx +++ b/centreon/packages/ui/src/Graph/Gauge/ResponsiveGauge.tsx @@ -1,18 +1,20 @@ import { useRef } from 'react'; import { Group } from '@visx/group'; -import { flatten, head, pluck } from 'ramda'; import { Tooltip } from '@visx/visx'; +import { flatten, head, pluck } from 'ramda'; -import { Box, Fade, useTheme } from '@mui/material'; +import { Box, useTheme } from '@mui/material'; -import { Metric } from '../common/timeSeries/models'; +import { Tooltip as MuiTooltip } from '../../components/Tooltip'; +import { margins } from '../common/margins'; import { formatMetricValueWithUnit } from '../common/timeSeries'; +import { Metric } from '../common/timeSeries/models'; +import { useTooltipStyles } from '../common/useTooltipStyles'; import { getColorFromDataAndTresholds } from '../common/utils'; -import { margins } from '../common/margins'; -import Thresholds from './Thresholds'; import PieData from './PieData'; +import Thresholds from './Thresholds'; import { GaugeProps } from './models'; interface Props extends Pick { @@ -22,11 +24,6 @@ interface Props extends Pick { width: number; } -const baseStyles = { - ...Tooltip.defaultStyles, - textAlign: 'center' -}; - const ResponsiveGauge = ({ width, height, @@ -35,24 +32,21 @@ const ResponsiveGauge = ({ displayAsRaw, baseColor }: Props): JSX.Element => { + const { classes } = useTooltipStyles(); const svgRef = useRef(null); const theme = useTheme(); - const { - showTooltip, - hideTooltip, - tooltipOpen, - tooltipLeft, - tooltipTop, - tooltipData - } = Tooltip.useTooltip(); + const { showTooltip, hideTooltip, tooltipOpen, tooltipData } = + Tooltip.useTooltip(); const innerWidth = width - margins.left - margins.right; const innerHeight = height - margins.top - margins.bottom; const centerY = innerHeight / 2; const centerX = innerWidth / 2; - const radius = Math.min(innerWidth, innerHeight) / 2; + const baseSize = Math.min(width, height); + const heightOverWidthRatio = height / width; + const radius = baseSize / (heightOverWidthRatio > 0.9 ? 2 : 1.8); const thresholdValues = thresholds.enabled ? flatten([ pluck('value', thresholds.warning), @@ -72,11 +66,6 @@ const ResponsiveGauge = ({ thresholds }); - const svgTop = svgRef.current?.getBoundingClientRect().top || 0; - const svgLeft = svgRef.current?.getBoundingClientRect().left || 0; - - const isSmallWidget = height < 240; - const gaugeValue = formatMetricValueWithUnit({ base: 1000, isRaw: displayAsRaw, @@ -93,54 +82,51 @@ const ResponsiveGauge = ({ width: '100%' }} > - - - - - - - {gaugeValue} - - - - - {tooltipData} - - + + + + + + + {gaugeValue} + + + + ); }; diff --git a/centreon/packages/ui/src/Graph/Gauge/Thresholds.tsx b/centreon/packages/ui/src/Graph/Gauge/Thresholds.tsx index baa99fb3d8..af2aba55a3 100644 --- a/centreon/packages/ui/src/Graph/Gauge/Thresholds.tsx +++ b/centreon/packages/ui/src/Graph/Gauge/Thresholds.tsx @@ -6,6 +6,7 @@ import { useTheme } from '@mui/material'; import AnimatedPie from './AnimatedPie'; import { GaugeProps } from './models'; +import { angles } from './utils'; export const thresholdThickness = 12; @@ -83,18 +84,19 @@ const Thresholds = ({ } ]; + const thresholdThicknessFactor = radius / thresholdThickness / 15; + return ( <> {arcs.map(({ thresholdArc, thresholdScaleOrdinal }) => ( -1} pieValue={(d) => d.value} - startAngle={Math.PI / 2} > {(pie) => ( diff --git a/centreon/packages/ui/src/Graph/Gauge/models.ts b/centreon/packages/ui/src/Graph/Gauge/models.ts index b99342f587..ee573264c0 100644 --- a/centreon/packages/ui/src/Graph/Gauge/models.ts +++ b/centreon/packages/ui/src/Graph/Gauge/models.ts @@ -14,7 +14,7 @@ export interface GaugeProps { } export enum ThresholdType { - Warning, - Error, - Success + Warning = 0, + Error = 1, + Success = 2 } diff --git a/centreon/packages/ui/src/Graph/Gauge/utils.ts b/centreon/packages/ui/src/Graph/Gauge/utils.ts new file mode 100644 index 0000000000..149907a70f --- /dev/null +++ b/centreon/packages/ui/src/Graph/Gauge/utils.ts @@ -0,0 +1,4 @@ +export const angles = { + endAngle: -(2 * Math.PI) / 3, + startAngle: (2 * Math.PI) / 3 +}; diff --git a/centreon/packages/ui/src/Graph/HeatMap/HeatMap.cypress.spec.tsx b/centreon/packages/ui/src/Graph/HeatMap/HeatMap.cypress.spec.tsx index 73376a2f76..49f3410571 100644 --- a/centreon/packages/ui/src/Graph/HeatMap/HeatMap.cypress.spec.tsx +++ b/centreon/packages/ui/src/Graph/HeatMap/HeatMap.cypress.spec.tsx @@ -85,7 +85,7 @@ describe('HeatMap', () => { cy.findByTestId(dataIds[0]).trigger('mouseover'); - cy.contains(`This is the tooltip for Server-Service Counter-53`).should( + cy.contains('This is the tooltip for Server-Service Counter-53').should( 'be.visible' ); }); @@ -102,13 +102,13 @@ describe('HeatMap', () => { cy.findByTestId(dataIds[0]).trigger('mouseover'); - cy.contains(`This is the tooltip for Server-Service Counter-53`).should( + cy.contains('This is the tooltip for Server-Service Counter-53').should( 'not.exist' ); cy.findByTestId(dataIds[1]).trigger('mouseover'); - cy.contains(`This is the tooltip for Server-Service Counter-779`).should( + cy.contains('This is the tooltip for Server-Service Counter-779').should( 'be.visible' ); }); diff --git a/centreon/packages/ui/src/Graph/HeatMap/HeatMap.stories.tsx b/centreon/packages/ui/src/Graph/HeatMap/HeatMap.stories.tsx index fa3ab4c306..9b1877ca41 100644 --- a/centreon/packages/ui/src/Graph/HeatMap/HeatMap.stories.tsx +++ b/centreon/packages/ui/src/Graph/HeatMap/HeatMap.stories.tsx @@ -55,17 +55,10 @@ const Template = (args): JSX.Element => { return ; }; -const TileContent = ({ - data, - backgroundColor -}: { - backgroundColor: string; - data: Data; -}): JSX.Element => ( +const TileContent = ({ data }: { data: Data }): JSX.Element => (
({ width: '100%' }, heatMapTileContent: { - height: `calc(100% - ${theme.spacing(1)})`, - width: `calc(100% - ${theme.spacing(1)})` + height: '100%', + position: 'relative', + width: '100%' }, heatMapTooltip: { backgroundColor: theme.palette.background.paper, diff --git a/centreon/packages/ui/src/Graph/HeatMap/HeatMap.tsx b/centreon/packages/ui/src/Graph/HeatMap/HeatMap.tsx index 484e54338f..8266860821 100644 --- a/centreon/packages/ui/src/Graph/HeatMap/HeatMap.tsx +++ b/centreon/packages/ui/src/Graph/HeatMap/HeatMap.tsx @@ -5,7 +5,9 @@ import { HeatMapProps } from './model'; const HeatMap = (props: HeatMapProps): JSX.Element => ( - {({ width }) => {...props} width={width} />} + {({ width, height }) => ( + {...props} height={height} width={width} /> + )} ); diff --git a/centreon/packages/ui/src/Graph/HeatMap/HeatMapData.json b/centreon/packages/ui/src/Graph/HeatMap/HeatMapData.json index ee11deaaa3..66c1798d27 100644 --- a/centreon/packages/ui/src/Graph/HeatMap/HeatMapData.json +++ b/centreon/packages/ui/src/Graph/HeatMap/HeatMapData.json @@ -134,4 +134,4 @@ "counter": 28 } } -] \ No newline at end of file +] diff --git a/centreon/packages/ui/src/Graph/HeatMap/ResponsiveHeatMap.tsx b/centreon/packages/ui/src/Graph/HeatMap/ResponsiveHeatMap.tsx index 132abd38fe..f358f5c5c8 100644 --- a/centreon/packages/ui/src/Graph/HeatMap/ResponsiveHeatMap.tsx +++ b/centreon/packages/ui/src/Graph/HeatMap/ResponsiveHeatMap.tsx @@ -7,8 +7,8 @@ import { Box } from '@mui/material'; import { Tooltip } from '../../components'; -import { HeatMapProps } from './model'; import { useHeatMapStyles } from './HeatMap.styles'; +import { HeatMapProps } from './model'; const gap = 8; const maxTileSize = 120; @@ -21,8 +21,12 @@ const ResponsiveHeatMap = ({ arrowClassName, tooltipContent, tileSizeFixed, - displayTooltipCondition = T -}: HeatMapProps & { width: number }): JSX.Element | null => { + displayTooltipCondition = T, + height +}: HeatMapProps & { + height: number; + width: number; +}): JSX.Element | null => { const { classes, cx } = useHeatMapStyles(); const tileSize = useMemo(() => { @@ -40,7 +44,11 @@ const ResponsiveHeatMap = ({ const theoricalTotalTilesWidth = tilesLength * tileWidth + (tilesLength - 1) * gap; - if (lt(width, 680) && gt(maxTotalTilesWidth, width) && !tileSizeFixed) { + if ( + (lt(height, maxTileSize) || + (lt(width, 680) && gt(maxTotalTilesWidth, width))) && + !tileSizeFixed + ) { return smallestTileSize; } @@ -49,7 +57,7 @@ const ResponsiveHeatMap = ({ } return tileSizeFixed ? maxTileSize : tileWidth; - }, [width, tiles]); + }, [width, tiles, height]); const isSmallestSize = equals(tileSize, smallestTileSize); diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/UnitLabel.tsx b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/UnitLabel.tsx deleted file mode 100644 index 1f1232ef73..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/UnitLabel.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { commonTickLabelProps } from '../../common'; - -interface UnitLabelProps { - unit: string; - x: number; - y?: number; -} - -const UnitLabel = ({ x, y = 16, unit }: UnitLabelProps): JSX.Element => ( - - {unit} - -); - -export default UnitLabel; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/index.tsx b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/index.tsx deleted file mode 100644 index 93189a1ad4..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/index.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Axis } from '@visx/visx'; -import { ScaleLinear } from 'd3-scale'; -import { isNil } from 'ramda'; - -import { useLocaleDateTimeFormat } from '@centreon/ui'; - -import { getXAxisTickFormat } from '../../helpers'; -import { GraphInterval } from '../../models'; -import { getUnits } from '../../../common/timeSeries'; - -import UnitLabel from './UnitLabel'; -import { Data } from './models'; -import useAxisY from './useAxisY'; - -interface Props { - data: Data; - graphInterval: GraphInterval; - height: number; - leftScale: ScaleLinear; - rightScale: ScaleLinear; - width: number; - xScale: ScaleLinear; -} - -const Axes = ({ - height, - width, - data, - rightScale, - leftScale, - xScale, - graphInterval -}: Props): JSX.Element => { - const { format } = useLocaleDateTimeFormat(); - const { lines, showBorder, yAxisTickLabelRotation } = data; - - const { axisLeft, axisRight } = useAxisY({ data, graphHeight: height }); - - const [firstUnit, secondUnit, thirdUnit] = getUnits(lines); - - const xTickCount = Math.min(Math.ceil(width / 82), 12); - - const tickFormat = - data?.axisX?.xAxisTickFormat ?? getXAxisTickFormat(graphInterval); - - const formatAxisTick = (tick): string => - format({ date: new Date(tick), formatString: tickFormat }); - - const hasMoreThanTwoUnits = !isNil(thirdUnit); - const displayAxisRight = !isNil(secondUnit) && !hasMoreThanTwoUnits; - - return ( - - - - {axisLeft.displayUnit && } - - ({ - ...axisLeft.tickLabelProps(), - angle: yAxisTickLabelRotation - })} - tickLength={2} - /> - - {displayAxisRight && ( - ({ - ...axisRight.tickLabelProps(), - angle: yAxisTickLabelRotation - })} - tickLength={2} - /> - )} - {axisRight.displayUnit && } - - ); -}; - -export default Axes; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/models.ts b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/models.ts deleted file mode 100644 index 02bde40b72..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/models.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Line, TimeValue } from '../../../common/timeSeries/models'; -import { LineChartAxis } from '../../models'; - -export interface LabelProps { - [x: string]: unknown; - textAnchor?: string; -} - -export interface Axis { - displayUnit?: boolean; -} - -export interface AxisYRight extends Axis { - display?: boolean; -} - -export interface AxisX { - xAxisTickFormat?: string; -} -export interface Data - extends Omit { - axisX?: AxisX; - axisYLeft?: Axis; - axisYRight?: AxisYRight; - baseAxis: number; - lines: Array; - timeSeries: Array; -} diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/useAxisY.ts b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/useAxisY.ts deleted file mode 100644 index dfe65b4991..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Axes/useAxisY.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { isNil } from 'ramda'; -import { Axis } from '@visx/visx'; - -import { useTheme } from '@mui/material'; - -import { formatMetricValue, getUnits } from '../../../common/timeSeries'; -import { commonTickLabelProps } from '../../common'; - -import { Data, LabelProps } from './models'; - -interface AxisYData { - displayUnit: boolean; - numTicks?: number; - tickFormat: (value: unknown) => string; - tickLabelProps: Axis.TickLabelProps; -} - -interface AxisRightData extends AxisYData { - display: boolean; -} - -interface AxisY { - axisLeft: AxisYData; - axisRight: AxisRightData; -} - -interface Props { - data: Omit; - graphHeight?: number; -} - -const useAxisY = ({ data, graphHeight }: Props): AxisY => { - const theme = useTheme(); - - const { lines } = data; - const [firstUnit, secondUnit, thirdUnit] = getUnits(lines); - - const numTicks = graphHeight && Math.ceil(graphHeight / 30); - - const hasMoreThanTwoUnits = !isNil(thirdUnit); - const hasTwoUnits = !isNil(secondUnit) && !hasMoreThanTwoUnits; - - const displayAxisRight = data?.axisYRight?.display ?? hasTwoUnits; - const displayUnitAxisRight = data?.axisYRight?.displayUnit ?? hasTwoUnits; - const displayUnitAxisLeft = - data?.axisYLeft?.displayUnit ?? !hasMoreThanTwoUnits; - - const formatTick = - ({ unit }) => - (value): string => { - if (isNil(value)) { - return ''; - } - - return formatMetricValue({ base: data.baseAxis, unit, value }) as string; - }; - - const labelProps = ({ - textAnchor, - ...rest - }: LabelProps): Record => ({ - ...commonTickLabelProps, - textAnchor, - ...rest - }); - - const tickLabelPropsAxisLeft = (): Record => - labelProps({ - dx: theme.spacing(-1), - dy: theme.spacing(0.5), - textAnchor: 'end' - }); - - const tickLabelPropsAxisRight = (): Record => - labelProps({ - dx: theme.spacing(0.5), - dy: theme.spacing(0.5), - textAnchor: 'start' - }); - - return { - axisLeft: { - displayUnit: displayUnitAxisLeft, - numTicks, - tickFormat: formatTick({ - unit: hasMoreThanTwoUnits ? '' : firstUnit - }), - tickLabelProps: tickLabelPropsAxisLeft - }, - axisRight: { - display: displayAxisRight, - displayUnit: displayUnitAxisRight, - numTicks, - tickFormat: formatTick({ unit: secondUnit }), - tickLabelProps: tickLabelPropsAxisRight - } - }; -}; - -export default useAxisY; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Grids/index.tsx b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Grids/index.tsx deleted file mode 100644 index fccd54d8ff..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Grids/index.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useMemo } from 'react'; - -import { Grid } from '@visx/visx'; -import { ScaleLinear } from 'd3-scale'; -import { includes } from 'ramda'; - -import { LineChartAxis } from '../../models'; - -interface Props extends Pick { - height: number; - leftScale: ScaleLinear; - width: number; - xScale: ScaleLinear; -} - -const Grids = ({ - height, - width, - leftScale, - xScale, - gridLinesType -}: Props): JSX.Element => { - const displayRows = useMemo( - () => includes(gridLinesType, ['all', 'horizontal', undefined]), - [gridLinesType] - ); - const displayColumns = useMemo( - () => includes(gridLinesType, ['all', 'vertical', undefined]), - [gridLinesType] - ); - - return ( - - {displayRows && ( - - )} - {displayColumns && ( - - )} - - ); -}; - -export default Grids; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/RegularLines/index.tsx b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/RegularLines/index.tsx deleted file mode 100644 index f71759a6e4..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/RegularLines/index.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { memo } from 'react'; - -import { Shape } from '@visx/visx'; -import { ScaleLinear, ScaleTime } from 'd3-scale'; -import { equals, isNil, pick, prop } from 'ramda'; - -import { getTime } from '../../../../common/timeSeries'; -import { TimeValue } from '../../../../common/timeSeries/models'; -import { getCurveFactory, getFillColor } from '../../../common'; -import { getStrokeDashArray } from '../../../../common/utils'; - -interface Props { - areaColor: string; - curve: 'linear' | 'step' | 'natural'; - dashLength?: number; - dashOffset?: number; - dotOffset?: number; - filled: boolean; - graphHeight: number; - highlight?: boolean; - lineColor: string; - lineWidth?: number; - metric_id: number; - shapeAreaClosed?: Record; - shapeLinePath?: Record; - timeSeries: Array; - transparency: number; - unit: string; - xScale: ScaleTime; - yScale: ScaleLinear; -} - -const RegularLine = ({ - filled, - timeSeries, - highlight, - metric_id, - lineColor, - unit, - yScale, - xScale, - areaColor, - transparency, - graphHeight, - curve, - lineWidth, - dotOffset, - dashLength, - dashOffset -}: Props): JSX.Element => { - const curveType = getCurveFactory(curve); - const formattedLineWidth = lineWidth ?? 2; - - const props = { - curve: curveType, - data: timeSeries, - defined: (value): boolean => !isNil(value[metric_id]), - opacity: 1, - stroke: lineColor, - strokeDasharray: getStrokeDashArray({ - dashLength, - dashOffset, - dotOffset, - lineWidth: formattedLineWidth - }), - strokeWidth: highlight - ? Math.ceil((formattedLineWidth || 1) * 1.3) - : formattedLineWidth, - unit, - x: (timeValue): number => xScale(getTime(timeValue)) as number, - y: (timeValue): number => yScale(prop(metric_id, timeValue)) ?? null - }; - - if (filled) { - return ( - - data-metric={metric_id} - fill={getFillColor({ areaColor, transparency })} - fillRule="nonzero" - key={metric_id} - y0={Math.min(yScale(0), graphHeight)} - yScale={yScale} - {...props} - /> - ); - } - - return data-metric={metric_id} {...props} />; -}; - -const memoizedProps = [ - 'curve', - 'lineColor', - 'areaColor', - 'filled', - 'transparency', - 'lineWidth', - 'dotOffset', - 'dashLength', - 'dashOffset' -]; - -export default memo(RegularLine, (prevProps, nextProps) => { - const { - timeSeries: prevTimeSeries, - graphHeight: prevGraphHeight, - highlight: prevHighlight, - xScale: prevXScale, - yScale: prevYScale - } = prevProps; - const { - timeSeries: nextTimeSeries, - graphHeight: nextGraphHeight, - highlight: nextHighlight, - xScale: nextXScale, - yScale: nextYScale - } = nextProps; - - const prevXScaleRange = prevXScale.range(); - const nextXScaleRange = nextXScale.range(); - const prevYScaleDomain = prevYScale.domain(); - const nextYScaleDomain = nextYScale.domain(); - - return ( - equals(prevTimeSeries, nextTimeSeries) && - equals(prevGraphHeight, nextGraphHeight) && - equals(prevHighlight, nextHighlight) && - equals(prevXScaleRange, nextXScaleRange) && - equals(prevYScaleDomain, nextYScaleDomain) && - equals(pick(memoizedProps, prevProps), pick(memoizedProps, nextProps)) - ); -}); diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/StackedLines/index.tsx b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/StackedLines/index.tsx deleted file mode 100644 index 8a55ccd70d..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/StackedLines/index.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { Shape } from '@visx/visx'; -import { ScaleLinear, ScaleTime } from 'd3-scale'; -import { all, equals, isNil, map, not, nth, path, pipe, prop } from 'ramda'; - -import StackedAnchorPoint, { - getYAnchorPoint -} from '../../../InteractiveComponents/AnchorPoint/StackedAnchorPoint'; -import { StackValue } from '../../../InteractiveComponents/AnchorPoint/models'; -import { getCurveFactory, getFillColor } from '../../../common'; -import { getDates, getTime } from '../../../../common/timeSeries'; -import { Line, TimeValue } from '../../../../common/timeSeries/models'; -import Point from '../Point'; -import { getPointRadius, getStrokeDashArray } from '../../../../common/utils'; - -interface Props { - areaTransparency?: number; - curve: 'linear' | 'step' | 'natural'; - dashLength?: number; - dashOffset?: number; - displayAnchor: boolean; - dotOffset?: number; - lineWidth?: number; - lines: Array; - showArea?: boolean; - showPoints?: boolean; - timeSeries: Array; - xScale: ScaleTime; - yScale: ScaleLinear; -} - -const StackLines = ({ - timeSeries, - lines, - yScale, - xScale, - displayAnchor, - curve, - showPoints, - showArea, - areaTransparency, - lineWidth, - dashLength, - dashOffset, - dotOffset -}: Props): JSX.Element => { - const curveType = getCurveFactory(curve); - - const formattedLineWidth = lineWidth ?? 2; - - return ( - { - return pipe( - map(prop('metric_id')) as unknown as ( - displayedLines - ) => Array, - all((metric_id) => pipe(path(['data', metric_id]), isNil, not)(d)) - )(lines); - }} - keys={map(prop('metric_id'), lines)} - x={(d): number => xScale(getTime(d.data)) ?? 0} - y0={(d): number => yScale(d[0]) ?? 0} - y1={(d): number => yScale(d[1]) ?? 0} - > - {({ stacks, path: linePath }): Array => { - return stacks.map((stack, index) => { - const { areaColor, transparency, lineColor, highlight, metric_id } = - nth(index, lines) as Line; - - const formattedTransparency = isNil(areaTransparency) - ? transparency || 80 - : areaTransparency; - - return ( - - {displayAnchor && ( - } - timeSeries={timeSeries} - transparency={transparency} - xScale={xScale} - yScale={yScale} - /> - )} - {showPoints && - getDates(timeSeries).map((timeTick) => ( - , - timeTick, - yScale - })} - yScale={yScale} - /> - ))} - - - ); - }); - }} - - ); -}; - -export default StackLines; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/StackedLines/useStackedLines.ts b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/StackedLines/useStackedLines.ts deleted file mode 100644 index 8dc712c304..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/StackedLines/useStackedLines.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { - getInvertedStackedLines, - getNotInvertedStackedLines, - getTimeSeriesForLines -} from '../../../../common/timeSeries'; -import { LinesData } from '../models'; - -interface StackedLines { - invertedStackedLinesData: LinesData; - stackedLinesData: LinesData; -} - -const useStackedLines = ({ lines, timeSeries }): StackedLines => { - const regularStackedLines = getNotInvertedStackedLines(lines); - - const regularStackedTimeSeries = getTimeSeriesForLines({ - lines: regularStackedLines, - timeSeries - }); - - const invertedStackedLines = getInvertedStackedLines(lines); - const invertedStackedTimeSeries = getTimeSeriesForLines({ - lines: invertedStackedLines, - timeSeries - }); - - return { - invertedStackedLinesData: { - lines: invertedStackedLines, - timeSeries: invertedStackedTimeSeries - }, - stackedLinesData: { - lines: regularStackedLines, - timeSeries: regularStackedTimeSeries - } - }; -}; - -export default useStackedLines; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx deleted file mode 100644 index e2a4a6d9f4..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { equals, isNil } from 'ramda'; - -import { displayArea } from '../../../helpers/index'; -import { - PatternThreshold, - ThresholdType, - VariationThreshold -} from '../../../models'; -import { TimeValue } from '../../../../common/timeSeries/models'; - -import BasicThreshold from './BasicThreshold'; -import Circle from './Circle'; -import ThresholdWithPatternLines from './ThresholdWithPatternLines'; -import ThresholdWithVariation from './ThresholdWithVariation'; -import { WrapperThresholdLinesModel } from './models'; -import useScaleThreshold from './useScaleThreshold'; - -interface Props extends WrapperThresholdLinesModel { - curve: 'linear' | 'natural' | 'step'; - graphHeight: number; - timeSeries: Array; -} - -const WrapperThresholdLines = ({ - areaThresholdLines, - graphHeight, - leftScale, - lines, - rightScale, - timeSeries, - xScale, - curve -}: Props): JSX.Element | null => { - const data = useScaleThreshold({ - areaThresholdLines, - leftScale, - lines, - rightScale, - xScale - }); - - if (!data) { - return null; - } - - const { getX, getY0, getY1, lineColorY0, lineColorY1, ...rest } = data; - - const commonProps = { - curve, - fillAboveArea: lineColorY0, - fillBelowArea: lineColorY1, - getX, - graphHeight, - timeSeries - }; - - const thresholdLines = areaThresholdLines?.map((item, index) => { - const { type } = item; - - if (equals(type, ThresholdType.basic)) { - return [ - { - Component: BasicThreshold, - key: index, - props: { ...commonProps, getY0, getY1 } - } - ]; - } - if (equals(type, ThresholdType.variation)) { - const dataVariation = item as VariationThreshold; - if (!rest?.getY0Variation || !rest.getY1Variation || !rest.getYOrigin) { - return null; - } - - return [ - { - Component: ThresholdWithVariation, - key: index, - props: { - factors: dataVariation.factors, - ...commonProps, - ...rest - } - }, - { - Component: Circle, - key: 'circle', - props: { - ...rest, - getCountDisplayedCircles: dataVariation?.getCountDisplayedCircles, - getX, - timeSeries - } - } - ]; - } - if (equals(type, ThresholdType.pattern)) { - const dataPattern = item as PatternThreshold; - - if (!displayArea(dataPattern?.data)) { - return null; - } - - const { data: pattern } = dataPattern; - - return pattern.map((element, ind) => ({ - Component: ThresholdWithPatternLines, - key: ind, - props: { - data: element, - graphHeight, - key: ind, - leftScale, - orientation: dataPattern?.orientation, - rightScale, - xScale - } - })); - } - - return null; - }); - - const filteredThresholdLines = thresholdLines?.filter((item) => !isNil(item)); - - if (!filteredThresholdLines) { - return null; - } - - return ( - - {filteredThresholdLines.map((element) => - element?.map(({ Component, props, key }) => ( - - )) - )} - - ); -}; - -export default WrapperThresholdLines; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/models.ts b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/models.ts deleted file mode 100644 index f50a1032e4..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/Threshold/models.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { ScaleLinear } from 'd3-scale'; -import { equals, reject } from 'ramda'; - -import { GlobalAreaLines, ThresholdType } from '../../../models'; -import { Line, TimeValue } from '../../../../common/timeSeries/models'; - -export interface Data { - lineColor: string; - metric: string; - yScale: ScaleLinear; -} - -export interface Point { - x: number; - y: number; -} - -export interface ArePointsOnline { - pointLower: Point; - pointOrigin: Point; - pointUpper: Point; -} -export interface Online extends ArePointsOnline { - maxDistance?: number; -} - -export interface FactorsVariation { - currentFactorMultiplication: number; - simulatedFactorMultiplication: number; -} - -export interface Result { - getX: (timeValue: TimeValue) => number; - getY0: (timeValue: TimeValue) => number; - getY1: (timeValue: TimeValue) => number; - lineColorY0: string; - lineColorY1: string; -} - -export interface EnvelopeVariationFormula { - factorsData: FactorsVariation; - lowerRealValue: number; - upperRealValue: number; -} - -export interface ThresholdLinesModel { - dataY0: Data; - dataY1: Data; - graphHeight: number; - timeSeries: Array; - xScale: ScaleLinear; -} - -export interface LinesThreshold { - lineLower: Line; - lineOrigin: Line; - lineUpper: Line; -} - -export interface WrapperThresholdLinesModel { - areaThresholdLines?: GlobalAreaLines['areaThresholdLines']; - leftScale: ScaleLinear; - lines: Array; - rightScale: ScaleLinear; - xScale: ScaleLinear; -} - -export interface ScaleVariationThreshold { - getY0Variation: (timeValue: TimeValue) => number; - getY1Variation: (timeValue: TimeValue) => number; - getYOrigin: (timeValue: TimeValue) => number; -} - -export interface Circle extends ScaleVariationThreshold { - getCountDisplayedCircles?: (value: number) => void; - getX: (timeValue: TimeValue) => number; - timeSeries: Array; -} - -export const lowerLineName = 'Lower Threshold'; -export const upperLineName = 'Upper Threshold'; - -// upper,lower and origin -export const requiredNumberLinesThreshold = 3; - -export const findLineOfOriginMetricThreshold = ( - lines: Array -): Array => { - const metrics = lines.map((line) => { - const { metric } = line; - - return metric.includes('_upper_thresholds') - ? metric.replace('_upper_thresholds', '') - : null; - }); - - const originMetric = metrics.find((element) => element); - - return reject((line: Line) => !equals(line.name, originMetric), lines); -}; - -export const canDisplayThreshold = ( - areaThresholdLines: GlobalAreaLines['areaThresholdLines'] -): boolean => - !!areaThresholdLines?.find((item) => item && item.type in ThresholdType); diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/index.tsx b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/index.tsx deleted file mode 100644 index de5e71a307..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/index.tsx +++ /dev/null @@ -1,241 +0,0 @@ -import { MutableRefObject } from 'react'; - -import { ScaleLinear } from 'd3-scale'; -import { isNil } from 'ramda'; - -import { getPointRadius } from '../../../common/utils'; -import GuidingLines from '../../InteractiveComponents/AnchorPoint/GuidingLines'; -import RegularAnchorPoint, { - getYAnchorPoint -} from '../../InteractiveComponents/AnchorPoint/RegularAnchorPoint'; -import { displayArea } from '../../helpers/index'; -import { DisplayAnchor, GlobalAreaLines } from '../../models'; -import { - getDates, - getStackedYScale, - getUnits, - getYScale -} from '../../../common/timeSeries'; -import { Line, TimeValue } from '../../../common/timeSeries/models'; - -import RegularLine from './RegularLines'; -import useRegularLines from './RegularLines/useRegularLines'; -import StackedLines from './StackedLines'; -import useStackedLines from './StackedLines/useStackedLines'; -import WrapperThresholdLines from './Threshold'; -import { - canDisplayThreshold, - requiredNumberLinesThreshold -} from './Threshold/models'; -import Point from './Point'; - -interface Props extends GlobalAreaLines { - areaTransparency?: number; - curve: 'linear' | 'step' | 'natural'; - dashLength?: number; - dashOffset?: number; - displayAnchor?: DisplayAnchor; - displayedLines: Array; - dotOffset?: number; - graphSvgRef: MutableRefObject; - height: number; - leftScale: ScaleLinear; - lineWidth?: number; - rightScale: ScaleLinear; - showArea?: boolean; - showPoints?: boolean; - timeSeries: Array; - width: number; - xScale: ScaleLinear; -} - -const Lines = ({ - areaTransparency, - height, - graphSvgRef, - width, - displayAnchor, - leftScale, - rightScale, - curve, - xScale, - timeSeries, - displayedLines, - areaThresholdLines, - areaStackedLines, - areaRegularLines, - showArea, - showPoints, - lineWidth, - dotOffset, - dashLength, - dashOffset -}: Props): JSX.Element => { - const { stackedLinesData, invertedStackedLinesData } = useStackedLines({ - lines: displayedLines, - timeSeries - }); - - const { regularLines } = useRegularLines({ lines: displayedLines }); - - const displayThresholdArea = - displayedLines?.length >= requiredNumberLinesThreshold && - canDisplayThreshold(areaThresholdLines); - - const displayAreaRegularLines = - (areaRegularLines?.display ?? true) && displayArea(regularLines); - - const stackedYScale = getStackedYScale({ - leftScale, - rightScale - }); - - const displayGuidingLines = displayAnchor?.displayGuidingLines ?? true; - const commonStackedLinesProps = { - areaTransparency, - curve, - dashLength, - dashOffset, - displayAnchor: displayGuidingLines, - dotOffset, - graphHeight: height, - graphSvgRef, - graphWidth: width, - lineWidth, - showArea, - showPoints, - xScale, - yScale: stackedYScale - }; - - return ( - - {displayGuidingLines && ( - - )} - - {(areaStackedLines?.display ?? true) && ( - <> - {displayArea(stackedLinesData.lines) && ( - - )} - - {displayArea(invertedStackedLinesData.lines) && ( - - )} - - )} - - {displayThresholdArea && ( - - )} - - {displayAreaRegularLines - ? regularLines.map( - ({ - areaColor, - transparency, - lineColor, - filled, - unit, - highlight, - invert, - metric_id - }) => { - const [, secondUnit, thirdUnit] = getUnits( - regularLines as Array - ); - const yScale = getYScale({ - hasMoreThanTwoUnits: !isNil(thirdUnit), - invert, - leftScale, - rightScale, - secondUnit, - unit - }); - - return ( - - {displayGuidingLines && ( - - )} - {showPoints && - getDates(timeSeries).map((timeTick) => ( - - ))} - - - ); - } - ) - : null} - - ); -}; - -export default Lines; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/models.ts b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/models.ts deleted file mode 100644 index 9250a8d2a5..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Lines/models.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ScaleLinear } from 'd3-scale'; - -import { Line, TimeValue } from '../../../common/timeSeries/models'; -import { LineChartData } from '../../../common/models'; - -import { FactorsVariation } from './Threshold/models'; - -export interface ShapeGraphData { - [x: string]: unknown; - display: boolean; - leftScale?: ScaleLinear; - rightScale?: ScaleLinear; - xScale?: ScaleLinear; - yScale?: ScaleLinear; -} - -export interface LinesData { - lines: Array; - timeSeries: Array; -} - -export interface AreaStackedLines extends ShapeGraphData { - invertedStackedLinesData: LinesData; - stackedLinesData: LinesData; -} - -export interface AreaRegularLines extends ShapeGraphData { - lines: Array; - timeSeries: Array; -} - -export interface AreaThreshold extends AreaRegularLines { - dataExclusionPeriods?: Array; - factors?: FactorsVariation; - getCountDisplayedCircles?: (value: number) => void; -} - -export interface Shape { - areaRegularLines: AreaRegularLines; - areaStackedLines: AreaStackedLines; - areaThreshold: AreaThreshold; -} diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Thresholds.tsx b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Thresholds.tsx deleted file mode 100644 index 3dac78f2ac..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/Thresholds.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { equals, isNil } from 'ramda'; - -import { getUnits, getYScale } from '../../common/timeSeries'; -import { Line } from '../../common/timeSeries/models'; -import { Thresholds as ThresholdsModel } from '../../common/models'; - -import { ThresholdLine } from './ThresholdLine'; - -interface Props { - displayedLines: Array; - hideTooltip: () => void; - leftScale: (value: number) => number; - rightScale: (value: number) => number; - showTooltip: (props) => void; - thresholdUnit?: string; - thresholds: ThresholdsModel; - width: number; -} - -const Thresholds = ({ - thresholds, - leftScale, - rightScale, - width, - displayedLines, - thresholdUnit, - showTooltip, - hideTooltip -}: Props): JSX.Element => { - const [firstUnit, secondUnit, thirdUnit] = getUnits( - displayedLines as Array - ); - - const shouldUseRightScale = equals(thresholdUnit, secondUnit); - - const yScale = shouldUseRightScale - ? rightScale - : getYScale({ - hasMoreThanTwoUnits: !isNil(thirdUnit), - invert: null, - leftScale, - rightScale, - secondUnit, - unit: firstUnit - }); - - return ( - <> - {thresholds.warning.map(({ value, label }) => ( - - ))} - {thresholds.critical.map(({ value, label }) => ( - - ))} - - ); -}; - -export default Thresholds; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/useFilterLines.ts b/centreon/packages/ui/src/Graph/LineChart/BasicComponents/useFilterLines.ts deleted file mode 100644 index 34fc94f673..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/useFilterLines.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Dispatch, SetStateAction, useEffect } from 'react'; - -import { equals, propEq, reject } from 'ramda'; - -import { Line } from '../../common/timeSeries/models'; - -import { - findLineOfOriginMetricThreshold, - lowerLineName, - upperLineName -} from './Lines/Threshold/models'; - -interface UseFilterLines { - displayThreshold?: boolean; - lines: Array; - linesGraph: Array | null; - setLinesGraph: Dispatch | null>>; -} - -interface Result { - displayedLines: Array; - newLines: Array; -} - -const useFilterLines = ({ - displayThreshold = false, - lines, - linesGraph, - setLinesGraph -}: UseFilterLines): Result => { - const displayedLines = reject(propEq(false, 'display'), linesGraph ?? lines); - const filterLines = (): Array => { - const lineOriginMetric = findLineOfOriginMetricThreshold(lines); - - const findLinesUpperLower = lines.map((line) => - equals(line.name, lowerLineName) || equals(line.name, upperLineName) - ? line - : null - ); - - const linesUpperLower = reject((element) => !element, findLinesUpperLower); - - return [...lineOriginMetric, ...linesUpperLower] as Array; - }; - - useEffect(() => { - const filteredLines = filterLines(); - if (!lines || !displayThreshold) { - setLinesGraph(lines); - - return; - } - - setLinesGraph(filteredLines); - }, [lines, displayThreshold]); - - return { displayedLines, newLines: linesGraph ?? lines }; -}; - -export default useFilterLines; diff --git a/centreon/packages/ui/src/Graph/LineChart/Header/index.tsx b/centreon/packages/ui/src/Graph/LineChart/Header/index.tsx deleted file mode 100644 index cade2ed743..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/Header/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import Typography from '@mui/material/Typography'; - -import { useMemoComponent } from '@centreon/ui'; - -import { useStyles } from '../LineChart.styles'; -import { LineChartHeader } from '../models'; - -interface Props { - header?: LineChartHeader; - title: string; -} - -const Header = ({ title, header }: Props): JSX.Element => { - const { classes } = useStyles(); - - const displayTitle = header?.displayTitle ?? true; - - return useMemoComponent({ - Component: ( -
-
-
- {displayTitle && ( - - {title} - - )} -
- {header?.extraComponent} -
- ), - - memoProps: [title, header] - }); -}; - -export default Header; diff --git a/centreon/packages/ui/src/Graph/LineChart/Icons/Downtime.tsx b/centreon/packages/ui/src/Graph/LineChart/Icons/Downtime.tsx deleted file mode 100644 index b48c5f3c78..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/Icons/Downtime.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { SvgIcon, SvgIconProps } from '@mui/material'; - -import { ReactComponent as IconDowntime } from '../../../@assets/icons/downtime.icon.svg'; - -const Downtime = (props: SvgIconProps): JSX.Element => ( - -); - -export default Downtime; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx b/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx deleted file mode 100644 index 4d0b8eb827..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import { useSetAtom } from 'jotai'; -import { makeStyles } from 'tss-react/mui'; - -import { Tooltip, Paper, Typography } from '@mui/material'; - -import { truncate } from '../../../helpers'; -import { labelBy } from '../../../translatedLabels'; -import { TimelineEvent } from '../models'; -import { annotationHoveredAtom } from '../annotationsAtoms'; - -const yMargin = -32; -const iconSize = 20; - -const useStyles = makeStyles()((theme) => ({ - tooltip: { - backgroundColor: 'transparent' - }, - tooltipContent: { - padding: theme.spacing(1) - } -})); - -export interface Props { - annotationHoveredId: number; - event: TimelineEvent; - header: string; - icon: JSX.Element; - marker: JSX.Element; - xIcon: number; -} - -const Annotation = ({ - icon, - header, - event, - xIcon, - marker, - annotationHoveredId -}: Props): JSX.Element => { - const { classes } = useStyles(); - const { t } = useTranslation(); - - const setAnnotationHovered = useSetAtom(annotationHoveredAtom); - - const content = `${truncate(event.content)} (${t(labelBy)} ${ - event.contact?.name - })`; - - return ( - - - {header} - {content} - - } - > - - setAnnotationHovered(() => ({ annotationHoveredId, event })) - } - onMouseLeave={(): void => setAnnotationHovered(() => undefined)} - > - - {icon} - - - {marker} - - ); -}; - -export default Annotation; -export { yMargin, iconSize }; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Area/Downtime.tsx b/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Area/Downtime.tsx deleted file mode 100644 index d03b0eafd4..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/Annotations/Area/Downtime.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useTranslation } from 'react-i18next'; - -import { useTheme } from '@mui/material'; - -import IconDowntime from '../../../Icons/Downtime'; -import { labelDowntime } from '../../../translatedLabels'; -import EventAnnotations from '../EventAnnotations'; -import { Args } from '../models'; - -const DowntimeAnnotations = (props: Args): JSX.Element => { - const { t } = useTranslation(); - const theme = useTheme(); - - const color = theme.palette.action.inDowntime; - - return ( - - ); -}; - -export default DowntimeAnnotations; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/GraphValueTooltip.tsx b/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/GraphValueTooltip.tsx deleted file mode 100644 index 3410413c8f..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/GraphValueTooltip.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { useAtomValue } from 'jotai'; -import { equals, isNil } from 'ramda'; - -import { Box, Typography } from '@mui/material'; - -import { mousePositionAtom } from '../interactionWithGraphAtoms'; -import { formatMetricValueWithUnit } from '../../../common/timeSeries'; -import { Tooltip } from '../../models'; - -import { useGraphValueTooltip } from './useGraphValueTooltip'; -import { useGraphValueTooltipStyles } from './useGraphValueTooltipStyles'; - -interface Props extends Pick { - base: number; - isSingleMode: boolean; -} - -const GraphValueTooltip = ({ - base, - isSingleMode, - sortOrder -}: Props): JSX.Element | null => { - const { classes } = useGraphValueTooltipStyles(); - const mousePosition = useAtomValue(mousePositionAtom); - - const graphValue = useGraphValueTooltip({ isSingleMode, sortOrder }); - - if (isNil(graphValue) || isNil(mousePosition)) { - return null; - } - - return ( -
- {graphValue.dateTime} -
- {graphValue.metrics.map(({ unit, color, id, value, name }) => { - const isMetricHighlighted = equals( - id, - graphValue.highlightedMetricId - ); - - return ( -
- - - {name} - - - {formatMetricValueWithUnit({ - base, - unit, - value - })} - -
- ); - })} -
-
- ); -}; - -export default GraphValueTooltip; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/index.tsx b/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/index.tsx deleted file mode 100644 index fa371a0014..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/index.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { useState } from 'react'; - -import { equals, isNil, negate } from 'ramda'; - -import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; -import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos'; - -import { GraphInterval, Interval } from '../../models'; -import { margin } from '../../common'; - -import TimeShiftIcon, { timeShiftIconSize } from './TimeShiftIcon'; -import TimeShiftZone from './TimeShiftZone'; -import { TimeShiftDirection } from './models'; - -interface Props { - getInterval?: (args: Interval) => void; - graphHeight: number; - graphInterval: GraphInterval; - graphWidth: number; -} - -const TimeShiftZones = ({ - graphHeight, - graphWidth, - getInterval, - graphInterval -}: Props): JSX.Element => { - const [directionHovered, setDirectionHovered] = - useState(null); - - const marginLeft = margin.left; - - const isBackward = equals(directionHovered, TimeShiftDirection.backward); - const displayIcon = !isNil(directionHovered); - const propsIcon = { color: 'primary' as const }; - - const xIcon = isBackward - ? negate(marginLeft) - : graphWidth + timeShiftIconSize / 2; - - const yIcon = graphHeight / 2 - timeShiftIconSize / 2; - - const Icon = isBackward ? ( - - ) : ( - - ); - const ariaLabelIcon = isBackward ? 'labelBackward' : 'labelForward'; - - const commonData = { - getInterval, - graphHeight, - graphInterval, - graphWidth - }; - - return ( - <> - - - {displayIcon && ( - - )} - - ); -}; - -export default TimeShiftZones; diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/models.ts b/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/models.ts deleted file mode 100644 index 8808950255..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/TimeShiftZones/models.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { GraphInterval, GraphIntervalProperty } from '../../models'; - -export enum TimeShiftDirection { - backward, - forward -} - -export interface GetShiftDate { - property: GraphIntervalProperty; - timePeriod: GraphInterval; - timeShiftDirection: TimeShiftDirection; -} diff --git a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/index.tsx b/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/index.tsx deleted file mode 100644 index a4f712ce1d..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/InteractiveComponents/index.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import { MutableRefObject } from 'react'; - -import { Event } from '@visx/visx'; -import { ScaleTime } from 'd3-scale'; -import { useSetAtom } from 'jotai'; -import { - all, - equals, - find, - isEmpty, - isNil, - keys, - map, - pick, - pipe, - pluck, - reduce, - toPairs, - values -} from 'ramda'; -import { makeStyles } from 'tss-react/mui'; - -import { - AnnotationEvent, - GraphInterval, - InteractedZone, - InteractedZone as ZoomPreviewModel -} from '../models'; -import { - formatMetricName, - getLineForMetric, - getLinesForMetrics, - getTimeValue, - getUnits, - getYScale -} from '../../common/timeSeries'; -import { Line, TimeValue } from '../../common/timeSeries/models'; -import { margin } from '../common'; - -import Annotations from './Annotations'; -import { TimelineEvent } from './Annotations/models'; -import Bar from './Bar'; -import TimeShiftZones from './TimeShiftZones'; -import ZoomPreview from './ZoomPreview'; -import { - MousePosition, - changeMousePositionDerivedAtom, - eventMouseDownAtom, - eventMouseLeaveAtom, - eventMouseUpAtom, - graphTooltipDataAtom -} from './interactionWithGraphAtoms'; - -const useStyles = makeStyles()(() => ({ - overlay: { - cursor: 'crosshair' - } -})); - -interface CommonData { - graphHeight: number; - graphSvgRef: MutableRefObject; - graphWidth: number; - leftScale; - lines; - rightScale; - timeSeries: Array; - xScale: ScaleTime; -} - -interface TimeShiftZonesData extends InteractedZone { - graphInterval: GraphInterval; -} - -interface Props { - annotationData?: AnnotationEvent; - commonData: CommonData; - timeShiftZonesData: TimeShiftZonesData; - zoomData: ZoomPreviewModel; -} - -const InteractionWithGraph = ({ - zoomData, - commonData, - annotationData, - timeShiftZonesData -}: Props): JSX.Element => { - const { classes } = useStyles(); - - const setEventMouseDown = useSetAtom(eventMouseDownAtom); - const setEventMouseUp = useSetAtom(eventMouseUpAtom); - const setEventMouseLeave = useSetAtom(eventMouseLeaveAtom); - const changeMousePosition = useSetAtom(changeMousePositionDerivedAtom); - const setGraphTooltipData = useSetAtom(graphTooltipDataAtom); - - const { - graphHeight, - graphWidth, - graphSvgRef, - xScale, - timeSeries, - leftScale, - rightScale, - lines - } = commonData; - - const displayZoomPreview = zoomData?.enable ?? true; - - const displayEventAnnotations = - !isNil(annotationData?.data) && !isEmpty(annotationData?.data); - const displayTimeShiftZones = timeShiftZonesData?.enable ?? true; - - const mouseLeave = (event): void => { - setEventMouseLeave(event); - setEventMouseDown(null); - updateMousePosition(null); - setGraphTooltipData(null); - }; - - const mouseUp = (event): void => { - setEventMouseUp(event); - setEventMouseDown(null); - }; - - const mouseMove = (event): void => { - const mousePoint = Event.localPoint( - graphSvgRef?.current as SVGSVGElement, - event - ); - if (!mousePoint) { - return; - } - updateMousePosition([mousePoint.x, mousePoint.y]); - }; - - const mouseDown = (event): void => { - setEventMouseDown(event); - }; - - const updateMousePosition = (pointPosition: MousePosition): void => { - if (isNil(pointPosition)) { - changeMousePosition({ - position: null - }); - setGraphTooltipData(null); - - return; - } - const timeValue = getTimeValue({ - timeSeries, - x: pointPosition[0], - xScale - }); - - if (isNil(timeValue)) { - changeMousePosition({ - position: null - }); - setGraphTooltipData(null); - - return; - } - - const date = timeValue.timeTick; - const displayedMetricIds = pluck('metric_id', lines); - const filteredMetricsValue = pick(displayedMetricIds, timeValue); - const [, secondUnit, thirdUnit] = getUnits(lines as Array); - const areAllValuesEmpty = pipe(values, all(isNil))(filteredMetricsValue); - - const linesData = getLinesForMetrics({ - lines, - metricIds: keys(filteredMetricsValue).map(Number) - }); - - if (areAllValuesEmpty) { - changeMousePosition({ position: pointPosition }); - setGraphTooltipData(null); - - return; - } - - const distanceWithPointPositionPerMetric = reduce( - (acc, [metricId, value]) => { - if (isNil(value)) { - return acc; - } - - const lineData = getLineForMetric({ - lines, - metric_id: Number(metricId) - }); - const yScale = getYScale({ - hasMoreThanTwoUnits: Boolean(thirdUnit), - invert: (lineData as Line).invert, - leftScale, - rightScale, - secondUnit, - unit: (lineData as Line).unit - }); - - const y0 = yScale(value); - - const diffBetweenY0AndPointPosition = Math.abs( - y0 + margin.top - pointPosition[1] - ); - - return { - ...acc, - [metricId]: diffBetweenY0AndPointPosition - }; - }, - {}, - Object.entries(filteredMetricsValue) - ); - - const nearestY0 = Math.min(...values(distanceWithPointPositionPerMetric)); - - const nearestLine = pipe( - toPairs, - find(([, y0]) => equals(y0, nearestY0)) as () => [string, number] - )(distanceWithPointPositionPerMetric); - - changeMousePosition({ position: pointPosition }); - setGraphTooltipData({ - date, - highlightedMetricId: Number(nearestLine[0]), - metrics: map( - ({ metric_id, color, unit, legend, name }) => ({ - color, - id: metric_id, - name: formatMetricName({ legend, name }), - unit, - value: timeValue?.[metric_id] - }), - linesData - ).filter(({ value }) => !isNil(value)) - }); - }; - - return ( - - {displayZoomPreview && ( - - )} - {displayEventAnnotations && ( - } - graphHeight={graphHeight} - graphSvgRef={graphSvgRef} - graphWidth={graphWidth} - xScale={xScale} - /> - )} - {displayTimeShiftZones && ( - - )} - - - ); -}; - -export default InteractionWithGraph; diff --git a/centreon/packages/ui/src/Graph/LineChart/Legend/index.tsx b/centreon/packages/ui/src/Graph/LineChart/Legend/index.tsx deleted file mode 100644 index 397564bed5..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/Legend/index.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import { Dispatch, ReactNode, SetStateAction, useMemo } from 'react'; - -import { equals, prop, slice, sortBy } from 'ramda'; - -import { Box, alpha, useTheme } from '@mui/material'; - -import { useMemoComponent } from '@centreon/ui'; - -import { formatMetricValue } from '../../common/timeSeries'; -import { Line } from '../../common/timeSeries/models'; -import { labelAvg, labelMax, labelMin } from '../translatedLabels'; -import { LegendModel } from '../models'; -import { margin } from '../common'; - -import { useStyles } from './Legend.styles'; -import LegendHeader from './LegendHeader'; -import { GetMetricValueProps, LegendDisplayMode } from './models'; -import useLegend from './useLegend'; -import LegendContent from './LegendContent'; - -interface Props extends Pick { - base: number; - height: number | null; - limitLegend?: false | number; - lines: Array; - renderExtraComponent?: ReactNode; - setLinesGraph: Dispatch | null>>; - shouldDisplayLegendInCompactMode: boolean; - toggable?: boolean; -} - -const MainLegend = ({ - lines, - base, - toggable = true, - limitLegend = false, - renderExtraComponent, - setLinesGraph, - shouldDisplayLegendInCompactMode, - placement, - height, - mode -}: Props): JSX.Element => { - const { classes, cx } = useStyles({ limitLegendRows: Boolean(limitLegend) }); - const theme = useTheme(); - - const { selectMetricLine, clearHighlight, highlightLine, toggleMetricLine } = - useLegend({ lines, setLinesGraph }); - - const sortedData = sortBy(prop('metric_id'), lines); - - const isListMode = useMemo(() => equals(mode, 'list'), [mode]); - - const displayedLines = limitLegend - ? slice(0, limitLegend, sortedData) - : sortedData; - - const getMetricValue = ({ value, unit }: GetMetricValueProps): string => - formatMetricValue({ - base, - unit, - value - }) || 'N/A'; - - const selectMetric = ({ event, metric_id }): void => { - if (!toggable) { - return; - } - - if (event.ctrlKey || event.metaKey) { - toggleMetricLine(metric_id); - - return; - } - - selectMetricLine(metric_id); - }; - - const itemMode = - !isListMode && shouldDisplayLegendInCompactMode - ? LegendDisplayMode.Compact - : LegendDisplayMode.Normal; - - return ( -
-
- {displayedLines.map((line) => { - const { color, display, highlight, metric_id } = line; - - const markerColor = display - ? color - : alpha(theme.palette.text.disabled, 0.2); - - const minMaxAvg = [ - { - label: labelMin, - value: line.minimum_value - }, - { - label: labelMax, - value: line.maximum_value - }, - { - label: labelAvg, - value: line.average_value - } - ]; - - return ( - selectMetric({ event, metric_id })} - onMouseEnter={(): void => highlightLine(metric_id)} - onMouseLeave={(): void => clearHighlight()} - > - - {!shouldDisplayLegendInCompactMode && !isListMode && ( -
-
- {minMaxAvg.map(({ label, value }) => ( - - ))} -
-
- )} -
- ); - })} -
- {renderExtraComponent} -
- ); -}; - -const Legend = (props: Props): JSX.Element => { - const { - toggable, - limitLegend, - lines, - base, - shouldDisplayLegendInCompactMode, - placement, - height, - mode - } = props; - - return useMemoComponent({ - Component: , - memoProps: [ - lines, - base, - toggable, - limitLegend, - shouldDisplayLegendInCompactMode, - placement, - height, - mode - ] - }); -}; - -export default Legend; diff --git a/centreon/packages/ui/src/Graph/LineChart/LineChart.cypress.spec.tsx b/centreon/packages/ui/src/Graph/LineChart/LineChart.cypress.spec.tsx deleted file mode 100644 index 7d76d6f89c..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/LineChart.cypress.spec.tsx +++ /dev/null @@ -1,407 +0,0 @@ -import { LineChartData } from '../common/models'; - -import dataLastDay from './mockedData/lastDay.json'; -import dataLastDayWithNullValues from './mockedData/lastDayWithNullValues.json'; -import dataLastDayWithIncompleteValues from './mockedData/lastDayWithIncompleteValues.json'; -import dataCurvesWithSameColor from './mockedData/curvesWithSameColor.json'; -import { args as argumentsData } from './helpers/doc'; -import { LineChartProps } from './models'; - -import WrapperLineChart from '.'; - -interface Props - extends Pick { - data?: LineChartData; -} - -const initialize = ({ - data = dataLastDay, - tooltip, - legend, - axis, - lineStyle -}: Props): void => { - cy.mount({ - Component: ( - - ) - }); -}; - -describe('Line chart', () => { - describe('Tooltip', () => { - it('displays a tooltip when the graph is hovered', () => { - initialize({}); - - cy.contains('oracle-buffer-hit-ratio graph on srv-oracle-users').should( - 'be.visible' - ); - cy.contains('hitratio').should('be.visible'); - cy.contains('querytime').should('be.visible'); - cy.contains('connTime').should('be.visible'); - cy.contains('Min: 70.31').should('be.visible'); - - cy.findByTestId('graph-interaction-zone').realMouseMove(250, 70); - - cy.contains('06/18/2023').should('be.visible'); - - cy.contains('0.45 s').should('be.visible'); - cy.contains('75.93%').should('be.visible'); - cy.contains('0.43 s').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('displays a metric highlighted when the graph is hovered and the metric is the nearest point', () => { - initialize({}); - - cy.contains('Min: 70.31').should('be.visible'); - - cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); - - cy.get('[data-metric="querytime"]').should( - 'have.attr', - 'data-highlight', - 'false' - ); - cy.get('[data-metric="connTime"]').should( - 'have.attr', - 'data-highlight', - 'true' - ); - - cy.makeSnapshot(); - }); - - it('does not display the tooltip when null values are hovered', () => { - initialize({ data: dataLastDayWithNullValues }); - - cy.contains('Min: 70.31').should('be.visible'); - - cy.findByTestId('graph-interaction-zone').realMouseMove(1185, 100); - - cy.get('[data-metric="querytime"]').should('not.exist'); - - cy.makeSnapshot(); - }); - - it('displays the tooltip with defined values whent the graph is hovered', () => { - initialize({ data: dataLastDayWithIncompleteValues }); - - cy.contains('Min: 70.31').should('be.visible'); - - cy.findByTestId('graph-interaction-zone').realMouseMove(1162, 100); - - cy.get('[data-metric="querytime"]').should('be.visible'); - cy.get('[data-metric="hitratio"]').should('not.exist'); - - cy.makeSnapshot(); - }); - - it('displays the tooltip a single metric when the corresponding prop is set', () => { - initialize({ tooltip: { mode: 'single', sortOrder: 'name' } }); - - cy.contains('Min: 70.31').should('be.visible'); - - cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); - - cy.get('[data-metric="connTime"]').should( - 'have.attr', - 'data-highlight', - 'true' - ); - cy.get('[data-metric="hitratio"]').should('not.exist'); - - cy.makeSnapshot(); - }); - - it('does not display the tooltip when the corresponding prop is set', () => { - initialize({ tooltip: { mode: 'hidden', sortOrder: 'name' } }); - - cy.contains('Min: 70.31').should('be.visible'); - - cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); - - cy.get('[data-metric="querytime"]').should('not.exist'); - cy.get('[data-metric="connTime"]').should('not.exist'); - - cy.makeSnapshot(); - }); - - it('sorts metrics by their value is ascending when the corresponding prop is set', () => { - initialize({ tooltip: { mode: 'all', sortOrder: 'ascending' } }); - - cy.contains('Min: 70.31').should('be.visible'); - - cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); - - cy.get('[data-metric="querytime"]').should('be.visible'); - cy.get('[data-metric="connTime"]').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('sorts metrics by their value is descending when the corresponding prop is set', () => { - initialize({ tooltip: { mode: 'all', sortOrder: 'descending' } }); - - cy.contains('Min: 70.31').should('be.visible'); - - cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26); - - cy.get('[data-metric="querytime"]').should('be.visible'); - cy.get('[data-metric="connTime"]').should('be.visible'); - - cy.makeSnapshot(); - }); - }); - - it('displays the curves with different shades when curves have same color', () => { - initialize({ data: dataCurvesWithSameColor }); - - cy.findByLabelText('Centreon-Server: Round-Trip Average Time') - .find('[data-icon="true"]') - .should('have.css', 'background-color', 'rgb(41, 175, 238)'); - cy.findByLabelText('Centreon-Server_5: Round-Trip Average Time') - .find('[data-icon="true"]') - .should('have.css', 'background-color', 'rgb(83, 191, 241)'); - cy.findByLabelText('Centreon-Server_4: Round-Trip Average Time') - .find('[data-icon="true"]') - .should('have.css', 'background-color', 'rgb(8, 34, 47)'); - cy.findByLabelText('Centreon-Server_3: Round-Trip Average Time') - .find('[data-icon="true"]') - .should('have.css', 'background-color', 'rgb(16, 70, 95)'); - cy.findByLabelText('Centreon-Server_2: Round-Trip Average Time') - .find('[data-icon="true"]') - .should('have.css', 'background-color', 'rgb(24, 105, 142)'); - cy.findByLabelText('Centreon-Server_1: Round-Trip Average Time') - .find('[data-icon="true"]') - .should('have.css', 'background-color', 'rgb(32, 140, 190)'); - - cy.get('[data-metric="1"]').should( - 'have.attr', - 'stroke', - 'rgb(41, 175, 238)' - ); - cy.get('[data-metric="21"]').should( - 'have.attr', - 'stroke', - 'rgb(32, 140, 190)' - ); - cy.get('[data-metric="17"]').should( - 'have.attr', - 'stroke', - 'rgb(24, 105, 142)' - ); - cy.get('[data-metric="13"]').should( - 'have.attr', - 'stroke', - 'rgb(16, 70, 95)' - ); - cy.get('[data-metric="9"]').should('have.attr', 'stroke', 'rgb(8, 34, 47)'); - cy.get('[data-metric="5"]').should( - 'have.attr', - 'stroke', - 'rgb(83, 191, 241)' - ); - - cy.makeSnapshot(); - }); - - describe('Legend', () => { - it('displays the legend in list mode when the corresponding props is set', () => { - initialize({ legend: { mode: 'list', placement: 'bottom' } }); - - cy.contains('Min:').should('not.exist'); - cy.contains('Max:').should('not.exist'); - cy.contains('Avg:').should('not.exist'); - - cy.get('[data-display-side="false"]').should('exist'); - cy.get('[data-as-list="true"]').should('exist'); - - cy.contains('9:00 AM').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('displays the legend on the left side of the graph when the corresponding prop is set', () => { - initialize({ legend: { mode: 'grid', placement: 'left' } }); - - cy.get('[data-display-side="true"]').should('exist'); - cy.get('[data-as-list="true"]').should('exist'); - - cy.contains('9:00 AM').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('displays the legend on the right side of the graph as list when the corresponding props are set', () => { - initialize({ legend: { mode: 'list', placement: 'right' } }); - - cy.get('[data-display-side="true"]').should('exist'); - cy.get('[data-as-list="true"]').should('exist'); - - cy.contains('9:00 AM').should('be.visible'); - - cy.makeSnapshot(); - }); - }); - - describe('Axis', () => { - it('does not display axis borders when the prop is set', () => { - initialize({ axis: { showBorder: false } }); - - cy.contains('9:00 AM').should('be.visible'); - - cy.get('line[class*="visx-axis-line"]') - .eq(0) - .should('have.attr', 'stroke-width') - .and('equal', '0'); - cy.get('line[class*="visx-axis-line"]') - .eq(1) - .should('have.attr', 'stroke-width') - .and('equal', '0'); - cy.get('line[class*="visx-axis-line"]') - .eq(2) - .should('have.attr', 'stroke-width') - .and('equal', '0'); - - cy.makeSnapshot(); - }); - - it('does not display grids when the prop is set', () => { - initialize({ axis: { showGridLines: false } }); - - cy.contains('9:00 AM').should('be.visible'); - - cy.get('g[class="visx-group visx-rows"]').should('not.exist'); - cy.get('g[class="visx-group visx-columns"]').should('not.exist'); - - cy.makeSnapshot(); - }); - - it('displays only horizontal lines when the prop is set', () => { - initialize({ axis: { gridLinesType: 'horizontal' } }); - - cy.contains('9:00 AM').should('be.visible'); - - cy.get('g[class="visx-group visx-rows"]').should('be.visible'); - cy.get('g[class="visx-group visx-columns"]').should('not.exist'); - - cy.makeSnapshot(); - }); - - it('displays only vertical lines when the prop is set', () => { - initialize({ axis: { gridLinesType: 'vertical' } }); - - cy.contains('9:00 AM').should('be.visible'); - - cy.get('g[class="visx-group visx-rows"]').should('not.exist'); - cy.get('g[class="visx-group visx-columns"]').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('rotates the tick label when the props is set', () => { - initialize({ axis: { yAxisTickLabelRotation: -35 } }); - - cy.contains('9:00 AM').should('be.visible'); - - cy.get('text[transform="rotate(-35, -2, 388)"]').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('displays as centered to zero when the prop is set', () => { - initialize({ axis: { isCenteredZero: true } }); - - cy.contains('9:00 AM').should('be.visible'); - - cy.contains('0.9').should('be.visible'); - cy.contains('-0.9').should('be.visible'); - - cy.makeSnapshot(); - }); - }); - - describe('Line style', () => { - it('displays the curve in a natural style when the prop is set', () => { - initialize({ lineStyle: { curve: 'natural' } }); - - cy.contains('9:00 AM').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('displays the curve in a step style when the prop is set', () => { - initialize({ lineStyle: { curve: 'step' } }); - - cy.contains('9:00 AM').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('shows the area when the prop is set', () => { - initialize({ lineStyle: { showArea: true } }); - - cy.contains('9:00 AM').should('be.visible'); - cy.get('path[fill="rgba(102, 153, 204, 0.19999999999999996)"]').should( - 'be.visible' - ); - - cy.makeSnapshot(); - }); - - it('shows the area with a custom transparency when props are set', () => { - initialize({ lineStyle: { areaTransparency: 20, showArea: true } }); - - cy.contains('9:00 AM').should('be.visible'); - cy.get('path[fill="rgba(102, 153, 204, 0.8)"]').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('shows points when the prop is set', () => { - initialize({ lineStyle: { showPoints: true } }); - - cy.contains('9:00 AM').should('be.visible'); - cy.get('circle[cx="4.0625"]').should('be.visible'); - cy.get('circle[cy="163.69430856642046"]').should('be.visible'); - - cy.makeSnapshot(); - }); - - it('displays lines with a custom line width when the prop is set', () => { - initialize({ lineStyle: { lineWidth: 6 } }); - - cy.contains('9:00 AM').should('be.visible'); - cy.get('path[stroke-width="6"]').should('have.length', 3); - - cy.makeSnapshot(); - }); - - it('displays lines with dots width when the prop is set', () => { - initialize({ lineStyle: { dotOffset: 10, lineWidth: 4 } }); - - cy.contains('9:00 AM').should('be.visible'); - cy.get('path[stroke-width="4"]') - .should('have.attr', 'stroke-dasharray') - .and('equals', '4 10'); - }); - - it('displays lines with dots width when the prop is set', () => { - initialize({ lineStyle: { dashLength: 5, dashOffset: 8 } }); - - cy.contains('9:00 AM').should('be.visible'); - cy.get('path[stroke-width="2"]') - .should('have.attr', 'stroke-dasharray') - .and('equals', '5 8'); - }); - }); -}); diff --git a/centreon/packages/ui/src/Graph/LineChart/LineChart.styles.ts b/centreon/packages/ui/src/Graph/LineChart/LineChart.styles.ts deleted file mode 100644 index dd1a4fc4d2..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/LineChart.styles.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { makeStyles } from 'tss-react/mui'; - -const useStyles = makeStyles()((theme) => ({ - container: { - '& .visx-axis-bottom': { - '& .visx-axis-tick': { - '& .visx-line': { - stroke: theme.palette.text.primary - }, - text: { - fill: theme.palette.text.primary - } - } - }, - '& .visx-axis-line': { - stroke: theme.palette.text.primary - }, - '& .visx-axis-right': { - '& .visx-axis-tick': { - '& .visx-line': { - stroke: theme.palette.text.primary - } - } - }, - '& .visx-columns': { - '& .visx-line': { - stroke: theme.palette.divider - } - }, - '& .visx-rows': { - '& .visx-line': { - stroke: theme.palette.divider - } - }, - fill: theme.palette.text.primary, - position: 'relative' - }, - graphValueTooltip: { - backgroundColor: theme.palette.background.paper, - borderRadius: theme.shape.borderRadius, - boxShadow: theme.shadows[3], - color: theme.palette.text.primary, - maxWidth: 'none', - padding: 0 - }, - header: { - display: 'grid', - gridTemplateColumns: '0.4fr 1fr 0.4fr', - width: '100%' - } -})); - -export { useStyles }; diff --git a/centreon/packages/ui/src/Graph/LineChart/LineChart.tsx b/centreon/packages/ui/src/Graph/LineChart/LineChart.tsx deleted file mode 100644 index bca63f774f..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/LineChart.tsx +++ /dev/null @@ -1,403 +0,0 @@ -import { MutableRefObject, useMemo, useRef, useState } from 'react'; - -import { Group, Tooltip } from '@visx/visx'; -import { equals, flatten, gt, isNil, lte, pluck, reduce } from 'ramda'; - -import { - ClickAwayListener, - Fade, - Skeleton, - Stack, - useTheme -} from '@mui/material'; - -import { - getLeftScale, - getRightScale, - getUnits, - getXScale -} from '../common/timeSeries'; -import { Line } from '../common/timeSeries/models'; -import { Thresholds as ThresholdsModel } from '../common/models'; -import { Tooltip as MuiTooltip } from '../../components/Tooltip'; - -import Axes from './BasicComponents/Axes'; -import Grids from './BasicComponents/Grids'; -import Lines from './BasicComponents/Lines'; -import { canDisplayThreshold } from './BasicComponents/Lines/Threshold/models'; -import useFilterLines from './BasicComponents/useFilterLines'; -import { useStyles } from './LineChart.styles'; -import Header from './Header'; -import InteractionWithGraph from './InteractiveComponents'; -import GraphTooltip from './InteractiveComponents/Tooltip'; -import useGraphTooltip from './InteractiveComponents/Tooltip/useGraphTooltip'; -import Legend from './Legend'; -import { margin } from './common'; -import { Data, GlobalAreaLines, GraphInterval, LineChartProps } from './models'; -import { useIntersection } from './useLineChartIntersection'; -import Thresholds from './BasicComponents/Thresholds'; -import { legendWidth } from './Legend/Legend.styles'; -import GraphValueTooltip from './InteractiveComponents/GraphValueTooltip/GraphValueTooltip'; - -const extraMargin = 10; - -interface Props extends LineChartProps { - graphData: Data; - graphInterval: GraphInterval; - graphRef: MutableRefObject; - limitLegend?: false | number; - shapeLines?: GlobalAreaLines; - thresholdUnit?: string; - thresholds?: ThresholdsModel; -} - -const baseStyles = { - ...Tooltip.defaultStyles, - textAlign: 'center' -}; - -const LineChart = ({ - graphData, - height = 500, - width, - shapeLines, - axis, - displayAnchor, - zoomPreview, - graphInterval, - timeShiftZones, - annotationEvent, - tooltip, - legend, - graphRef, - header, - lineStyle, - thresholds, - thresholdUnit, - limitLegend -}: Props): JSX.Element => { - const { classes } = useStyles(); - - const theme = useTheme(); - - const [linesGraph, setLinesGraph] = useState | null>(null); - const graphSvgRef = useRef(null); - - const { isInViewport } = useIntersection({ element: graphRef?.current }); - - const legendRef = useRef(null); - - const { - tooltipOpen: thresholdTooltipOpen, - tooltipLeft: thresholdTooltipLeft, - tooltipTop: thresholdTooltipTop, - tooltipData: thresholdTooltipData, - hideTooltip: hideThresholdTooltip, - showTooltip: showThresholdTooltip - } = Tooltip.useTooltip(); - - const { title, timeSeries, baseAxis, lines } = graphData; - - const thresholdValues = flatten([ - pluck('value', thresholds?.warning || []), - pluck('value', thresholds?.critical || []) - ]); - - const { displayedLines, newLines } = useFilterLines({ - displayThreshold: canDisplayThreshold(shapeLines?.areaThresholdLines), - lines, - linesGraph, - setLinesGraph - }); - - const legendBoundingHeight = - !equals(legend?.display, false) && - (isNil(legend?.placement) || equals(legend?.placement, 'bottom')) - ? legendRef.current?.getBoundingClientRect().height || 0 - : 0; - const legendBoundingWidth = - !equals(legend?.display, false) && - (equals(legend?.placement, 'left') || equals(legend?.placement, 'right')) - ? legendRef.current?.getBoundingClientRect().width || 0 - : 0; - - const [, secondUnit] = getUnits(displayedLines); - - const graphWidth = - width > 0 - ? width - - margin.left - - (secondUnit ? margin.right : 8) - - extraMargin - - legendBoundingWidth - : 0; - const graphHeight = - (height || 0) > 0 - ? (height || 0) - margin.top - 5 - legendBoundingHeight - : 0; - - const xScale = useMemo( - () => - getXScale({ - dataTime: timeSeries, - valueWidth: graphWidth - }), - [timeSeries, graphWidth] - ); - - const leftScale = useMemo( - () => - getLeftScale({ - dataLines: displayedLines, - dataTimeSeries: timeSeries, - isCenteredZero: axis?.isCenteredZero, - scale: axis?.scale, - scaleLogarithmicBase: axis?.scaleLogarithmicBase, - thresholdUnit, - thresholds: (thresholds?.enabled && thresholdValues) || [], - valueGraphHeight: graphHeight - 35 - }), - [ - displayedLines, - timeSeries, - graphHeight, - thresholdValues, - axis?.isCenteredZero, - axis?.scale, - axis?.scaleLogarithmicBase - ] - ); - - const rightScale = useMemo( - () => - getRightScale({ - dataLines: displayedLines, - dataTimeSeries: timeSeries, - isCenteredZero: axis?.isCenteredZero, - scale: axis?.scale, - scaleLogarithmicBase: axis?.scaleLogarithmicBase, - thresholdUnit, - thresholds: (thresholds?.enabled && thresholdValues) || [], - valueGraphHeight: graphHeight - 35 - }), - [ - timeSeries, - displayedLines, - graphHeight, - axis?.isCenteredZero, - axis?.scale, - axis?.scaleLogarithmicBase - ] - ); - - const graphTooltipData = useGraphTooltip({ - graphWidth, - timeSeries, - xScale - }); - - const displayLegend = legend?.display ?? true; - const displayTooltip = !isNil(tooltip?.renderComponent); - - const legendItemsWidth = reduce( - (acc) => acc + legendWidth * 8 + 24, - 0, - displayedLines - ); - - const displayLegendInBottom = - isNil(legend?.placement) || equals(legend?.placement, 'bottom'); - - const shouldDisplayLegendInCompactMode = - lte(graphWidth, 808) && - gt(legendItemsWidth, graphWidth) && - displayLegendInBottom; - - const showGridLines = useMemo( - () => isNil(axis?.showGridLines) || axis?.showGridLines, - [axis?.showGridLines] - ); - - if (!isInViewport) { - return ( - - ); - } - - return ( - <> -
- - - ) - } - > -
- - {displayLegend && - (equals(legend?.placement, 'left') || - equals(legend?.placement, 'right')) && ( -
- -
- )} - - - {showGridLines && ( - - )} - - - - - - - {thresholds?.enabled && ( - - )} - - -
- {displayTooltip && ( - - )} - - - {thresholdTooltipData} - - -
-
-
- {displayLegend && displayLegendInBottom && ( -
- -
- )} - - ); -}; - -export default LineChart; diff --git a/centreon/packages/ui/src/Graph/LineChart/common/index.ts b/centreon/packages/ui/src/Graph/LineChart/common/index.ts deleted file mode 100644 index 80e40f5d99..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/common/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -import * as Curve from '@visx/curve'; -import { always, cond, equals, isNil } from 'ramda'; - -import { alpha } from '@mui/material'; - -const commonTickLabelProps = { - fontFamily: 'Roboto, sans-serif', - fontSize: 10, - textAnchor: 'middle' -}; - -const margin = { bottom: 30, left: 50, right: 50, top: 30 }; - -interface FillColor { - areaColor: string; - transparency: number; -} - -const getFillColor = ({ - transparency, - areaColor -}: FillColor): string | undefined => { - return !isNil(transparency) - ? alpha(areaColor, 1 - transparency * 0.01) - : undefined; -}; - -const dateFormat = 'L'; -const timeFormat = 'LT'; -const dateTimeFormat = `${dateFormat} ${timeFormat}`; -const maxLinesDisplayedLegend = 11; - -const getCurveFactory = ( - curve: 'linear' | 'step' | 'natural' -): typeof Curve.curveLinear => { - return cond([ - [equals('linear'), always(Curve.curveLinear)], - [equals('step'), always(Curve.curveStep)], - [equals('natural'), always(Curve.curveCatmullRom)] - ])(curve); -}; - -export { - commonTickLabelProps, - margin, - getFillColor, - dateFormat, - timeFormat, - dateTimeFormat, - maxLinesDisplayedLegend, - getCurveFactory -}; diff --git a/centreon/packages/ui/src/Graph/LineChart/graphAtoms.ts b/centreon/packages/ui/src/Graph/LineChart/graphAtoms.ts deleted file mode 100644 index 8e9ff5d233..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/graphAtoms.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { atom } from 'jotai'; - -export const timeTickGraphAtom = atom(null); diff --git a/centreon/packages/ui/src/Graph/LineChart/helpers/index.ts b/centreon/packages/ui/src/Graph/LineChart/helpers/index.ts deleted file mode 100644 index 2ac5061750..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/helpers/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import dayjs from 'dayjs'; -import { gt, gte, isEmpty, isNil, prop, propEq, reject, sortBy } from 'ramda'; - -import { LinesData } from '../BasicComponents/Lines/models'; -import { dateFormat, timeFormat } from '../common'; -import { GetDate, GraphInterval } from '../models'; -import { - getLineData, - getTimeSeries, - getTimeValue -} from '../../common/timeSeries'; -import { LineChartData } from '../../common/models'; - -export const adjustGraphData = (graphData: LineChartData): LinesData => { - const lines = getLineData(graphData); - const sortedLines = sortBy(prop('name'), lines); - const displayedLines = reject(propEq(false, 'display'), sortedLines); - - const timeSeries = getTimeSeries(graphData); - - return { lines: displayedLines, timeSeries }; -}; - -export const getXAxisTickFormat = (graphInterval: GraphInterval): string => { - if ( - isNil(graphInterval) || - isNil(graphInterval?.start) || - isNil(graphInterval?.end) - ) { - return timeFormat; - } - const { end, start } = graphInterval; - const numberDays = dayjs.duration(dayjs(end).diff(dayjs(start))).asDays(); - - return gte(numberDays, 2) ? dateFormat : timeFormat; -}; - -export const truncate = (content?: string): string => { - const maxLength = 180; - - if (isNil(content)) { - return ''; - } - - if (gt(content.length, maxLength)) { - return `${content.substring(0, maxLength)}...`; - } - - return content; -}; - -export const displayArea = (data: unknown): boolean => - !isEmpty(data) && !isNil(data); - -export const getDate = ({ positionX, xScale, timeSeries }: GetDate): Date => { - const { timeTick } = getTimeValue({ - timeSeries, - x: positionX, - xScale - }); - - return new Date(timeTick); -}; diff --git a/centreon/packages/ui/src/Graph/LineChart/index.stories.tsx b/centreon/packages/ui/src/Graph/LineChart/index.stories.tsx deleted file mode 100644 index ddf162db52..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/index.stories.tsx +++ /dev/null @@ -1,502 +0,0 @@ -import { useEffect, useState } from 'react'; - -import { Meta, StoryObj } from '@storybook/react'; - -import { Button } from '@mui/material'; -import ButtonGroup from '@mui/material/ButtonGroup'; -import Switch from '@mui/material/Switch'; -import Tooltip from '@mui/material/Tooltip'; - -import { useLocaleDateTimeFormat } from '@centreon/ui'; - -import TimePeriod from '../../TimePeriods'; -import { LineChartData } from '../common/models'; - -import { dateTimeFormat } from './common'; -import { - argTypes, - args as argumentsData, - defaultEnd, - defaultLast7days, - defaultLastMonth, - defaultStart, - lastDayForwardDate, - zoomPreviewDate -} from './helpers/doc'; -import annotationData from './mockedData/annotationData.json'; -import exclusionPeriodFirstPeriod from './mockedData/exclusionPeriodFirstPeriod.json'; -import exclusionPeriodSecondPeriod from './mockedData/exclusionPeriodSecondPeriod.json'; -import exclusionPeriodThirdPeriod from './mockedData/exclusionPeriodThirdPeriod.json'; -import dataLastDayForword from './mockedData/lastDayForward.json'; -import dataLastDayThreshold from './mockedData/lastDayThreshold.json'; -import dataLastMonth from './mockedData/lastMonth.json'; -import dataLastWeek from './mockedData/lastWeek.json'; -import dataZoomPreview from './mockedData/zoomPreview.json'; -import dataLastDay from './mockedData/lastDay.json'; -import dataCurvesSameColor from './mockedData/curvesWithSameColor.json'; -import { Interval, ThresholdType, TooltipData } from './models'; - -import WrapperLineChart from './index'; - -const meta: Meta = { - component: WrapperLineChart -}; -export default meta; - -type Story = StoryObj; - -interface Random { - max: number; - min: number; -} - -const Threshold = (args): JSX.Element => { - const [currentFactorMultiplication, setCurrentFactorMultiplication] = - useState(2.5); - const [countedCircles, setCountedCircles] = useState(); - - const getRandomInt = ({ min, max }: Random): number => { - return Math.floor(Math.random() * (max - min) + min); - }; - - const handleClick = (): void => { - setCurrentFactorMultiplication(getRandomInt({ max: 5, min: 1 })); - }; - - const getCountDisplayedCircles = (value: number): void => { - setCountedCircles(value); - }; - - return ( - <> - - - - - - - ); -}; - -const ExternalComponent = (tooltipData): JSX.Element => { - const { hideTooltip, data } = tooltipData; - const { format } = useLocaleDateTimeFormat(); - - return ( - <> - External component -
-
- {format({ - date: data, - formatString: dateTimeFormat - })} -
-
- - - ); -}; - -const LineChartAndCLS = (args): JSX.Element => { - const [data, setData] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - setTimeout(() => { - setLoading(false); - setData(dataLastDayThreshold as unknown as LineChartData); - }, 100000); - }, []); - - return ( - - ); -}; - -interface TimePeriodSwitchProps { - getDataSwitch: (value: boolean) => void; -} - -const TimePeriodSwitch = ({ - getDataSwitch -}: TimePeriodSwitchProps): JSX.Element => { - const [checked, setChecked] = useState(false); - - const handleChange = (event: React.ChangeEvent): void => { - setChecked(event.target.checked); - }; - - useEffect(() => { - getDataSwitch?.(checked); - }, [checked]); - - return ( - - ); -}; - -const LineChartAndTimePeriod = (args): JSX.Element => { - const [currentData, setCurrentData] = useState(); - const [start, setStart] = useState(); - const [end, setEnd] = useState(); - const [displayAnnotation, setDisplayAnnotation] = useState(); - const [adjustedTimePeriodInterval, setAdjustedTimePeriodInterval] = - useState(); - - const getParameters = (interval): void => { - setStart(interval.start); - setEnd(interval.end); - }; - - useEffect(() => { - if (!start || !end) { - return; - } - if (start.includes(lastDayForwardDate)) { - setCurrentData(dataLastDayForword as unknown as LineChartData); - - return; - } - - if (start.includes(`${defaultStart.split('T')[0]}`)) { - setCurrentData(dataLastDayThreshold as unknown as LineChartData); - - return; - } - if (start.includes(defaultLast7days.split('T')[0])) { - setCurrentData(dataLastWeek as unknown as LineChartData); - - return; - } - if (start.includes(defaultLastMonth.split('T')[0])) { - setCurrentData(dataLastMonth as unknown as LineChartData); - - return; - } - if (start.includes(zoomPreviewDate)) { - setCurrentData(dataZoomPreview as unknown as LineChartData); - } - }, [start, end, adjustedTimePeriodInterval]); - - const getInterval = (interval: Interval): void => { - setAdjustedTimePeriodInterval(interval); - }; - - const getDataSwitch = (value): void => { - setDisplayAnnotation(value); - }; - - const annotationEventData = displayAnnotation && { - data: annotationData.result - }; - - return ( - <> - - } - /> - ( - - ) - }} - zoomPreview={{ enable: true, getInterval }} - /> - - ); -}; - -const LineChartAndExclusionPeriod = (args): JSX.Element => { - const [dataExclusionPeriods, setDataExclusionPeriods] = useState< - Array - >([exclusionPeriodFirstPeriod as unknown as LineChartData]); - - const handleClick = (data): void => { - setDataExclusionPeriods([...dataExclusionPeriods, data]); - }; - - return ( - <> -
Add exclusion periods:
- - - - - - - ); -}; - -const Template: Story = { - render: (args) => ( - - ) -}; - -const WithTimePeriod = { - render: (args): JSX.Element => -}; - -const LineChartWithExclusionPeriod: Story = { - render: (args) => -}; - -const LineChartWithEnvelopVariation: Story = { - render: (args) => -}; - -const LineChartWithCLS: Story = { - render: (args) => -}; - -export const LineChart: Story = { - ...Template, - argTypes, - args: argumentsData -}; - -export const LineChartWithStepCurve: Story = { - ...Template, - argTypes, - args: { - ...argumentsData, - curve: 'step' - } -}; - -export const LineChartWithTimePeriod: Story = { - ...WithTimePeriod, - args: { - end: defaultEnd, - height: 500, - start: defaultStart - }, - parameters: { - chromatic: { disableSnapshot: true } - } -}; - -export const WithEnvelopVariation: Story = { - ...LineChartWithEnvelopVariation, - args: { - end: defaultEnd, - height: 500, - start: defaultStart - } -}; - -export const withExclusionPeriods: Story = { - ...LineChartWithExclusionPeriod, - args: { - end: defaultEnd, - height: 500, - start: defaultStart - } -}; - -export const withCLS: Story = { - ...LineChartWithCLS, - args: { - end: defaultEnd, - height: 500, - start: defaultStart - } -}; - -export const withThresholds: Story = { - argTypes, - args: { - ...argumentsData, - thresholds: { - critical: [ - { - label: 'critical', - value: 350 - } - ], - enabled: true, - warning: [ - { - label: 'warning', - value: 300 - } - ] - } - }, - render: (args) => ( - - ) -}; - -export const withThresholdsAndUnit: Story = { - argTypes, - args: { - ...argumentsData, - thresholdUnit: '%', - thresholds: { - critical: [ - { - label: 'critical', - value: 79 - } - ], - enabled: true, - warning: [ - { - label: 'warning', - value: 65 - } - ] - } - }, - render: (args) => ( - - ) -}; - -export const thresholdsRange: Story = { - argTypes, - args: { - ...argumentsData, - thresholdUnit: '%', - thresholds: { - critical: [ - { - label: 'critical 1', - value: 60 - }, - { - label: 'critical 2', - value: 79 - } - ], - enabled: true, - warning: [ - { - label: 'warning 1', - value: 20 - }, - { - label: 'warning 2', - value: 30 - } - ] - } - }, - render: (args) => ( - - ) -}; - -export const LineChartWithSameColorCurves: Story = { - ...Template, - argTypes, - args: { - ...argumentsData, - lineStyle: { - areaTransparency: 10, - dashLength: 10, - dashOffset: 10, - lineWidth: 9, - showArea: true, - showPoints: true - } - }, - render: (args) => ( - - ) -}; diff --git a/centreon/packages/ui/src/Graph/LineChart/index.tsx b/centreon/packages/ui/src/Graph/LineChart/index.tsx deleted file mode 100644 index fa20058c80..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/index.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { MutableRefObject, useRef } from 'react'; - -import dayjs from 'dayjs'; -import 'dayjs/locale/en'; -import 'dayjs/locale/es'; -import 'dayjs/locale/fr'; -import 'dayjs/locale/pt'; -import localizedFormat from 'dayjs/plugin/localizedFormat'; -import timezonePlugin from 'dayjs/plugin/timezone'; -import utcPlugin from 'dayjs/plugin/utc'; - -import { ParentSize } from '../..'; -import { LineChartData, Thresholds } from '../common/models'; - -import LineChart from './LineChart'; -import LoadingSkeleton from './LoadingSkeleton'; -import { GlobalAreaLines, LineChartProps } from './models'; -import useLineChartData from './useLineChartData'; - -dayjs.extend(localizedFormat); -dayjs.extend(utcPlugin); -dayjs.extend(timezonePlugin); - -interface Props extends Partial { - data?: LineChartData; - end: string; - limitLegend?: false | number; - loading: boolean; - shapeLines?: GlobalAreaLines; - start: string; - thresholdUnit?: string; - thresholds?: Thresholds; -} - -const WrapperLineChart = ({ - end, - start, - height = 500, - width, - shapeLines, - axis, - displayAnchor, - zoomPreview, - data, - loading, - timeShiftZones, - tooltip = { - mode: 'all', - sortOrder: 'name' - }, - annotationEvent, - legend = { - display: true, - mode: 'grid', - placement: 'bottom' - }, - header, - lineStyle, - thresholds, - thresholdUnit, - limitLegend -}: Props): JSX.Element | null => { - const { adjustedData } = useLineChartData({ data, end, start }); - const lineChartRef = useRef(null); - - if (loading && !adjustedData) { - return ( - - ); - } - - if (!adjustedData) { - return null; - } - - return ( -
} - style={{ height: '100%', overflow: 'hidden', width: '100%' }} - > - - {({ - height: responsiveHeight, - width: responsiveWidth - }): JSX.Element => { - return ( - - ); - }} - -
- ); -}; - -export default WrapperLineChart; diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/annotationData.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/annotationData.json deleted file mode 100644 index 1ac3819318..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/annotationData.json +++ /dev/null @@ -1,326 +0,0 @@ - -{ - "result": [ - { - "id": 78662735, - "type": "comment", - "date": "2023-06-07T20:07:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 85.149% (memory used)", - "contact": "nouha", - "status": { - "code": 0, - "name": "OK", - "severity_code": 5 - }, - "tries": 1 - }, - { - "id": 78662642, - "type": "comment", - "date": "2023-06-07T19:57:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 84.908% (memory used)", - "contact": "nouha", - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 3 - }, - { - "id": 78662621, - "type": "comment", - "date": "2023-06-07T19:56:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 82.956% (memory used)", - "contact": "nouha", - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 2 - }, - { - "id": 78662612, - "type": "downtime", - "date": "2023-06-07T19:55:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 84.341% (memory used)", - "contact": "nouha", - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 1 - }, - { - "id": 78662414, - "type": "downtime", - "date": "2023-06-07T19:45:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 85.217% (memory used)", - "contact": null, - "status": { - "code": 0, - "name": "OK", - "severity_code": 5 - }, - "tries": 1 - }, - { - "id": 78661672, - "type": "downtime", - "date": "2023-06-07T19:05:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 84.467% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 3 - }, - { - "id": 78661660, - "type": "acknowledgement", - "date": "2023-06-07T19:04:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 83.731% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 2 - }, - { - "id": 78661625, - "type": "acknowledgement", - "date": "2023-06-07T19:03:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 84.825% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 1 - }, - { - "id": 78659281, - "type": "acknowledgement", - "date": "2023-06-07T17:18:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 86.132% (memory used)", - "contact": null, - "status": { - "code": 0, - "name": "OK", - "severity_code": 5 - }, - "tries": 1 - }, - { - "id": 78658829, - "type": "acknowledgement", - "date": "2023-06-07T16:58:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 82.638% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 3 - }, - { - "id": 78658821, - "type": "event", - "date": "2023-06-07T16:57:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 83.353% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 2 - }, - { - "id": 78658804, - "type": "event", - "date": "2023-06-07T16:56:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 84.231% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 1 - }, - { - "id": 78658665, - "type": "event", - "date": "2023-06-07T16:51:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 85.792% (memory used)", - "contact": null, - "status": { - "code": 0, - "name": "OK", - "severity_code": 5 - }, - "tries": 1 - }, - { - "id": 78650736, - "type": "event", - "date": "2023-06-07T11:06:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 81.780% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 3 - }, - { - "id": 78650731, - "type": "event", - "date": "2023-06-07T11:05:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 82.828% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 2 - }, - { - "id": 78650689, - "type": "event", - "date": "2023-06-07T11:04:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 84.561% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 1 - }, - { - "id": 78650260, - "type": "event", - "date": "2023-06-07T10:44:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 85.529% (memory used)", - "contact": null, - "status": { - "code": 0, - "name": "OK", - "severity_code": 5 - }, - "tries": 1 - }, - { - "id": 78650158, - "type": "event", - "date": "2023-06-07T10:39:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 84.905% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 3 - }, - { - "id": 78650096, - "type": "event", - "date": "2023-06-07T10:38:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 84.210% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 2 - }, - { - "id": 78650057, - "type": "event", - "date": "2023-06-07T10:37:28+02:00", - "start_date": null, - "end_date": null, - "content": "Shared pool hit ratio = 83.771% (memory used)", - "contact": null, - "status": { - "code": 1, - "name": "WARNING", - "severity_code": 2 - }, - "tries": 1 - } - ], - "meta": { - "page": 1, - "limit": 20, - "search": { - "$and": [ - { - "date": { - "$gt": "2023-06-06T19:27:15.554Z" - } - }, - { - "date": { - "$lt": "2023-06-07T19:27:15.554Z" - } - } - ] - }, - "sort_by": {}, - "total": 44 - } -} - diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodFirstPeriod.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodFirstPeriod.json deleted file mode 100644 index 014cca593a..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodFirstPeriod.json +++ /dev/null @@ -1,588 +0,0 @@ -{ - "global": { - "title": "anomaly-nbr-connect graph on fw-brasilia", - "start": "2023-06-14T21:02:27+02:00", - "end": "2023-06-15T00:02:58+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 1, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 152032, - "metric_id": 15165, - "metric": "connection", - "metric_legend": "connection", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#993366" - }, - "legend": "connection", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 22.203333333, - 27.576666667, - 27.406666667, - 22.22, - 25.78, - 15.846666667, - 15.39, - 22.373333333, - 20.813333333, - 23.983333333, - 28.186666667, - 26.61, - 26, - 22.813333333, - 18.016666667, - 13.813333333, - 16.186666667, - 17.796666667, - 21.983333333, - 14.236666667, - 23.153333333, - 17.236666667, - 15, - 20.576666667, - 22.796666667, - 27.78, - 28.203333333, - 27.203333333, - 14.253333333, - 13.39, - 21.17, - 19.813333333, - 22.186666667, - 14.236666667, - 22.356666667, - 15.44, - 14.593333333 - ], - "prints": [ - [ - "Last:14.59" - ], - [ - "Min:13.39" - ], - [ - "Max:28.20" - ], - [ - "Average:20.77" - ] - ], - "last_value": 14.59, - "minimum_value": 13.39, - "maximum_value": 28.2, - "average_value": 20.77 - }, - { - "index_id": 152032, - "metric_id": 16196, - "metric": "connection_fit", - "metric_legend": "connection_fit", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#9933ff" - }, - "legend": "connection_fit", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.139333333, - 19.3473, - 19.493566667, - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.139333333, - 19.3473, - 19.493566667, - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.139333333, - 19.3473, - 19.493566667, - 19.3527 - ], - "prints": [ - [ - "Last:19.35" - ], - [ - "Min:18.93" - ], - [ - "Max:19.49" - ], - [ - "Average:19.10" - ] - ], - "last_value": 19.35, - "minimum_value": 18.93, - "maximum_value": 19.49, - "average_value": 19.1 - }, - { - "index_id": 152032, - "metric_id": 16197, - "metric": "connection_lower_margin", - "metric_legend": "connection_lower_margin", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#00ff99" - }, - "legend": "connection_lower_margin", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88 - ], - "prints": [ - [ - "Last:-17.88" - ], - [ - "Min:-17.88" - ], - [ - "Max:-17.88" - ], - [ - "Average:-17.88" - ] - ], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - }, - { - "index_id": 152032, - "metric_id": 16198, - "metric": "connection_upper_margin", - "metric_legend": "connection_upper_margin", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#9900ff" - }, - "legend": "connection_upper_margin", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15 - ], - "prints": [ - [ - "Last:10.15" - ], - [ - "Min:10.15" - ], - [ - "Max:10.15" - ], - [ - "Average:10.15" - ] - ], - "last_value": 10.15, - "minimum_value": 10.15, - "maximum_value": 10.15, - "average_value": 10.15 - }, - { - "index_id": 152032, - "metric_id": 15177, - "metric": "connection_lower_thresholds", - "metric_legend": "connection_lower_thresholds", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 50, - "host_id": null, - "service_id": null, - "name": "Anomaly Lower Threshold", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": ".*_lower_thresholds", - "ds_color_line": "#D728C9", - "ds_color_line_mode": "0", - "ds_color_area": "#FFFFFF", - "ds_color_area_warn": "#F8C706", - "ds_color_area_crit": "#F91E05", - "ds_filled": null, - "ds_max": null, - "ds_min": null, - "ds_minmax_int": null, - "ds_average": null, - "ds_last": null, - "ds_total": null, - "ds_tickness": 2, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": "Lower Threshold", - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "Lower Threshold", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.4927, - -34.2827, - -34.1444, - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.4927, - -34.2827, - -34.1444, - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.4927, - -34.2827, - -34.1444, - -34.2873 - ], - "prints": [], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - }, - { - "index_id": 152032, - "metric_id": 15178, - "metric": "connection_upper_thresholds", - "metric_legend": "connection_upper_thresholds", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 51, - "host_id": null, - "service_id": null, - "name": "Anomaly Upper Threshold", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": ".*_upper_thresholds", - "ds_color_line": "#D728C9", - "ds_color_line_mode": "0", - "ds_color_area": "#FFFFFF", - "ds_color_area_warn": "#F8C706", - "ds_color_area_crit": "#F91E05", - "ds_filled": null, - "ds_max": null, - "ds_min": null, - "ds_minmax_int": null, - "ds_average": null, - "ds_last": null, - "ds_total": null, - "ds_tickness": 2, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": "Upper Threshold", - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "Upper Threshold", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.421866667, - 49.5973, - 49.8073, - 49.9456, - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.421866667, - 49.5973, - 49.8073, - 49.9456, - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.421866667, - 49.5973, - 49.8073, - 49.9456, - 49.810666667 - ], - "prints": [], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - } - ], - "times": [ - "2023-06-14T21:05:00+02:00", - "2023-06-14T21:10:00+02:00", - "2023-06-14T21:15:00+02:00", - "2023-06-14T21:20:00+02:00", - "2023-06-14T21:25:00+02:00", - "2023-06-14T21:30:00+02:00", - "2023-06-14T21:35:00+02:00", - "2023-06-14T21:40:00+02:00", - "2023-06-14T21:45:00+02:00", - "2023-06-14T21:50:00+02:00", - "2023-06-14T21:55:00+02:00", - "2023-06-14T22:00:00+02:00", - "2023-06-14T22:05:00+02:00", - "2023-06-14T22:10:00+02:00", - "2023-06-14T22:15:00+02:00", - "2023-06-14T22:20:00+02:00", - "2023-06-14T22:25:00+02:00", - "2023-06-14T22:30:00+02:00", - "2023-06-14T22:35:00+02:00", - "2023-06-14T22:40:00+02:00", - "2023-06-14T22:45:00+02:00", - "2023-06-14T22:50:00+02:00", - "2023-06-14T22:55:00+02:00", - "2023-06-14T23:00:00+02:00", - "2023-06-14T23:05:00+02:00", - "2023-06-14T23:10:00+02:00", - "2023-06-14T23:15:00+02:00", - "2023-06-14T23:20:00+02:00", - "2023-06-14T23:25:00+02:00", - "2023-06-14T23:30:00+02:00", - "2023-06-14T23:35:00+02:00", - "2023-06-14T23:40:00+02:00", - "2023-06-14T23:45:00+02:00", - "2023-06-14T23:50:00+02:00", - "2023-06-14T23:55:00+02:00", - "2023-06-15T00:00:00+02:00", - "2023-06-15T00:05:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodSecondPeriod.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodSecondPeriod.json deleted file mode 100644 index 49d85042b9..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodSecondPeriod.json +++ /dev/null @@ -1,588 +0,0 @@ -{ - "global": { - "title": "anomaly-nbr-connect graph on fw-brasilia", - "start": "2023-06-15T12:02:17+02:00", - "end": "2023-06-15T15:00:01+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 1, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 152032, - "metric_id": 15165, - "metric": "connection", - "metric_legend": "connection", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#993366" - }, - "legend": "connection", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 90.506666667, - 124.84, - 131.21333333, - 175.1, - 155.07333333, - 116.39333333, - 101.31333333, - 141.41333333, - 156.46, - 131.38, - 162.25333333, - 182.70666667, - 181.82, - 124.62, - 96.646666667, - 96.413333333, - 124.22, - 146.96666667, - 140.75333333, - 106.12, - 144.83333333, - 152.43333333, - 97.293333333, - 96.44, - 142.32, - 142.33333333, - 103.74, - 118.54, - 145.55333333, - 122.16666667, - 109.15333333, - 134.74666667, - 117.19333333, - 122.83333333, - 152.28, - 170.50666667, - 93.506666667 - ], - "prints": [ - [ - "Last:93.51" - ], - [ - "Min:90.51" - ], - [ - "Max:182.71" - ], - [ - "Average:131.14" - ] - ], - "last_value": 93.51, - "minimum_value": 90.51, - "maximum_value": 182.71, - "average_value": 131.14 - }, - { - "index_id": 152032, - "metric_id": 16196, - "metric": "connection_fit", - "metric_legend": "connection_fit", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#9933ff" - }, - "legend": "connection_fit", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 131.36, - 131.36, - 131.35613333, - 131.3342, - 131.3042, - 131.2974, - 131.38933333, - 131.49126667, - 131.57226667, - 131.52453333, - 131.4426, - 131.36806667, - 131.36, - 131.36, - 131.35613333, - 131.3342, - 131.3042, - 131.2974, - 131.38933333, - 131.49126667, - 131.57226667, - 131.52453333, - 131.4426, - 131.36806667, - 131.36, - 131.36, - 131.35613333, - 131.3342, - 131.3042, - 131.2974, - 131.38933333, - 131.49126667, - 131.59546667, - 131.67353333, - 131.7416, - 131.79193333, - 131.8 - ], - "prints": [ - [ - "Last:131.80" - ], - [ - "Min:131.30" - ], - [ - "Max:131.80" - ], - [ - "Average:131.44" - ] - ], - "last_value": 131.8, - "minimum_value": 131.3, - "maximum_value": 131.8, - "average_value": 131.44 - }, - { - "index_id": 152032, - "metric_id": 16197, - "metric": "connection_lower_margin", - "metric_legend": "connection_lower_margin", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#00ff99" - }, - "legend": "connection_lower_margin", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84 - ], - "prints": [ - [ - "Last:-92.84" - ], - [ - "Min:-92.84" - ], - [ - "Max:-92.84" - ], - [ - "Average:-92.84" - ] - ], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - }, - { - "index_id": 152032, - "metric_id": 16198, - "metric": "connection_upper_margin", - "metric_legend": "connection_upper_margin", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#9900ff" - }, - "legend": "connection_upper_margin", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19 - ], - "prints": [ - [ - "Last:80.19" - ], - [ - "Min:80.19" - ], - [ - "Max:80.19" - ], - [ - "Average:80.19" - ] - ], - "last_value": 80.19, - "minimum_value": 80.19, - "maximum_value": 80.19, - "average_value": 80.19 - }, - { - "index_id": 152032, - "metric_id": 15177, - "metric": "connection_lower_thresholds", - "metric_legend": "connection_lower_thresholds", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 50, - "host_id": null, - "service_id": null, - "name": "Anomaly Lower Threshold", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": ".*_lower_thresholds", - "ds_color_line": "#D728C9", - "ds_color_line_mode": "0", - "ds_color_area": "#FFFFFF", - "ds_color_area_warn": "#F8C706", - "ds_color_area_crit": "#F91E05", - "ds_filled": null, - "ds_max": null, - "ds_min": null, - "ds_minmax_int": null, - "ds_average": null, - "ds_last": null, - "ds_total": null, - "ds_tickness": 2, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": "Lower Threshold", - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "Lower Threshold", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - -147.17, - -147.17, - -147.17386667, - -147.1958, - -147.22386667, - -147.22453333, - -147.13873333, - -147.02873333, - -146.94966667, - -147.00546667, - -147.08546667, - -147.15386667, - -147.17, - -147.17, - -147.17386667, - -147.1958, - -147.22386667, - -147.22453333, - -147.13873333, - -147.02873333, - -146.94966667, - -147.00546667, - -147.08546667, - -147.15386667, - -147.17, - -147.17, - -147.17386667, - -147.1958, - -147.22386667, - -147.22453333, - -147.13873333, - -147.02873333, - -146.92453333, - -146.8484, - -146.78646667, - -146.72806667, - -146.72 - ], - "prints": [], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - }, - { - "index_id": 152032, - "metric_id": 15178, - "metric": "connection_upper_thresholds", - "metric_legend": "connection_upper_thresholds", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 51, - "host_id": null, - "service_id": null, - "name": "Anomaly Upper Threshold", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": ".*_upper_thresholds", - "ds_color_line": "#D728C9", - "ds_color_line_mode": "0", - "ds_color_area": "#FFFFFF", - "ds_color_area_warn": "#F8C706", - "ds_color_area_crit": "#F91E05", - "ds_filled": null, - "ds_max": null, - "ds_min": null, - "ds_minmax_int": null, - "ds_average": null, - "ds_last": null, - "ds_total": null, - "ds_tickness": 2, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": "Upper Threshold", - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "Upper Threshold", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - 371.92, - 371.92, - 371.91613333, - 371.8942, - 371.8642, - 371.8574, - 371.95126667, - 372.06126667, - 372.14033333, - 372.08453333, - 372.0026, - 371.92806667, - 371.92, - 371.92, - 371.91613333, - 371.8942, - 371.8642, - 371.8574, - 371.95126667, - 372.06126667, - 372.14033333, - 372.08453333, - 372.0026, - 371.92806667, - 371.92, - 371.92, - 371.91613333, - 371.8942, - 371.8642, - 371.8574, - 371.95126667, - 372.06126667, - 372.16353333, - 372.23353333, - 372.3016, - 372.35386667, - 372.37 - ], - "prints": [], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - } - ], - "times": [ - "2023-06-15T12:05:00+02:00", - "2023-06-15T12:10:00+02:00", - "2023-06-15T12:15:00+02:00", - "2023-06-15T12:20:00+02:00", - "2023-06-15T12:25:00+02:00", - "2023-06-15T12:30:00+02:00", - "2023-06-15T12:35:00+02:00", - "2023-06-15T12:40:00+02:00", - "2023-06-15T12:45:00+02:00", - "2023-06-15T12:50:00+02:00", - "2023-06-15T12:55:00+02:00", - "2023-06-15T13:00:00+02:00", - "2023-06-15T13:05:00+02:00", - "2023-06-15T13:10:00+02:00", - "2023-06-15T13:15:00+02:00", - "2023-06-15T13:20:00+02:00", - "2023-06-15T13:25:00+02:00", - "2023-06-15T13:30:00+02:00", - "2023-06-15T13:35:00+02:00", - "2023-06-15T13:40:00+02:00", - "2023-06-15T13:45:00+02:00", - "2023-06-15T13:50:00+02:00", - "2023-06-15T13:55:00+02:00", - "2023-06-15T14:00:00+02:00", - "2023-06-15T14:05:00+02:00", - "2023-06-15T14:10:00+02:00", - "2023-06-15T14:15:00+02:00", - "2023-06-15T14:20:00+02:00", - "2023-06-15T14:25:00+02:00", - "2023-06-15T14:30:00+02:00", - "2023-06-15T14:35:00+02:00", - "2023-06-15T14:40:00+02:00", - "2023-06-15T14:45:00+02:00", - "2023-06-15T14:50:00+02:00", - "2023-06-15T14:55:00+02:00", - "2023-06-15T15:00:00+02:00", - "2023-06-15T15:05:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodThirdPeriod.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodThirdPeriod.json deleted file mode 100644 index 5487f34502..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/exclusionPeriodThirdPeriod.json +++ /dev/null @@ -1,581 +0,0 @@ -{ - "global": { - "title": "anomaly-nbr-connect graph on fw-brasilia", - "start": "2023-06-15T06:00:41+02:00", - "end": "2023-06-15T08:58:26+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 1, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 152032, - "metric_id": 15165, - "metric": "connection", - "metric_legend": "connection", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#993366" - }, - "legend": "connection", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 11, - 18.933333333, - 25.76, - 15.1, - 15.173333333, - 21.553333333, - 27.76, - 24.24, - 15.86, - 17.966666667, - 24.553333333, - 16.48, - 24.313333333, - 22.24, - 22.586666667, - 27.76, - 18.686666667, - 19.966666667, - 23.38, - 13.686666667, - 23.693333333, - 23.033333333, - 25.173333333, - 22.826666667, - 19.62, - 11.86, - 17.14, - 18.206666667, - 19.586666667, - 26.346666667, - 28.793333333, - 18.686666667, - 11.24, - 16.346666667, - 15.62, - 83.226666667 - ], - "prints": [ - [ - "Last:83.23" - ], - [ - "Min:11.00" - ], - [ - "Max:83.23" - ], - [ - "Average:21.90" - ] - ], - "last_value": 83.23, - "minimum_value": 11, - "maximum_value": 83.23, - "average_value": 21.9 - }, - { - "index_id": 152032, - "metric_id": 16196, - "metric": "connection_fit", - "metric_legend": "connection_fit", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#9933ff" - }, - "legend": "connection_fit", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 19.97, - 19.97, - 19.97, - 19.977933333, - 19.987933333, - 20.005866667, - 20.065533333, - 20.1276, - 20.179666667, - 20.150333333, - 20.108266667, - 20.0762, - 20.07, - 20.07, - 20.07, - 20.077933333, - 20.087933333, - 20.105866667, - 20.165533333, - 20.2276, - 20.24, - 20.041666667, - 19.783733333, - 19.571333333, - 19.53, - 19.53, - 19.537933333, - 19.547933333, - 19.557933333, - 19.567933333, - 19.5938, - 19.631733333, - 19.8304, - 20.7368, - 21.808866667, - 27.519866667 - ], - "prints": [ - [ - "Last:27.52" - ], - [ - "Min:19.53" - ], - [ - "Max:27.52" - ], - [ - "Average:20.21" - ] - ], - "last_value": 27.52, - "minimum_value": 19.53, - "maximum_value": 27.52, - "average_value": 20.21 - }, - { - "index_id": 152032, - "metric_id": 16197, - "metric": "connection_lower_margin", - "metric_legend": "connection_lower_margin", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#00ff99" - }, - "legend": "connection_lower_margin", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -21.9736 - ], - "prints": [ - [ - "Last:-21.97" - ], - [ - "Min:-21.97" - ], - [ - "Max:-17.88" - ], - [ - "Average:-17.99" - ] - ], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - }, - { - "index_id": 152032, - "metric_id": 16198, - "metric": "connection_upper_margin", - "metric_legend": "connection_upper_margin", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#9900ff" - }, - "legend": "connection_upper_margin", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 13.9818 - ], - "prints": [ - [ - "Last:13.98" - ], - [ - "Min:10.15" - ], - [ - "Max:13.98" - ], - [ - "Average:10.26" - ] - ], - "last_value": 13.98, - "minimum_value": 10.15, - "maximum_value": 13.98, - "average_value": 10.26 - }, - { - "index_id": 152032, - "metric_id": 15177, - "metric": "connection_lower_thresholds", - "metric_legend": "connection_lower_thresholds", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 50, - "host_id": null, - "service_id": null, - "name": "Anomaly Lower Threshold", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": ".*_lower_thresholds", - "ds_color_line": "#D728C9", - "ds_color_line_mode": "0", - "ds_color_area": "#FFFFFF", - "ds_color_area_warn": "#F8C706", - "ds_color_area_crit": "#F91E05", - "ds_filled": null, - "ds_max": null, - "ds_min": null, - "ds_minmax_int": null, - "ds_average": null, - "ds_last": null, - "ds_total": null, - "ds_tickness": 2, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": "Lower Threshold", - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "Lower Threshold", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - -33.67, - -33.67, - -33.67, - -33.662066667, - -33.652066667, - -33.6262, - -33.5724, - -33.504466667, - -33.458266667, - -33.481733333, - -33.529666667, - -33.5638, - -33.57, - -33.57, - -33.57, - -33.562066667, - -33.552066667, - -33.5262, - -33.4724, - -33.404466667, - -33.39, - -33.596266667, - -33.848333333, - -34.058666667, - -34.1, - -34.1, - -34.1, - -34.092066667, - -34.082066667, - -34.064133333, - -34.0362, - -34.0062, - -33.801666667, - -32.901133333, - -31.831133333, - -38.408866667 - ], - "prints": [], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - }, - { - "index_id": 152032, - "metric_id": 15178, - "metric": "connection_upper_thresholds", - "metric_legend": "connection_upper_thresholds", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 51, - "host_id": null, - "service_id": null, - "name": "Anomaly Upper Threshold", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": ".*_upper_thresholds", - "ds_color_line": "#D728C9", - "ds_color_line_mode": "0", - "ds_color_area": "#FFFFFF", - "ds_color_area_warn": "#F8C706", - "ds_color_area_crit": "#F91E05", - "ds_filled": null, - "ds_max": null, - "ds_min": null, - "ds_minmax_int": null, - "ds_average": null, - "ds_last": null, - "ds_total": null, - "ds_tickness": 2, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": "Upper Threshold", - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "Upper Threshold", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - 50.42, - 50.42, - 50.427933333, - 50.437933333, - 50.447933333, - 50.465866667, - 50.525533333, - 50.5876, - 50.631733333, - 50.608266667, - 50.568266667, - 50.528266667, - 50.52, - 50.52, - 50.527933333, - 50.537933333, - 50.547933333, - 50.565866667, - 50.625533333, - 50.6876, - 50.7, - 50.501666667, - 50.243733333, - 50.031333333, - 49.99, - 49.99, - 49.99, - 49.997933333, - 50.007933333, - 50.025866667, - 50.0538, - 50.0838, - 50.288333333, - 51.188866667, - 52.2668, - 69.4594 - ], - "prints": [], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - } - ], - "times": [ - "2023-06-15T06:05:00+02:00", - "2023-06-15T06:10:00+02:00", - "2023-06-15T06:15:00+02:00", - "2023-06-15T06:20:00+02:00", - "2023-06-15T06:25:00+02:00", - "2023-06-15T06:30:00+02:00", - "2023-06-15T06:35:00+02:00", - "2023-06-15T06:40:00+02:00", - "2023-06-15T06:45:00+02:00", - "2023-06-15T06:50:00+02:00", - "2023-06-15T06:55:00+02:00", - "2023-06-15T07:00:00+02:00", - "2023-06-15T07:05:00+02:00", - "2023-06-15T07:10:00+02:00", - "2023-06-15T07:15:00+02:00", - "2023-06-15T07:20:00+02:00", - "2023-06-15T07:25:00+02:00", - "2023-06-15T07:30:00+02:00", - "2023-06-15T07:35:00+02:00", - "2023-06-15T07:40:00+02:00", - "2023-06-15T07:45:00+02:00", - "2023-06-15T07:50:00+02:00", - "2023-06-15T07:55:00+02:00", - "2023-06-15T08:00:00+02:00", - "2023-06-15T08:05:00+02:00", - "2023-06-15T08:10:00+02:00", - "2023-06-15T08:15:00+02:00", - "2023-06-15T08:20:00+02:00", - "2023-06-15T08:25:00+02:00", - "2023-06-15T08:30:00+02:00", - "2023-06-15T08:35:00+02:00", - "2023-06-15T08:40:00+02:00", - "2023-06-15T08:45:00+02:00", - "2023-06-15T08:50:00+02:00", - "2023-06-15T08:55:00+02:00", - "2023-06-15T09:00:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDay.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDay.json deleted file mode 100644 index 9cff4d3e4f..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDay.json +++ /dev/null @@ -1,1326 +0,0 @@ -{ - "global": { - "title": "oracle-buffer-hit-ratio graph on srv-oracle-users", - "start": "2023-06-18T17:04:46+02:00", - "end": "2023-06-19T17:04:46+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 0, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 5614, - "metric_id": 13536, - "metric": "connTime", - "metric_legend": "connTime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#6699cc" - }, - "legend": "connTime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 0.53123333333, - 0.56452, - 0.5341, - 0.51537666667, - 0.25730333333, - 0.48611333333, - 0.41435666667, - 0.42371, - 0.55438333333, - 0.60211, - 0.72619, - 0.67167333333, - 0.63883333333, - 0.52027666667, - 0.67368666667, - 0.83443333333, - 0.86102333333, - 0.76291666667, - 0.39081666667, - 0.22492333333, - 0.64388333333, - 0.81007666667, - 0.61811333333, - 0.58901, - 0.58737333333, - 0.60651333333, - 0.74783333333, - 0.92823, - 0.89503333333, - 0.82551333333, - 0.75017333333, - 0.33549666667, - 0.40213666667, - 0.60645666667, - 0.55312666667, - 0.31503666667, - 0.078203333333, - 0.44113, - 0.35953666667, - 0.41073333333, - 0.8358, - 0.86683333333, - 0.68390666667, - 0.28047333333, - 0.0607, - 0.49994666667, - 0.75459666667, - 0.51677333333, - 0.63137, - 0.74141666667, - 0.60566666667, - 0.32040666667, - 0.15528666667, - 0.43645333333, - 0.65261666667, - 0.46921666667, - 0.60091666667, - 0.47360333333, - 0.10643, - 0.29183, - 0.35995, - 0.40254333333, - 0.58827666667, - 0.45241333333, - 0.24455333333, - 0.18674, - 0.13640333333, - 0.34897666667, - 0.55044, - 0.52277666667, - 0.69064333333, - 0.56236333333, - 0.39762, - 0.65475666667, - 0.58477, - 0.49433, - 0.28894333333, - 0.49294333333, - 0.64683, - 0.35607666667, - 0.55465, - 0.45637333333, - 0.54171666667, - 0.42502666667, - 0.30588, - 0.32094, - 0.22269333333, - 0.44262, - 0.62073333333, - 0.60227666667, - 0.32498333333, - 0.25148, - 0.47383333333, - 0.30778333333, - 0.26413666667, - 0.58817, - 0.42611, - 0.44147, - 0.70327, - 0.61590333333, - 0.67324333333, - 0.71732333333, - 0.38394, - 0.23022, - 0.32007333333, - 0.37968, - 0.32084666667, - 0.54738333333, - 0.85402666667, - 0.72061666667, - 0.69251666667, - 0.87611666667, - 0.83591333333, - 0.36148, - 0.45470333333, - 0.68843, - 0.52516, - 0.50904666667, - 0.51209333333, - 0.6553, - 0.85674333333, - 0.51166, - 0.4353, - 0.76875333333, - 0.78365666667, - 0.71250666667, - 0.81178666667, - 0.67356666667, - 0.48919333333, - 0.55755, - 0.50259333333, - 0.28751333333, - 0.56895666667, - 0.46348666667, - 0.065866666667, - 0.56505666667, - 0.90545333333, - 0.80578666667, - 0.5926, - 0.60521333333, - 0.80492333333, - 0.46766666667, - 0.45899, - 0.67702333333, - 0.35113666667, - 0.47643666667, - 0.71041666667, - 0.55792, - 0.73992, - 0.76518, - 0.35002333333, - 0.26003, - 0.55407333333, - 0.76546333333, - 0.37679, - 0.067946666667, - 0.34679, - 0.26, - 0.66257333333, - 0.40848, - 0.53458333333, - 0.51552, - 0.61109, - 0.85858333333, - 0.68362, - 0.27503333333, - 0.2019, - 0.13221333333, - 0.79457, - 0.69949666667, - 0.35275333333, - 0.81529, - 0.078553333333, - 0.03339, - 0.39325333333, - 0.40176333333, - 0.14054333333, - 0.32028666667, - 0.33053666667, - 0.89415666667, - 0.35837666667, - 0.85846, - 0.44418, - 0.29612333333, - 0.84746333333, - 0.69179, - 0.15608666667, - 0.46017333333, - 0.52039333333, - 0.04379, - 0.20713333333, - 0.69767, - 0.073123333333, - 0.72342666667, - 0.16706, - 0.56104666667, - 0.7642, - 0.84448, - 0.12149, - 0.84398666667, - 0.17495, - 0.73171, - 0.31948666667, - 0.86547, - 0.51050333333, - 0.73184, - 0.24332, - 0.64512333333, - 0.87497666667, - 0.64631666667, - 0.93808666667, - 0.40630666667, - 0.58898666667, - 0.079853333333, - 0.52536666667, - 0.24560333333, - 0.08881, - 0.59968333333, - 0.76672666667, - 0.12605, - 0.57891, - 0.3994, - 0.93223, - 0.91706, - 0.73287333333, - 0.35697666667, - 0.76189, - 0.53946666667, - 0.80423333333, - 0.89725, - 0.11539666667, - 0.29745333333, - 0.77966666667, - 0.71089333333, - 0.26618666667, - 0.66581333333, - 0.72693, - 0.2858, - 0.21299, - 0.19799666667, - 0.73068666667, - 0.48692, - 0.5738, - 0.060393333333, - 0.36694333333, - 0.29905, - 0.70373, - 0.59026666667, - 0.95010333333, - 0.96899666667, - 0.18778333333, - 0.44893666667, - 0.54063333333, - 0.30962666667, - 0.67226, - 0.8979, - 0.61484, - 0.75435333333, - 0.21677, - 0.25687, - 0.73120666667, - 0.20676666667, - 0.32435333333, - 0.44787666667, - 0.89004333333, - 0.48926333333, - 0.36620666667, - 0.53720333333, - 0.77175333333, - 0.81031333333, - 0.68735, - 0.29566333333, - 0.64441333333, - 0.53196, - 0.57447666667, - 0.050853333333, - 0.28769333333, - 0.17988666667, - 0.10621333333, - 0.49249333333, - 0.81975, - 0.48222, - 0.25617333333, - 0.75395, - 0.36961, - 0.53932333333, - 0.65789666667, - 0.32339333333, - null - ], - "prints": [ - [ - "Last:0.32" - ], - [ - "Min:0.03" - ], - [ - "Max:0.97" - ], - [ - "Average:0.51" - ] - ], - "last_value": 0.32, - "minimum_value": 0.03, - "maximum_value": 0.97, - "average_value": 0.51 - }, - { - "index_id": 5614, - "metric_id": 13534, - "metric": "hitratio", - "metric_legend": "hitratio", - "unit": "%", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#cc9999" - }, - "legend": "hitratio", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 80.192446667, - 80.324963333, - 80.31374, - 80.043863333, - 78.97382, - 78.01196, - 77.85379, - 77.311446667, - 77.518806667, - 77.363833333, - 76.410303333, - 75.385206667, - 75.470793333, - 75.444866667, - 74.902366667, - 74.787096667, - 73.424696667, - 72.984073333, - 73.127803333, - 72.06457, - 71.092996667, - 70.652853333, - 72.838793333, - 74.3249, - 74.690726667, - 75.462586667, - 74.87943, - 75.429203333, - 76.836436667, - 77.9801, - 78.159586667, - 77.133953333, - 76.139193333, - 76.100923333, - 75.977446667, - 75.897756667, - 75.158033333, - 73.702993333, - 72.387816667, - 71.130253333, - 70.39241, - 71.103633333, - 71.842186667, - 72.052586667, - 71.766026667, - 71.548363333, - 71.128753333, - 72.8407, - 74.584996667, - 73.229936667, - 71.78108, - 71.673396667, - 71.184396667, - 70.4531, - 70.344756667, - 72.715336667, - 74.256866667, - 73.24873, - 73.652976667, - 75.191423333, - 75.63962, - 74.709446667, - 74.725396667, - 75.930556667, - 77.090426667, - 77.774146667, - 78.34251, - 79.083023333, - 79.19294, - 79.902196667, - 80.164726667, - 79.28103, - 78.529063333, - 77.409276667, - 75.7148, - 75.432493333, - 76.331206667, - 76.05935, - 76.290816667, - 76.174896667, - 74.520766667, - 74.641866667, - 75.632723333, - 75.710626667, - 74.692966667, - 73.84993, - 73.685023333, - 73.59346, - 73.485723333, - 74.233233333, - 76.036953333, - 77.343543333, - 77.40446, - 77.324593333, - 77.389233333, - 76.69522, - 75.906923333, - 75.531203333, - 75.230936667, - 74.892196667, - 75.257436667, - 76.047326667, - 76.83612, - 76.4245, - 74.62692, - 73.454276667, - 73.838346667, - 74.91667, - 75.654806667, - 75.07332, - 73.51074, - 72.497866667, - 72.15109, - 71.317343333, - 71.56787, - 72.18692, - 71.37498, - 70.426836667, - 70.611836667, - 71.692516667, - 72.545326667, - 71.79552, - 70.463443333, - 70.393413333, - 72.92507, - 75.238116667, - 74.41566, - 72.43751, - 70.750156667, - 70.50232, - 73.044236667, - 75.752553333, - 76.848816667, - 77.010526667, - 77.599906667, - 77.768733333, - 77.314866667, - 77.01545, - 77.704426667, - 78.521463333, - 79.173236667, - 79.92521, - 80.769776667, - 82.234066667, - 83.11997, - 82.61005, - 82.86877, - 83.577323333, - 84.011146667, - 84.565116667, - 84.8117, - 85.159493333, - 84.523926667, - 83.279573333, - 82.95924, - 83.57027, - 84.89847, - 83.853206667, - 84.676703333, - 86.10003, - 85.350266667, - 84.94219, - 85.116616667, - 84.75833, - 83.948586667, - 83.637406667, - 83.2102, - 82.458723333, - 82.4267, - 83.49822, - 83.83907, - 82.507316667, - 82.858513333, - 84.26815, - 83.920333333, - 84.255026667, - 82.74865, - 82.445566667, - 81.86038, - 80.631133333, - 81.62438, - 81.23579, - 80.95778, - 79.499446667, - 78.88417, - 78.406263333, - 76.631363333, - 75.627376667, - 75.485826667, - 73.82354, - 72.111716667, - 70.308843333, - 74.6297, - 75.690653333, - 74.810816667, - 75.50583, - 76.246803333, - 77.157083333, - 77.98975, - 77.812933333, - 77.722826667, - 79.01059, - 79.221413333, - 80.305683333, - 80.499336667, - 78.993733333, - 80.18652, - 81.94138, - 83.55718, - 82.897013333, - 82.29185, - 81.54342, - 82.708416667, - 83.576366667, - 83.04722, - 83.864086667, - 83.699626667, - 82.20913, - 81.32802, - 79.87446, - 79.22439, - 77.4626, - 78.31997, - 76.586803333, - 77.81823, - 77.163863333, - 77.913456667, - 79.026213333, - 77.37621, - 78.781353333, - 79.298723333, - 78.798236667, - 79.785363333, - 80.425, - 81.082246667, - 82.75068, - 83.45285, - 82.340293333, - 82.654883333, - 82.498793333, - 81.795116667, - 82.371406667, - 80.786006667, - 79.975043333, - 80.537633333, - 78.944543333, - 77.60028, - 76.822273333, - 75.409623333, - 74.17238, - 75.874883333, - 77.656453333, - 76.133693333, - 75.23148, - 76.698886667, - 76.538843333, - 77.68948, - 77.99752, - 79.06483, - 79.920213333, - 80.295163333, - 82.13812, - 81.25856, - 79.891413333, - 80.126633333, - 79.632393333, - 81.009086667, - 81.655146667, - 82.30286, - 83.57457, - 83.236493333, - 83.495466667, - 82.422156667, - 82.68833, - 83.218446667, - 84.335683333, - 85.520996667, - 85.508586667, - 85.91827, - 84.19682, - 86.29191, - 87.191866667, - 87.270053333, - 88.025836667, - 87.42611, - 86.863723333, - 86.564723333, - 87.268263333, - null - ], - "prints": [ - [ - "Last:87.27" - ], - [ - "Min:70.31" - ], - [ - "Max:88.03" - ], - [ - "Average:78.07" - ] - ], - "last_value": 87.27, - "minimum_value": 70.31, - "maximum_value": 88.03, - "average_value": 78.07 - }, - { - "index_id": 5614, - "metric_id": 13535, - "metric": "querytime", - "metric_legend": "querytime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#00ffcc" - }, - "legend": "querytime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 0.29714333333, - 0.69919666667, - 0.79321666667, - 0.71506, - 0.5782, - 0.48894666667, - 0.67059333333, - 0.54513333333, - 0.63351666667, - 0.83608666667, - 0.5301, - 0.27967333333, - 0.37714333333, - 0.59969333333, - 0.48521, - 0.59266333333, - 0.53817, - 0.1465, - 0.16135, - 0.3028, - 0.19724333333, - 0.17198333333, - 0.33685666667, - 0.24265333333, - 0.34326666667, - 0.76181, - 0.73900333333, - 0.67112333333, - 0.59812333333, - 0.52067666667, - 0.77137333333, - 0.47664333333, - 0.046403333333, - 0.24118333333, - 0.53058333333, - 0.57370333333, - 0.47472333333, - 0.19977, - 0.44531, - 0.80133, - 0.3802, - 0.034383333333, - 0.23191333333, - 0.32398666667, - 0.22054333333, - 0.35904666667, - 0.24970666667, - 0.29793666667, - 0.69748666667, - 0.54007333333, - 0.28856, - 0.18591333333, - 0.28871666667, - 0.43670333333, - 0.31626666667, - 0.3028, - 0.47199333333, - 0.56091666667, - 0.39671, - 0.44483, - 0.61814, - 0.61943, - 0.71691, - 0.4302, - 0.11944666667, - 0.42061, - 0.39272666667, - 0.19695, - 0.16065, - 0.34680666667, - 0.39646, - 0.48262, - 0.40757, - 0.14027, - 0.29311333333, - 0.57186, - 0.76852, - 0.8357, - 0.90495, - 0.50284, - 0.46309, - 0.73553666667, - 0.41647333333, - 0.47040333333, - 0.79052, - 0.53166333333, - 0.46984666667, - 0.69507333333, - 0.81015333333, - 0.68305, - 0.44918, - 0.42194333333, - 0.44094333333, - 0.22025666667, - 0.48985, - 0.86948, - 0.89493, - 0.60076, - 0.20515333333, - 0.56671333333, - 0.53818333333, - 0.18702666667, - 0.56491333333, - 0.91616666667, - 0.48051333333, - 0.35035666667, - 0.78203666667, - 0.88262, - 0.69741, - 0.67662, - 0.55486333333, - 0.28368666667, - 0.46458333333, - 0.84172, - 0.71890333333, - 0.63952333333, - 0.87039666667, - 0.54808, - 0.56612666667, - 0.63758666667, - 0.37719666667, - 0.68918666667, - 0.88794, - 0.90652666667, - 0.97649666667, - 0.78016, - 0.36409, - 0.34504333333, - 0.60541666667, - 0.58179, - 0.70434333333, - 0.53593666667, - 0.53723333333, - 0.50562666667, - 0.36219666667, - 0.36345666667, - 0.61732333333, - 0.77207666667, - 0.30536333333, - 0.22801666667, - 0.30937, - 0.32652666667, - 0.50535, - 0.60912, - 0.50587666667, - 0.27743666667, - 0.51364333333, - 0.50690666667, - 0.15515333333, - 0.39111333333, - 0.4863, - 0.52368, - 0.34827333333, - 0.2388, - 0.57008333333, - 0.60963666667, - 0.73512333333, - 0.7397, - 0.89249666667, - 0.71656666667, - 0.53072, - 0.66387333333, - 0.61843, - 0.30160333333, - 0.74331, - 0.17412666667, - 0.83096666667, - 0.17164666667, - 0.12400333333, - 0.30874333333, - 0.31753666667, - 0.54321666667, - 0.24991333333, - 0.29325, - 0.87885333333, - 0.14124333333, - 0.22927333333, - 0.87817666667, - 0.73802333333, - 0.94914, - 0.86089333333, - 0.49467, - 0.076276666667, - 0.33023333333, - 0.68270666667, - 0.78202, - 0.64673, - 0.4965, - 0.21815666667, - 0.073196666667, - 0.34646333333, - 0.23888666667, - 0.79677333333, - 0.91694333333, - 0.80389, - 0.16613333333, - 0.10015, - 0.77488, - 0.90486666667, - 0.07169, - 0.72866333333, - 0.65142333333, - 0.41378333333, - 0.92684, - 0.66168333333, - 0.47534, - 0.73346, - 0.42083, - 0.23695666667, - 0.22677, - 0.08573, - 0.55321, - 0.80721333333, - 0.43997, - 0.22795, - 0.34503666667, - 0.73733666667, - 0.90842333333, - 0.88768333333, - 0.08724, - 0.25737333333, - 0.25853333333, - 0.27085, - 0.39665, - 0.34975333333, - 0.17418333333, - 0.90513, - 0.89959666667, - 0.65670333333, - 0.92508, - 0.49195, - 0.63128, - 0.15663333333, - 0.059676666667, - 0.11686333333, - 0.16909, - 0.33827666667, - 0.77581, - 0.43058666667, - 0.097993333333, - 0.090543333333, - 0.44194333333, - 0.12752, - 0.34368333333, - 0.90045666667, - 0.85451333333, - 0.13603333333, - 0.87106666667, - 0.24542333333, - 0.65059, - 0.18116666667, - 0.77148333333, - 0.88124666667, - 0.86107, - 0.31515666667, - 0.91171666667, - 0.37591333333, - 0.34916, - 0.77019333333, - 0.62402666667, - 0.48065666667, - 0.22993333333, - 0.89142, - 0.085606666667, - 0.70465333333, - 0.50069666667, - 0.27494333333, - 0.88125, - 0.55443333333, - 0.38727, - 0.76749333333, - 0.83601, - 0.71435, - 0.53133666667, - 0.33418, - 0.44919, - 0.86442, - 0.19165, - 0.82827, - 0.32092, - 0.23609333333, - 0.45102333333, - 0.75873, - 0.23588666667, - 0.41906666667, - 0.357, - 0.32246333333, - 0.64624666667, - null - ], - "prints": [ - [ - "Last:0.65" - ], - [ - "Min:0.03" - ], - [ - "Max:0.98" - ], - [ - "Average:0.50" - ] - ], - "last_value": 0.65, - "minimum_value": 0.03, - "maximum_value": 0.98, - "average_value": 0.5 - } - ], - "times": [ - "2023-06-18T17:05:00+02:00", - "2023-06-18T17:10:00+02:00", - "2023-06-18T17:15:00+02:00", - "2023-06-18T17:20:00+02:00", - "2023-06-18T17:25:00+02:00", - "2023-06-18T17:30:00+02:00", - "2023-06-18T17:35:00+02:00", - "2023-06-18T17:40:00+02:00", - "2023-06-18T17:45:00+02:00", - "2023-06-18T17:50:00+02:00", - "2023-06-18T17:55:00+02:00", - "2023-06-18T18:00:00+02:00", - "2023-06-18T18:05:00+02:00", - "2023-06-18T18:10:00+02:00", - "2023-06-18T18:15:00+02:00", - "2023-06-18T18:20:00+02:00", - "2023-06-18T18:25:00+02:00", - "2023-06-18T18:30:00+02:00", - "2023-06-18T18:35:00+02:00", - "2023-06-18T18:40:00+02:00", - "2023-06-18T18:45:00+02:00", - "2023-06-18T18:50:00+02:00", - "2023-06-18T18:55:00+02:00", - "2023-06-18T19:00:00+02:00", - "2023-06-18T19:05:00+02:00", - "2023-06-18T19:10:00+02:00", - "2023-06-18T19:15:00+02:00", - "2023-06-18T19:20:00+02:00", - "2023-06-18T19:25:00+02:00", - "2023-06-18T19:30:00+02:00", - "2023-06-18T19:35:00+02:00", - "2023-06-18T19:40:00+02:00", - "2023-06-18T19:45:00+02:00", - "2023-06-18T19:50:00+02:00", - "2023-06-18T19:55:00+02:00", - "2023-06-18T20:00:00+02:00", - "2023-06-18T20:05:00+02:00", - "2023-06-18T20:10:00+02:00", - "2023-06-18T20:15:00+02:00", - "2023-06-18T20:20:00+02:00", - "2023-06-18T20:25:00+02:00", - "2023-06-18T20:30:00+02:00", - "2023-06-18T20:35:00+02:00", - "2023-06-18T20:40:00+02:00", - "2023-06-18T20:45:00+02:00", - "2023-06-18T20:50:00+02:00", - "2023-06-18T20:55:00+02:00", - "2023-06-18T21:00:00+02:00", - "2023-06-18T21:05:00+02:00", - "2023-06-18T21:10:00+02:00", - "2023-06-18T21:15:00+02:00", - "2023-06-18T21:20:00+02:00", - "2023-06-18T21:25:00+02:00", - "2023-06-18T21:30:00+02:00", - "2023-06-18T21:35:00+02:00", - "2023-06-18T21:40:00+02:00", - "2023-06-18T21:45:00+02:00", - "2023-06-18T21:50:00+02:00", - "2023-06-18T21:55:00+02:00", - "2023-06-18T22:00:00+02:00", - "2023-06-18T22:05:00+02:00", - "2023-06-18T22:10:00+02:00", - "2023-06-18T22:15:00+02:00", - "2023-06-18T22:20:00+02:00", - "2023-06-18T22:25:00+02:00", - "2023-06-18T22:30:00+02:00", - "2023-06-18T22:35:00+02:00", - "2023-06-18T22:40:00+02:00", - "2023-06-18T22:45:00+02:00", - "2023-06-18T22:50:00+02:00", - "2023-06-18T22:55:00+02:00", - "2023-06-18T23:00:00+02:00", - "2023-06-18T23:05:00+02:00", - "2023-06-18T23:10:00+02:00", - "2023-06-18T23:15:00+02:00", - "2023-06-18T23:20:00+02:00", - "2023-06-18T23:25:00+02:00", - "2023-06-18T23:30:00+02:00", - "2023-06-18T23:35:00+02:00", - "2023-06-18T23:40:00+02:00", - "2023-06-18T23:45:00+02:00", - "2023-06-18T23:50:00+02:00", - "2023-06-18T23:55:00+02:00", - "2023-06-19T00:00:00+02:00", - "2023-06-19T00:05:00+02:00", - "2023-06-19T00:10:00+02:00", - "2023-06-19T00:15:00+02:00", - "2023-06-19T00:20:00+02:00", - "2023-06-19T00:25:00+02:00", - "2023-06-19T00:30:00+02:00", - "2023-06-19T00:35:00+02:00", - "2023-06-19T00:40:00+02:00", - "2023-06-19T00:45:00+02:00", - "2023-06-19T00:50:00+02:00", - "2023-06-19T00:55:00+02:00", - "2023-06-19T01:00:00+02:00", - "2023-06-19T01:05:00+02:00", - "2023-06-19T01:10:00+02:00", - "2023-06-19T01:15:00+02:00", - "2023-06-19T01:20:00+02:00", - "2023-06-19T01:25:00+02:00", - "2023-06-19T01:30:00+02:00", - "2023-06-19T01:35:00+02:00", - "2023-06-19T01:40:00+02:00", - "2023-06-19T01:45:00+02:00", - "2023-06-19T01:50:00+02:00", - "2023-06-19T01:55:00+02:00", - "2023-06-19T02:00:00+02:00", - "2023-06-19T02:05:00+02:00", - "2023-06-19T02:10:00+02:00", - "2023-06-19T02:15:00+02:00", - "2023-06-19T02:20:00+02:00", - "2023-06-19T02:25:00+02:00", - "2023-06-19T02:30:00+02:00", - "2023-06-19T02:35:00+02:00", - "2023-06-19T02:40:00+02:00", - "2023-06-19T02:45:00+02:00", - "2023-06-19T02:50:00+02:00", - "2023-06-19T02:55:00+02:00", - "2023-06-19T03:00:00+02:00", - "2023-06-19T03:05:00+02:00", - "2023-06-19T03:10:00+02:00", - "2023-06-19T03:15:00+02:00", - "2023-06-19T03:20:00+02:00", - "2023-06-19T03:25:00+02:00", - "2023-06-19T03:30:00+02:00", - "2023-06-19T03:35:00+02:00", - "2023-06-19T03:40:00+02:00", - "2023-06-19T03:45:00+02:00", - "2023-06-19T03:50:00+02:00", - "2023-06-19T03:55:00+02:00", - "2023-06-19T04:00:00+02:00", - "2023-06-19T04:05:00+02:00", - "2023-06-19T04:10:00+02:00", - "2023-06-19T04:15:00+02:00", - "2023-06-19T04:20:00+02:00", - "2023-06-19T04:25:00+02:00", - "2023-06-19T04:30:00+02:00", - "2023-06-19T04:35:00+02:00", - "2023-06-19T04:40:00+02:00", - "2023-06-19T04:45:00+02:00", - "2023-06-19T04:50:00+02:00", - "2023-06-19T04:55:00+02:00", - "2023-06-19T05:00:00+02:00", - "2023-06-19T05:05:00+02:00", - "2023-06-19T05:10:00+02:00", - "2023-06-19T05:15:00+02:00", - "2023-06-19T05:20:00+02:00", - "2023-06-19T05:25:00+02:00", - "2023-06-19T05:30:00+02:00", - "2023-06-19T05:35:00+02:00", - "2023-06-19T05:40:00+02:00", - "2023-06-19T05:45:00+02:00", - "2023-06-19T05:50:00+02:00", - "2023-06-19T05:55:00+02:00", - "2023-06-19T06:00:00+02:00", - "2023-06-19T06:05:00+02:00", - "2023-06-19T06:10:00+02:00", - "2023-06-19T06:15:00+02:00", - "2023-06-19T06:20:00+02:00", - "2023-06-19T06:25:00+02:00", - "2023-06-19T06:30:00+02:00", - "2023-06-19T06:35:00+02:00", - "2023-06-19T06:40:00+02:00", - "2023-06-19T06:45:00+02:00", - "2023-06-19T06:50:00+02:00", - "2023-06-19T06:55:00+02:00", - "2023-06-19T07:00:00+02:00", - "2023-06-19T07:05:00+02:00", - "2023-06-19T07:10:00+02:00", - "2023-06-19T07:15:00+02:00", - "2023-06-19T07:20:00+02:00", - "2023-06-19T07:25:00+02:00", - "2023-06-19T07:30:00+02:00", - "2023-06-19T07:35:00+02:00", - "2023-06-19T07:40:00+02:00", - "2023-06-19T07:45:00+02:00", - "2023-06-19T07:50:00+02:00", - "2023-06-19T07:55:00+02:00", - "2023-06-19T08:00:00+02:00", - "2023-06-19T08:05:00+02:00", - "2023-06-19T08:10:00+02:00", - "2023-06-19T08:15:00+02:00", - "2023-06-19T08:20:00+02:00", - "2023-06-19T08:25:00+02:00", - "2023-06-19T08:30:00+02:00", - "2023-06-19T08:35:00+02:00", - "2023-06-19T08:40:00+02:00", - "2023-06-19T08:45:00+02:00", - "2023-06-19T08:50:00+02:00", - "2023-06-19T08:55:00+02:00", - "2023-06-19T09:00:00+02:00", - "2023-06-19T09:05:00+02:00", - "2023-06-19T09:10:00+02:00", - "2023-06-19T09:15:00+02:00", - "2023-06-19T09:20:00+02:00", - "2023-06-19T09:25:00+02:00", - "2023-06-19T09:30:00+02:00", - "2023-06-19T09:35:00+02:00", - "2023-06-19T09:40:00+02:00", - "2023-06-19T09:45:00+02:00", - "2023-06-19T09:50:00+02:00", - "2023-06-19T09:55:00+02:00", - "2023-06-19T10:00:00+02:00", - "2023-06-19T10:05:00+02:00", - "2023-06-19T10:10:00+02:00", - "2023-06-19T10:15:00+02:00", - "2023-06-19T10:20:00+02:00", - "2023-06-19T10:25:00+02:00", - "2023-06-19T10:30:00+02:00", - "2023-06-19T10:35:00+02:00", - "2023-06-19T10:40:00+02:00", - "2023-06-19T10:45:00+02:00", - "2023-06-19T10:50:00+02:00", - "2023-06-19T10:55:00+02:00", - "2023-06-19T11:00:00+02:00", - "2023-06-19T11:05:00+02:00", - "2023-06-19T11:10:00+02:00", - "2023-06-19T11:15:00+02:00", - "2023-06-19T11:20:00+02:00", - "2023-06-19T11:25:00+02:00", - "2023-06-19T11:30:00+02:00", - "2023-06-19T11:35:00+02:00", - "2023-06-19T11:40:00+02:00", - "2023-06-19T11:45:00+02:00", - "2023-06-19T11:50:00+02:00", - "2023-06-19T11:55:00+02:00", - "2023-06-19T12:00:00+02:00", - "2023-06-19T12:05:00+02:00", - "2023-06-19T12:10:00+02:00", - "2023-06-19T12:15:00+02:00", - "2023-06-19T12:20:00+02:00", - "2023-06-19T12:25:00+02:00", - "2023-06-19T12:30:00+02:00", - "2023-06-19T12:35:00+02:00", - "2023-06-19T12:40:00+02:00", - "2023-06-19T12:45:00+02:00", - "2023-06-19T12:50:00+02:00", - "2023-06-19T12:55:00+02:00", - "2023-06-19T13:00:00+02:00", - "2023-06-19T13:05:00+02:00", - "2023-06-19T13:10:00+02:00", - "2023-06-19T13:15:00+02:00", - "2023-06-19T13:20:00+02:00", - "2023-06-19T13:25:00+02:00", - "2023-06-19T13:30:00+02:00", - "2023-06-19T13:35:00+02:00", - "2023-06-19T13:40:00+02:00", - "2023-06-19T13:45:00+02:00", - "2023-06-19T13:50:00+02:00", - "2023-06-19T13:55:00+02:00", - "2023-06-19T14:00:00+02:00", - "2023-06-19T14:05:00+02:00", - "2023-06-19T14:10:00+02:00", - "2023-06-19T14:15:00+02:00", - "2023-06-19T14:20:00+02:00", - "2023-06-19T14:25:00+02:00", - "2023-06-19T14:30:00+02:00", - "2023-06-19T14:35:00+02:00", - "2023-06-19T14:40:00+02:00", - "2023-06-19T14:45:00+02:00", - "2023-06-19T14:50:00+02:00", - "2023-06-19T14:55:00+02:00", - "2023-06-19T15:00:00+02:00", - "2023-06-19T15:05:00+02:00", - "2023-06-19T15:10:00+02:00", - "2023-06-19T15:15:00+02:00", - "2023-06-19T15:20:00+02:00", - "2023-06-19T15:25:00+02:00", - "2023-06-19T15:30:00+02:00", - "2023-06-19T15:35:00+02:00", - "2023-06-19T15:40:00+02:00", - "2023-06-19T15:45:00+02:00", - "2023-06-19T15:50:00+02:00", - "2023-06-19T15:55:00+02:00", - "2023-06-19T16:00:00+02:00", - "2023-06-19T16:05:00+02:00", - "2023-06-19T16:10:00+02:00", - "2023-06-19T16:15:00+02:00", - "2023-06-19T16:20:00+02:00", - "2023-06-19T16:25:00+02:00", - "2023-06-19T16:30:00+02:00", - "2023-06-19T16:35:00+02:00", - "2023-06-19T16:40:00+02:00", - "2023-06-19T16:45:00+02:00", - "2023-06-19T16:50:00+02:00", - "2023-06-19T16:55:00+02:00", - "2023-06-19T17:00:00+02:00", - "2023-06-19T17:05:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayAreaStack.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayAreaStack.json deleted file mode 100644 index a38097e316..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayAreaStack.json +++ /dev/null @@ -1,3106 +0,0 @@ -{ - "global": { - "title": "memory-stats graph on srv-oracle-crm", - "start": "2023-06-06T12:43:09+02:00", - "end": "2023-06-07T12:43:09+02:00", - "vertical-label": "Memory Usage", - "base": 1024, - "width": 550, - "height": 140, - "scaled": 1, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 5397, - "metric_id": 13071, - "metric": "mem_active", - "metric_legend": "mem_active", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 25, - "host_id": null, - "service_id": null, - "name": "Memory-stats-active", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": "mem_active", - "ds_color_line": "#E84017", - "ds_color_line_mode": "0", - "ds_color_area": "#E84017", - "ds_color_area_warn": "#E84017", - "ds_color_area_crit": "#E84017", - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "10", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": "1", - "default_tpl1": null, - "comment": null - }, - "legend": "mem_active", - "stack": "1", - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 1893820035, - 2052146925.1, - 2466085903, - 2466085903, - 2466085903, - 2466085903, - 2466085903, - 2285190216.1, - 1812246071, - 1812246071, - 2063947848.5, - 2146317828, - 641190915, - 641190915, - 641190915, - 2311348047.5, - 6240789467.9, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 976416823, - 3746504548, - 4136212707, - 4136212707, - 4136212707, - 4136212707, - 4136212707, - 4136212707, - 4136212707, - 4136212707, - 4136212707, - 4136212707, - 4136212707, - 4045334676.2, - 4032549554, - 4032549554, - 4032549554, - 4032549554, - 4032549554, - 4032549554, - 4032549554, - 4032549554, - 4032549554, - 4032549554, - 4032549554, - 2843304694.2, - 2675996482, - 3290636903.5, - 3377107229, - 3377107229, - 3377107229, - 3377107229, - 1008975090.3, - 675815816, - 675815816, - 675815816, - 675815816, - 675815816, - 675815816, - 675815816, - 675815816, - 5007167276.5, - 5616520904, - 5616520904, - 5616520904, - 5616520904, - 5616520904, - 5616520904, - 5616520904, - 5616520904, - 6020516585.6, - 3004905509.1, - 2717449076.5, - 4013696655, - 4013696655, - 4013696655, - 4013696655, - 4013696655, - 4013696655, - 4013696655, - 4013696655, - 4013696655, - 4013696655, - 3518667258.2, - 3477659444.3, - 4029339877, - 4029339877, - 4029339877, - 4029339877, - 4029339877, - 4029339877, - 4029339877, - 4029339877, - 4029339877, - 4029339877, - 4029339877, - 2669352098.8, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 1176218664, - 921214667.61, - 641245245, - 641245245, - 641245245, - 641245245, - 641245245, - 641245245, - 641245245, - 641245245, - 641245245, - 641245245, - 531967203.39, - 410376143, - 410376143, - 410376143, - 410376143, - 410376143, - 410376143, - 410376143, - 410376143, - 410376143, - 364244282.82, - 312223249, - 312223249, - 312223249, - 312223249, - 312223249, - 312223249, - 312223249, - 312223249, - 191874059.65, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 56161144, - 2507006790.8, - 5270726350, - 5270726350, - 5270726350, - 5270726350, - 5357995355.7, - 6141977364.6, - 1153868339, - 1153868339, - 1153868339, - 1435336547.7, - 5174842749, - 5174842749, - 4977220904.4, - 2351673540, - 2351673540, - 2351673540, - 2439970914.3, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3613064601, - 3633811544.1, - 3738396850.5, - 1465840195, - 1465840195, - 1465840195, - 1465840195, - 1465840195, - 1174502940.9, - 1130969788, - 1130969788, - 1130969788, - 1130969788, - 1130969788, - 1130969788, - 1130969788, - 1116663662, - 1114525965, - 1114525965, - 1114525965, - 1114525965, - 1114525965, - 1114525965, - 1114525965, - 1114525965, - 1114525965, - 496913723.64, - 404626837, - 404626837, - 404626837, - 404626837, - 404626837, - 404626837, - 404626837, - 5119506062, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5824028245, - 5908740341.6, - 5921398471, - 5921398471, - 5921398471, - 5921398471, - 5921398471, - 5921398471, - 5921398471, - 6245118232.5, - 6005456642, - 4040032635, - 2592658957, - 2592658957, - null - ], - "prints": [ - [ - "Last:2592658957.00" - ], - [ - "Average:2419187156.86" - ] - ], - "last_value": 2592658957, - "minimum_value": null, - "maximum_value": null, - "average_value": 2419187156.86 - }, - { - "index_id": 5397, - "metric_id": 13073, - "metric": "mem_apps", - "metric_legend": "mem_apps", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 26, - "host_id": null, - "service_id": null, - "name": "Memory-stats-apps", - "ds_order": 2, - "ds_hidecurve": null, - "ds_name": "mem_apps", - "ds_color_line": "#4BB846", - "ds_color_line_mode": "0", - "ds_color_area": "#4BB846", - "ds_color_area_warn": "#4BB846", - "ds_color_area_crit": "#4BB846", - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "10", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": "1", - "default_tpl1": null, - "comment": null - }, - "legend": "mem_apps", - "stack": "1", - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 2, - "data": [ - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 98553122, - 212008185.56, - 508631665, - 508631665, - 508631665, - 508631665, - 508631665, - 404436836.74, - 132023852, - 132023852, - 751679255.8, - 2023984324.9, - 1114786080, - 1114786080, - 1114786080, - 1545614683, - 2477236437.9, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 131631027, - 1689936947, - 1909166297, - 1909166297, - 1909166297, - 1909166297, - 1909166297, - 1909166297, - 1909166297, - 1909166297, - 1909166297, - 1909166297, - 1909166297, - 1590469817.4, - 1545634191, - 1545634191, - 1545634191, - 1545634191, - 1545634191, - 1545634191, - 1545634191, - 1545634191, - 1545634191, - 1545634191, - 1545634191, - 540868656.99, - 399513810, - 805884426.34, - 863054437, - 863054437, - 863054437, - 863054437, - 561082446.51, - 518599695, - 518599695, - 518599695, - 518599695, - 518599695, - 518599695, - 518599695, - 518599695, - 1357142860, - 1475112811, - 1475112811, - 1475112811, - 1475112811, - 1475112811, - 1475112811, - 1475112811, - 1475112811, - 1844808332.4, - 1834001095.6, - 2325101374.9, - 2897236369, - 2897236369, - 2897236369, - 2897236369, - 2897236369, - 2897236369, - 2897236369, - 2897236369, - 2897236369, - 2897236369, - 2780403570.1, - 2660846348.1, - 2670413196, - 2670413196, - 2670413196, - 2670413196, - 2670413196, - 2670413196, - 2670413196, - 2670413196, - 2670413196, - 2670413196, - 2670413196, - 1430911514, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 70060017, - 69927619.973, - 69782261, - 69782261, - 69782261, - 69782261, - 69782261, - 69782261, - 69782261, - 69782261, - 69782261, - 69782261, - 57749074.973, - 44360037, - 44360037, - 44360037, - 44360037, - 44360037, - 44360037, - 44360037, - 44360037, - 44360037, - 29247892.94, - 12206539, - 12206539, - 12206539, - 12206539, - 12206539, - 12206539, - 12206539, - 12206539, - 9103798.28, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 5604963, - 1292535222.4, - 2743754451, - 2743754451, - 2743754451, - 2743754451, - 2746719079.1, - 2664862881, - 1054057710, - 1054057710, - 1054057710, - 1077191458.5, - 1384539832, - 1384539832, - 1377460654.4, - 1283408724, - 1283408724, - 1283408724, - 1427368034.9, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3339970309, - 3341758517.8, - 3277555338.2, - 2108933138, - 2108933138, - 2108933138, - 2108933138, - 2108933138, - 1548430581.6, - 1464677326, - 1464677326, - 1464677326, - 1464677326, - 1464677326, - 1464677326, - 1464677326, - 300788359.3, - 126873916, - 126873916, - 126873916, - 126873916, - 126873916, - 126873916, - 126873916, - 126873916, - 126873916, - 84415687.93, - 78071355, - 78071355, - 78071355, - 78071355, - 78071355, - 78071355, - 78071355, - 1014630991.2, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 1154576684, - 2456071615.8, - 2650547870, - 2650547870, - 2650547870, - 2650547870, - 2650547870, - 2650547870, - 2650547870, - 2726291049, - 1847897022.8, - 477644310.52, - 158057658, - 158057658, - null - ], - "prints": [ - [ - "Last:158057658.00" - ], - [ - "Average:1062901083.13" - ] - ], - "last_value": 158057658, - "minimum_value": null, - "maximum_value": null, - "average_value": 1062901083.13 - }, - { - "index_id": 5397, - "metric_id": 13070, - "metric": "mem_mapped", - "metric_legend": "mem_mapped", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 27, - "host_id": null, - "service_id": null, - "name": "Memory-stats-mapped", - "ds_order": 3, - "ds_hidecurve": null, - "ds_name": "mem_mapped", - "ds_color_line": "#39C3C6", - "ds_color_line_mode": "0", - "ds_color_area": "#39C3C6", - "ds_color_area_warn": "#39C3C6", - "ds_color_area_crit": "#39C3C6", - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "10", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": "1", - "default_tpl1": null, - "comment": null - }, - "legend": "mem_mapped", - "stack": "1", - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 3, - "data": [ - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 26075867, - 30188011.807, - 40939041, - 40939041, - 40939041, - 40939041, - 40939041, - 40006741.287, - 37569283, - 37569283, - 44363448.583, - 50169994.46, - 18910194, - 18910194, - 18910194, - 44714711.123, - 103907909.91, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 4288797, - 134021342.32, - 152272689, - 152272689, - 152272689, - 152272689, - 152272689, - 152272689, - 152272689, - 152272689, - 152272689, - 152272689, - 152272689, - 96299329.143, - 88424750, - 88424750, - 88424750, - 88424750, - 88424750, - 88424750, - 88424750, - 88424750, - 88424750, - 88424750, - 88424750, - 50472420.157, - 45133119, - 95402405.987, - 102474511, - 102474511, - 102474511, - 102474511, - 59306851.707, - 53233835, - 53233835, - 53233835, - 53233835, - 53233835, - 53233835, - 53233835, - 53233835, - 139167265.92, - 151256760, - 151256760, - 151256760, - 151256760, - 151256760, - 151256760, - 151256760, - 151256760, - 167520608.11, - 87172020.61, - 105523104.02, - 169023088, - 169023088, - 169023088, - 169023088, - 169023088, - 169023088, - 169023088, - 169023088, - 169023088, - 169023088, - 125884231.76, - 92215363.55, - 107249346, - 107249346, - 107249346, - 107249346, - 107249346, - 107249346, - 107249346, - 107249346, - 107249346, - 107249346, - 107249346, - 71144807.53, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 31505559, - 29477861.9, - 27251649, - 27251649, - 27251649, - 27251649, - 27251649, - 27251649, - 27251649, - 27251649, - 27251649, - 27251649, - 18183509.593, - 8093608, - 8093608, - 8093608, - 8093608, - 8093608, - 8093608, - 8093608, - 8093608, - 8093608, - 4702974.42, - 879494, - 879494, - 879494, - 879494, - 879494, - 879494, - 879494, - 879494, - 486918.98, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 44228, - 68949003.82, - 146650134, - 146650134, - 146650134, - 146650134, - 147031336.99, - 152013277.07, - 150915692, - 150915692, - 150915692, - 151609863.87, - 160832433, - 160832433, - 155141940.43, - 79539682, - 79539682, - 79539682, - 81880551.23, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 112980671, - 115500915.72, - 146919039.18, - 119482341, - 119482341, - 119482341, - 119482341, - 119482341, - 90930015.45, - 86663576, - 86663576, - 86663576, - 86663576, - 86663576, - 86663576, - 86663576, - 52103843.03, - 46939745, - 46939745, - 46939745, - 46939745, - 46939745, - 46939745, - 46939745, - 46939745, - 46939745, - 30694571.69, - 28267132, - 28267132, - 28267132, - 28267132, - 28267132, - 28267132, - 28267132, - 150105765.22, - 168311538, - 168311538, - 168311538, - 168311538, - 168311538, - 168311538, - 168311538, - 168311538, - 168311538, - 168311538, - 168311538, - 168311538, - 169874079.75, - 170107563, - 170107563, - 170107563, - 170107563, - 170107563, - 170107563, - 170107563, - 170629573.67, - 120264551.1, - 56314383.81, - 48993877, - 48993877, - null - ], - "prints": [ - [ - "Last:48993877.00" - ], - [ - "Average:72908106.02" - ] - ], - "last_value": 48993877, - "minimum_value": null, - "maximum_value": null, - "average_value": 72908106.02 - }, - { - "index_id": 5397, - "metric_id": 13069, - "metric": "mem_pages_tables", - "metric_legend": "mem_pages_tables", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 28, - "host_id": null, - "service_id": null, - "name": "Memory-stats-page-tables", - "ds_order": 4, - "ds_hidecurve": null, - "ds_name": "mem_pages_tables", - "ds_color_line": "#E3DB1C", - "ds_color_line_mode": "0", - "ds_color_area": "#E3DB1C", - "ds_color_area_warn": "#E3DB1C", - "ds_color_area_crit": "#E3DB1C", - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "10", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": "1", - "default_tpl1": null, - "comment": null - }, - "legend": "mem_pages_tables", - "stack": "1", - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 4, - "data": [ - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 74549259, - 78623541.143, - 89275580, - 89275580, - 89275580, - 89275580, - 89275580, - 66932420.177, - 8517171, - 8517171, - 48204303.26, - 144020594.4, - 123251230, - 123251230, - 123251230, - 157464418.47, - 241700900.2, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 178924790, - 311516741.45, - 330170362, - 330170362, - 330170362, - 330170362, - 330170362, - 330170362, - 330170362, - 330170362, - 330170362, - 330170362, - 330170362, - 56983891.587, - 18550814, - 18550814, - 18550814, - 18550814, - 18550814, - 18550814, - 18550814, - 18550814, - 18550814, - 18550814, - 18550814, - 13753708.903, - 13078831, - 93841567.95, - 105203626, - 105203626, - 105203626, - 105203626, - 29710500.823, - 19089795, - 19089795, - 19089795, - 19089795, - 19089795, - 19089795, - 19089795, - 19089795, - 80470299.85, - 89105580, - 89105580, - 89105580, - 89105580, - 89105580, - 89105580, - 89105580, - 89105580, - 257340638.01, - 238801689.93, - 251976806.54, - 288584148, - 288584148, - 288584148, - 288584148, - 288584148, - 288584148, - 288584148, - 288584148, - 288584148, - 288584148, - 186830459.77, - 128637295.24, - 187399676, - 187399676, - 187399676, - 187399676, - 187399676, - 187399676, - 187399676, - 187399676, - 187399676, - 187399676, - 187399676, - 128653847.91, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 64156680, - 38517552.2, - 10368300, - 10368300, - 10368300, - 10368300, - 10368300, - 10368300, - 10368300, - 10368300, - 10368300, - 10368300, - 9097165.2267, - 7682804, - 7682804, - 7682804, - 7682804, - 7682804, - 7682804, - 7682804, - 7682804, - 7682804, - 4386945.92, - 670340, - 670340, - 670340, - 670340, - 670340, - 670340, - 670340, - 670340, - 573501.2, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 464300, - 105221194.23, - 223351309, - 223351309, - 223351309, - 223351309, - 231537164.72, - 337387099.68, - 298792029, - 298792029, - 298792029, - 298809162.27, - 299036790, - 299036790, - 296149074.19, - 257783707, - 257783707, - 257783707, - 262884434.38, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 330651241, - 331120621.73, - 315063592.89, - 18884007, - 18884007, - 18884007, - 18884007, - 18884007, - 3107364.36, - 749935, - 749935, - 749935, - 749935, - 749935, - 749935, - 749935, - 251633.8, - 177175, - 177175, - 177175, - 177175, - 177175, - 177175, - 177175, - 177175, - 177175, - 47990.44, - 28687, - 28687, - 28687, - 28687, - 28687, - 28687, - 28687, - 114925814.68, - 132094351, - 132094351, - 132094351, - 132094351, - 132094351, - 132094351, - 132094351, - 132094351, - 132094351, - 132094351, - 132094351, - 132094351, - 253196701.48, - 271292455, - 271292455, - 271292455, - 271292455, - 271292455, - 271292455, - 271292455, - 285387781.79, - 253248736.66, - 186446431.82, - 172196696, - 172196696, - null - ], - "prints": [ - [ - "Last:172196696.00" - ], - [ - "Average:118644866.56" - ] - ], - "last_value": 172196696, - "minimum_value": null, - "maximum_value": null, - "average_value": 118644866.56 - }, - { - "index_id": 5397, - "metric_id": 13072, - "metric": "mem_inactive", - "metric_legend": "mem_inactive", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 29, - "host_id": null, - "service_id": null, - "name": "Memory-stats-inactive", - "ds_order": 5, - "ds_hidecurve": null, - "ds_name": "mem_inactive", - "ds_color_line": "#91876E", - "ds_color_line_mode": "0", - "ds_color_area": "#91876E", - "ds_color_area_warn": "#91876E", - "ds_color_area_crit": "#91876E", - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "10", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": "1", - "default_tpl1": null, - "comment": null - }, - "legend": "mem_inactive", - "stack": "1", - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 5, - "data": [ - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 78174332, - 84397956.413, - 100669360, - 100669360, - 100669360, - 100669360, - 100669360, - 85037735.11, - 44169511, - 44169511, - 138186268.11, - 334429102.58, - 204856540, - 204856540, - 204856540, - 266905172.87, - 417538119.81, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 277947135, - 456831211.17, - 481997412, - 481997412, - 481997412, - 481997412, - 481997412, - 481997412, - 481997412, - 481997412, - 481997412, - 481997412, - 481997412, - 121519411.11, - 70805776, - 70805776, - 70805776, - 70805776, - 70805776, - 70805776, - 70805776, - 70805776, - 70805776, - 70805776, - 70805776, - 14874547.867, - 7005896, - 97493389.33, - 110223569, - 110223569, - 110223569, - 110223569, - 82766160.353, - 78903331, - 78903331, - 78903331, - 78903331, - 78903331, - 78903331, - 78903331, - 78903331, - 361860746.73, - 401668444, - 401668444, - 401668444, - 401668444, - 401668444, - 401668444, - 401668444, - 401668444, - 443765650.34, - 339668456.03, - 346882883.6, - 412521374, - 412521374, - 412521374, - 412521374, - 412521374, - 412521374, - 412521374, - 412521374, - 412521374, - 412521374, - 284942314.77, - 265374316.08, - 397672966, - 397672966, - 397672966, - 397672966, - 397672966, - 397672966, - 397672966, - 397672966, - 397672966, - 397672966, - 397672966, - 238462035.07, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 63664020, - 40019224.54, - 14059554, - 14059554, - 14059554, - 14059554, - 14059554, - 14059554, - 14059554, - 14059554, - 14059554, - 14059554, - 9025003.1667, - 3423179, - 3423179, - 3423179, - 3423179, - 3423179, - 3423179, - 3423179, - 3423179, - 3423179, - 2992653.83, - 2507168, - 2507168, - 2507168, - 2507168, - 2507168, - 2507168, - 2507168, - 2507168, - 2373775.89, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 2223355, - 208213620.2, - 440500515, - 440500515, - 440500515, - 440500515, - 442135076.11, - 435862503.86, - 64010186, - 64010186, - 64010186, - 85934393.62, - 377213152, - 377213152, - 356856826.5, - 86408502, - 86408502, - 86408502, - 103265039.74, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 327216184, - 336353686.99, - 457049389.5, - 447715491, - 447715491, - 447715491, - 447715491, - 447715491, - 359026791.42, - 345774457, - 345774457, - 345774457, - 345774457, - 345774457, - 345774457, - 345774457, - 128463407.08, - 95991641, - 95991641, - 95991641, - 95991641, - 95991641, - 95991641, - 95991641, - 95991641, - 95991641, - 86254514, - 84799541, - 84799541, - 84799541, - 84799541, - 84799541, - 84799541, - 84799541, - 117187388.57, - 122026952, - 122026952, - 122026952, - 122026952, - 122026952, - 122026952, - 122026952, - 122026952, - 122026952, - 122026952, - 122026952, - 122026952, - 196747423.13, - 207912551, - 207912551, - 207912551, - 207912551, - 207912551, - 207912551, - 207912551, - 326892127.45, - 316977681.63, - 105944222.97, - 51188466, - 51188466, - null - ], - "prints": [ - [ - "Last:51188466.00" - ], - [ - "Average:183852943.55" - ] - ], - "last_value": 51188466, - "minimum_value": null, - "maximum_value": null, - "average_value": 183852943.55 - }, - { - "index_id": 5397, - "metric_id": 13067, - "metric": "mem_buffer", - "metric_legend": "mem_buffer", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 30, - "host_id": null, - "service_id": null, - "name": "Memory-stats-buffer", - "ds_order": 6, - "ds_hidecurve": null, - "ds_name": "mem_buffer", - "ds_color_line": "#1209F5", - "ds_color_line_mode": "0", - "ds_color_area": "#1209F5", - "ds_color_area_warn": "#1209F5", - "ds_color_area_crit": "#1209F5", - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "10", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": "1", - "default_tpl1": null, - "comment": null - }, - "legend": "mem_buffer", - "stack": "1", - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 6, - "data": [ - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 37552729, - 191708687.1, - 594742939, - 594742939, - 594742939, - 594742939, - 594742939, - 540393727.81, - 398300007, - 398300007, - 480586455.45, - 625139901.46, - 440608844, - 440608844, - 440608844, - 467841282.06, - 537710601.72, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 521707935, - 696259169.45, - 720815807, - 720815807, - 720815807, - 720815807, - 720815807, - 720815807, - 720815807, - 720815807, - 720815807, - 720815807, - 720815807, - 113953070.44, - 28576944, - 28576944, - 28576944, - 28576944, - 28576944, - 28576944, - 28576944, - 28576944, - 28576944, - 28576944, - 28576944, - 16222688.197, - 14484637, - 236373711.35, - 267590045, - 267590045, - 267590045, - 267590045, - 195705498.99, - 185592464, - 185592464, - 185592464, - 185592464, - 185592464, - 185592464, - 185592464, - 185592464, - 650575197.22, - 715991019, - 715991019, - 715991019, - 715991019, - 715991019, - 715991019, - 715991019, - 715991019, - 838061375.8, - 281973265.07, - 328841897.77, - 681039689, - 681039689, - 681039689, - 681039689, - 681039689, - 681039689, - 681039689, - 681039689, - 681039689, - 681039689, - 445778518.09, - 419835812, - 674934492, - 674934492, - 674934492, - 674934492, - 674934492, - 674934492, - 674934492, - 674934492, - 674934492, - 674934492, - 674934492, - 424722024.73, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 150013232, - 145144937.14, - 139800026, - 139800026, - 139800026, - 139800026, - 139800026, - 139800026, - 139800026, - 139800026, - 139800026, - 139800026, - 137569339.95, - 135087309, - 135087309, - 135087309, - 135087309, - 135087309, - 135087309, - 135087309, - 135087309, - 135087309, - 122012400.62, - 107268355, - 107268355, - 107268355, - 107268355, - 107268355, - 107268355, - 107268355, - 107268355, - 98034856.26, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 87622613, - 404735924.31, - 762331786, - 762331786, - 762331786, - 762331786, - 766513542.81, - 809009098.93, - 635470168, - 635470168, - 635470168, - 638174903.11, - 674109241, - 674109241, - 647779351.33, - 297967960, - 297967960, - 297967960, - 312033490.01, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 498904103, - 513191502.42, - 659509551.15, - 81577554, - 81577554, - 81577554, - 81577554, - 81577554, - 45720144.69, - 40362141, - 40362141, - 40362141, - 40362141, - 40362141, - 40362141, - 40362141, - 19195506.45, - 16032676, - 16032676, - 16032676, - 16032676, - 16032676, - 16032676, - 16032676, - 16032676, - 16032676, - 5517032.98, - 3945730, - 3945730, - 3945730, - 3945730, - 3945730, - 3945730, - 3945730, - 462388009.63, - 530890879, - 530890879, - 530890879, - 530890879, - 530890879, - 530890879, - 530890879, - 530890879, - 530890879, - 530890879, - 530890879, - 530890879, - 617384949.64, - 630309351, - 630309351, - 630309351, - 630309351, - 630309351, - 630309351, - 630309351, - 638703189.57, - 584936985.36, - 354641768.23, - 175353479, - 175353479, - null - ], - "prints": [ - [ - "Last:175353479.00" - ], - [ - "Average:332234252.08" - ] - ], - "last_value": 175353479, - "minimum_value": null, - "maximum_value": null, - "average_value": 332234252.08 - }, - { - "index_id": 5397, - "metric_id": 13068, - "metric": "mem_cache", - "metric_legend": "mem_cache", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 31, - "host_id": null, - "service_id": null, - "name": "Memory-stats-cache", - "ds_order": 7, - "ds_hidecurve": null, - "ds_name": "mem_cache", - "ds_color_line": "#C738B3", - "ds_color_line_mode": "0", - "ds_color_area": "#C738B3", - "ds_color_area_warn": "#C738B3", - "ds_color_area_crit": "#C738B3", - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "10", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": "1", - "default_tpl1": null, - "comment": null - }, - "legend": "mem_cache", - "stack": "1", - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 7, - "data": [ - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2366932380, - 2525106295.6, - 2938645328, - 2938645328, - 2938645328, - 2938645328, - 2938645328, - 2351768818.4, - 817404932, - 817404932, - 1645987946.6, - 3207589652.9, - 1626643617, - 1626643617, - 1626643617, - 2160810351.6, - 3323027980.6, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 500774058, - 2333026907.7, - 2590796320, - 2590796320, - 2590796320, - 2590796320, - 2590796320, - 2590796320, - 2590796320, - 2590796320, - 2590796320, - 2590796320, - 2590796320, - 1910659820.6, - 1814975218, - 1814975218, - 1814975218, - 1814975218, - 1814975218, - 1814975218, - 1814975218, - 1814975218, - 1814975218, - 1814975218, - 1814975218, - 1222898572, - 1139602618, - 1443507739.1, - 1486262452, - 1486262452, - 1486262452, - 1486262452, - 1479102156.9, - 1478094815, - 1478094815, - 1478094815, - 1478094815, - 1478094815, - 1478094815, - 1478094815, - 1478094815, - 3660937859.7, - 3968029847, - 3968029847, - 3968029847, - 3968029847, - 3968029847, - 3968029847, - 3968029847, - 3968029847, - 4183448669.9, - 2332788260.5, - 2874868720.4, - 4456800060, - 4456800060, - 4456800060, - 4456800060, - 4456800060, - 4456800060, - 4456800060, - 4456800060, - 4456800060, - 4456800060, - 3221762121.1, - 2425597488.2, - 3040187834, - 3040187834, - 3040187834, - 3040187834, - 3040187834, - 3040187834, - 3040187834, - 3040187834, - 3040187834, - 3040187834, - 3040187834, - 2657943826.1, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 2238277328, - 1398491748, - 476489398, - 476489398, - 476489398, - 476489398, - 476489398, - 476489398, - 476489398, - 476489398, - 476489398, - 476489398, - 286775000.57, - 75684333, - 75684333, - 75684333, - 75684333, - 75684333, - 75684333, - 75684333, - 75684333, - 75684333, - 72587698.52, - 69095749, - 69095749, - 69095749, - 69095749, - 69095749, - 69095749, - 69095749, - 69095749, - 54257856.05, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 37525764, - 2408894455.5, - 5082991065, - 5082991065, - 5082991065, - 5082991065, - 5086825971.8, - 5115011610.7, - 4812577773, - 4812577773, - 4812577773, - 4824094075.7, - 4977096383, - 4977096383, - 4809771214.1, - 2586736827, - 2586736827, - 2586736827, - 2601799952.6, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2801924335, - 2949784835.2, - 4695957105.6, - 1796215918, - 1796215918, - 1796215918, - 1796215918, - 1796215918, - 1759041364.4, - 1753486546, - 1753486546, - 1753486546, - 1753486546, - 1753486546, - 1753486546, - 1753486546, - 1184101489.7, - 1099020964, - 1099020964, - 1099020964, - 1099020964, - 1099020964, - 1099020964, - 1099020964, - 1099020964, - 1099020964, - 985758279.22, - 968833970, - 968833970, - 968833970, - 968833970, - 968833970, - 968833970, - 968833970, - 3623849409.9, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4020575855, - 4886590537.3, - 5015995030, - 5015995030, - 5015995030, - 5015995030, - 5015995030, - 5015995030, - 5015995030, - 5048183774.8, - 4637944118.6, - 3658964974.6, - 3122834181, - 3122834181, - null - ], - "prints": [ - [ - "Last:3122834181.00" - ], - [ - "Average:2112555251.91" - ] - ], - "last_value": 3122834181, - "minimum_value": null, - "maximum_value": null, - "average_value": 2112555251.91 - }, - { - "index_id": 5397, - "metric_id": 13074, - "metric": "mem_unused", - "metric_legend": "mem_unused", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 32, - "host_id": null, - "service_id": null, - "name": "Memory-stats-unused", - "ds_order": 8, - "ds_hidecurve": null, - "ds_name": "mem_unused", - "ds_color_line": "#01FD0B", - "ds_color_line_mode": "0", - "ds_color_area": "#01FD0B", - "ds_color_area_warn": "#01FD0B", - "ds_color_area_crit": "#01FD0B", - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "10", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": "1", - "default_tpl1": null, - "comment": null - }, - "legend": "mem_unused", - "stack": "1", - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 8, - "data": [ - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12604211456, - 12005689577, - 10440879364, - 10440879364, - 10440879364, - 10440879364, - 10440879364, - 11406102684, - 13929638353, - 13929638353, - 12006913654, - 8648217781.3, - 13009621760, - 13009621760, - 13009621760, - 10225170513, - 3837957762, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 14588178615, - 7811772312.9, - 6858437586, - 6858437586, - 6858437586, - 6858437586, - 6858437586, - 6858437586, - 6858437586, - 6858437586, - 6858437586, - 6858437586, - 6858437586, - 9244649163.5, - 9580351933, - 9580351933, - 9580351933, - 9580351933, - 9580351933, - 9580351933, - 9580351933, - 9580351933, - 9580351933, - 9580351933, - 9580351933, - 12477473892, - 12885053787, - 11116729036, - 10867953311, - 10867953311, - 10867953311, - 10867953311, - 13763220474, - 14170539429, - 14170539429, - 14170539429, - 14170539429, - 14170539429, - 14170539429, - 14170539429, - 14170539429, - 5922547674.1, - 4762183815, - 4762183815, - 4762183815, - 4762183815, - 4762183815, - 4762183815, - 4762183815, - 4762183815, - 3424407319.8, - 9060558883.2, - 8229225316.2, - 4260967797, - 4260967797, - 4260967797, - 4260967797, - 4260967797, - 4260967797, - 4260967797, - 4260967797, - 4260967797, - 4260967797, - 6615600706.2, - 7709703112.6, - 6072671793, - 6072671793, - 6072671793, - 6072671793, - 6072671793, - 6072671793, - 6072671793, - 6072671793, - 6072671793, - 6072671793, - 6072671793, - 9558679025.8, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 13385973680, - 14537075569, - 15800872747, - 15800872747, - 15800872747, - 15800872747, - 15800872747, - 15800872747, - 15800872747, - 15800872747, - 15800872747, - 15800872747, - 16129502883, - 16495161767, - 16495161767, - 16495161767, - 16495161767, - 16495161767, - 16495161767, - 16495161767, - 16495161767, - 16495161767, - 16579694331, - 16675018286, - 16675018286, - 16675018286, - 16675018286, - 16675018286, - 16675018286, - 16675018286, - 16675018286, - 16823164414, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 16990222813, - 10184312969, - 2509563570, - 2509563570, - 2509563570, - 2509563570, - 2401111652.8, - 1523745344.1, - 9010177283, - 9010177283, - 9010177283, - 8668718775.2, - 4132198600, - 4132198600, - 4559489214.7, - 10236350238, - 10236350238, - 10236350238, - 9950666762.9, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 6155157736, - 5958347556.1, - 3889418312.9, - 11141220536, - 11141220536, - 11141220536, - 11141220536, - 11141220536, - 12199109977, - 12357185411, - 12357185411, - 12357185411, - 12357185411, - 12357185411, - 12357185411, - 12357185411, - 14378301279, - 14680307098, - 14680307098, - 14680307098, - 14680307098, - 14680307098, - 14680307098, - 14680307098, - 14680307098, - 14680307098, - 15490267380, - 15611295928, - 15611295928, - 15611295928, - 15611295928, - 15611295928, - 15611295928, - 15611295928, - 6577275738.8, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 5227364676, - 2691263531.3, - 2312305889, - 2312305889, - 2312305889, - 2312305889, - 2312305889, - 2312305889, - 2312305889, - 1738663451.3, - 3413143441.8, - 8299880453.1, - 10858585866, - 10858585866, - null - ], - "prints": [ - [ - "Last:10858585866.00" - ], - [ - "Average:10877585519.89" - ] - ], - "last_value": 10858585866, - "minimum_value": null, - "maximum_value": null, - "average_value": 10877585519.89 - } - ], - "times": [ - "2023-06-06T12:45:00+02:00", - "2023-06-06T12:50:00+02:00", - "2023-06-06T12:55:00+02:00", - "2023-06-06T13:00:00+02:00", - "2023-06-06T13:05:00+02:00", - "2023-06-06T13:10:00+02:00", - "2023-06-06T13:15:00+02:00", - "2023-06-06T13:20:00+02:00", - "2023-06-06T13:25:00+02:00", - "2023-06-06T13:30:00+02:00", - "2023-06-06T13:35:00+02:00", - "2023-06-06T13:40:00+02:00", - "2023-06-06T13:45:00+02:00", - "2023-06-06T13:50:00+02:00", - "2023-06-06T13:55:00+02:00", - "2023-06-06T14:00:00+02:00", - "2023-06-06T14:05:00+02:00", - "2023-06-06T14:10:00+02:00", - "2023-06-06T14:15:00+02:00", - "2023-06-06T14:20:00+02:00", - "2023-06-06T14:25:00+02:00", - "2023-06-06T14:30:00+02:00", - "2023-06-06T14:35:00+02:00", - "2023-06-06T14:40:00+02:00", - "2023-06-06T14:45:00+02:00", - "2023-06-06T14:50:00+02:00", - "2023-06-06T14:55:00+02:00", - "2023-06-06T15:00:00+02:00", - "2023-06-06T15:05:00+02:00", - "2023-06-06T15:10:00+02:00", - "2023-06-06T15:15:00+02:00", - "2023-06-06T15:20:00+02:00", - "2023-06-06T15:25:00+02:00", - "2023-06-06T15:30:00+02:00", - "2023-06-06T15:35:00+02:00", - "2023-06-06T15:40:00+02:00", - "2023-06-06T15:45:00+02:00", - "2023-06-06T15:50:00+02:00", - "2023-06-06T15:55:00+02:00", - "2023-06-06T16:00:00+02:00", - "2023-06-06T16:05:00+02:00", - "2023-06-06T16:10:00+02:00", - "2023-06-06T16:15:00+02:00", - "2023-06-06T16:20:00+02:00", - "2023-06-06T16:25:00+02:00", - "2023-06-06T16:30:00+02:00", - "2023-06-06T16:35:00+02:00", - "2023-06-06T16:40:00+02:00", - "2023-06-06T16:45:00+02:00", - "2023-06-06T16:50:00+02:00", - "2023-06-06T16:55:00+02:00", - "2023-06-06T17:00:00+02:00", - "2023-06-06T17:05:00+02:00", - "2023-06-06T17:10:00+02:00", - "2023-06-06T17:15:00+02:00", - "2023-06-06T17:20:00+02:00", - "2023-06-06T17:25:00+02:00", - "2023-06-06T17:30:00+02:00", - "2023-06-06T17:35:00+02:00", - "2023-06-06T17:40:00+02:00", - "2023-06-06T17:45:00+02:00", - "2023-06-06T17:50:00+02:00", - "2023-06-06T17:55:00+02:00", - "2023-06-06T18:00:00+02:00", - "2023-06-06T18:05:00+02:00", - "2023-06-06T18:10:00+02:00", - "2023-06-06T18:15:00+02:00", - "2023-06-06T18:20:00+02:00", - "2023-06-06T18:25:00+02:00", - "2023-06-06T18:30:00+02:00", - "2023-06-06T18:35:00+02:00", - "2023-06-06T18:40:00+02:00", - "2023-06-06T18:45:00+02:00", - "2023-06-06T18:50:00+02:00", - "2023-06-06T18:55:00+02:00", - "2023-06-06T19:00:00+02:00", - "2023-06-06T19:05:00+02:00", - "2023-06-06T19:10:00+02:00", - "2023-06-06T19:15:00+02:00", - "2023-06-06T19:20:00+02:00", - "2023-06-06T19:25:00+02:00", - "2023-06-06T19:30:00+02:00", - "2023-06-06T19:35:00+02:00", - "2023-06-06T19:40:00+02:00", - "2023-06-06T19:45:00+02:00", - "2023-06-06T19:50:00+02:00", - "2023-06-06T19:55:00+02:00", - "2023-06-06T20:00:00+02:00", - "2023-06-06T20:05:00+02:00", - "2023-06-06T20:10:00+02:00", - "2023-06-06T20:15:00+02:00", - "2023-06-06T20:20:00+02:00", - "2023-06-06T20:25:00+02:00", - "2023-06-06T20:30:00+02:00", - "2023-06-06T20:35:00+02:00", - "2023-06-06T20:40:00+02:00", - "2023-06-06T20:45:00+02:00", - "2023-06-06T20:50:00+02:00", - "2023-06-06T20:55:00+02:00", - "2023-06-06T21:00:00+02:00", - "2023-06-06T21:05:00+02:00", - "2023-06-06T21:10:00+02:00", - "2023-06-06T21:15:00+02:00", - "2023-06-06T21:20:00+02:00", - "2023-06-06T21:25:00+02:00", - "2023-06-06T21:30:00+02:00", - "2023-06-06T21:35:00+02:00", - "2023-06-06T21:40:00+02:00", - "2023-06-06T21:45:00+02:00", - "2023-06-06T21:50:00+02:00", - "2023-06-06T21:55:00+02:00", - "2023-06-06T22:00:00+02:00", - "2023-06-06T22:05:00+02:00", - "2023-06-06T22:10:00+02:00", - "2023-06-06T22:15:00+02:00", - "2023-06-06T22:20:00+02:00", - "2023-06-06T22:25:00+02:00", - "2023-06-06T22:30:00+02:00", - "2023-06-06T22:35:00+02:00", - "2023-06-06T22:40:00+02:00", - "2023-06-06T22:45:00+02:00", - "2023-06-06T22:50:00+02:00", - "2023-06-06T22:55:00+02:00", - "2023-06-06T23:00:00+02:00", - "2023-06-06T23:05:00+02:00", - "2023-06-06T23:10:00+02:00", - "2023-06-06T23:15:00+02:00", - "2023-06-06T23:20:00+02:00", - "2023-06-06T23:25:00+02:00", - "2023-06-06T23:30:00+02:00", - "2023-06-06T23:35:00+02:00", - "2023-06-06T23:40:00+02:00", - "2023-06-06T23:45:00+02:00", - "2023-06-06T23:50:00+02:00", - "2023-06-06T23:55:00+02:00", - "2023-06-07T00:00:00+02:00", - "2023-06-07T00:05:00+02:00", - "2023-06-07T00:10:00+02:00", - "2023-06-07T00:15:00+02:00", - "2023-06-07T00:20:00+02:00", - "2023-06-07T00:25:00+02:00", - "2023-06-07T00:30:00+02:00", - "2023-06-07T00:35:00+02:00", - "2023-06-07T00:40:00+02:00", - "2023-06-07T00:45:00+02:00", - "2023-06-07T00:50:00+02:00", - "2023-06-07T00:55:00+02:00", - "2023-06-07T01:00:00+02:00", - "2023-06-07T01:05:00+02:00", - "2023-06-07T01:10:00+02:00", - "2023-06-07T01:15:00+02:00", - "2023-06-07T01:20:00+02:00", - "2023-06-07T01:25:00+02:00", - "2023-06-07T01:30:00+02:00", - "2023-06-07T01:35:00+02:00", - "2023-06-07T01:40:00+02:00", - "2023-06-07T01:45:00+02:00", - "2023-06-07T01:50:00+02:00", - "2023-06-07T01:55:00+02:00", - "2023-06-07T02:00:00+02:00", - "2023-06-07T02:05:00+02:00", - "2023-06-07T02:10:00+02:00", - "2023-06-07T02:15:00+02:00", - "2023-06-07T02:20:00+02:00", - "2023-06-07T02:25:00+02:00", - "2023-06-07T02:30:00+02:00", - "2023-06-07T02:35:00+02:00", - "2023-06-07T02:40:00+02:00", - "2023-06-07T02:45:00+02:00", - "2023-06-07T02:50:00+02:00", - "2023-06-07T02:55:00+02:00", - "2023-06-07T03:00:00+02:00", - "2023-06-07T03:05:00+02:00", - "2023-06-07T03:10:00+02:00", - "2023-06-07T03:15:00+02:00", - "2023-06-07T03:20:00+02:00", - "2023-06-07T03:25:00+02:00", - "2023-06-07T03:30:00+02:00", - "2023-06-07T03:35:00+02:00", - "2023-06-07T03:40:00+02:00", - "2023-06-07T03:45:00+02:00", - "2023-06-07T03:50:00+02:00", - "2023-06-07T03:55:00+02:00", - "2023-06-07T04:00:00+02:00", - "2023-06-07T04:05:00+02:00", - "2023-06-07T04:10:00+02:00", - "2023-06-07T04:15:00+02:00", - "2023-06-07T04:20:00+02:00", - "2023-06-07T04:25:00+02:00", - "2023-06-07T04:30:00+02:00", - "2023-06-07T04:35:00+02:00", - "2023-06-07T04:40:00+02:00", - "2023-06-07T04:45:00+02:00", - "2023-06-07T04:50:00+02:00", - "2023-06-07T04:55:00+02:00", - "2023-06-07T05:00:00+02:00", - "2023-06-07T05:05:00+02:00", - "2023-06-07T05:10:00+02:00", - "2023-06-07T05:15:00+02:00", - "2023-06-07T05:20:00+02:00", - "2023-06-07T05:25:00+02:00", - "2023-06-07T05:30:00+02:00", - "2023-06-07T05:35:00+02:00", - "2023-06-07T05:40:00+02:00", - "2023-06-07T05:45:00+02:00", - "2023-06-07T05:50:00+02:00", - "2023-06-07T05:55:00+02:00", - "2023-06-07T06:00:00+02:00", - "2023-06-07T06:05:00+02:00", - "2023-06-07T06:10:00+02:00", - "2023-06-07T06:15:00+02:00", - "2023-06-07T06:20:00+02:00", - "2023-06-07T06:25:00+02:00", - "2023-06-07T06:30:00+02:00", - "2023-06-07T06:35:00+02:00", - "2023-06-07T06:40:00+02:00", - "2023-06-07T06:45:00+02:00", - "2023-06-07T06:50:00+02:00", - "2023-06-07T06:55:00+02:00", - "2023-06-07T07:00:00+02:00", - "2023-06-07T07:05:00+02:00", - "2023-06-07T07:10:00+02:00", - "2023-06-07T07:15:00+02:00", - "2023-06-07T07:20:00+02:00", - "2023-06-07T07:25:00+02:00", - "2023-06-07T07:30:00+02:00", - "2023-06-07T07:35:00+02:00", - "2023-06-07T07:40:00+02:00", - "2023-06-07T07:45:00+02:00", - "2023-06-07T07:50:00+02:00", - "2023-06-07T07:55:00+02:00", - "2023-06-07T08:00:00+02:00", - "2023-06-07T08:05:00+02:00", - "2023-06-07T08:10:00+02:00", - "2023-06-07T08:15:00+02:00", - "2023-06-07T08:20:00+02:00", - "2023-06-07T08:25:00+02:00", - "2023-06-07T08:30:00+02:00", - "2023-06-07T08:35:00+02:00", - "2023-06-07T08:40:00+02:00", - "2023-06-07T08:45:00+02:00", - "2023-06-07T08:50:00+02:00", - "2023-06-07T08:55:00+02:00", - "2023-06-07T09:00:00+02:00", - "2023-06-07T09:05:00+02:00", - "2023-06-07T09:10:00+02:00", - "2023-06-07T09:15:00+02:00", - "2023-06-07T09:20:00+02:00", - "2023-06-07T09:25:00+02:00", - "2023-06-07T09:30:00+02:00", - "2023-06-07T09:35:00+02:00", - "2023-06-07T09:40:00+02:00", - "2023-06-07T09:45:00+02:00", - "2023-06-07T09:50:00+02:00", - "2023-06-07T09:55:00+02:00", - "2023-06-07T10:00:00+02:00", - "2023-06-07T10:05:00+02:00", - "2023-06-07T10:10:00+02:00", - "2023-06-07T10:15:00+02:00", - "2023-06-07T10:20:00+02:00", - "2023-06-07T10:25:00+02:00", - "2023-06-07T10:30:00+02:00", - "2023-06-07T10:35:00+02:00", - "2023-06-07T10:40:00+02:00", - "2023-06-07T10:45:00+02:00", - "2023-06-07T10:50:00+02:00", - "2023-06-07T10:55:00+02:00", - "2023-06-07T11:00:00+02:00", - "2023-06-07T11:05:00+02:00", - "2023-06-07T11:10:00+02:00", - "2023-06-07T11:15:00+02:00", - "2023-06-07T11:20:00+02:00", - "2023-06-07T11:25:00+02:00", - "2023-06-07T11:30:00+02:00", - "2023-06-07T11:35:00+02:00", - "2023-06-07T11:40:00+02:00", - "2023-06-07T11:45:00+02:00", - "2023-06-07T11:50:00+02:00", - "2023-06-07T11:55:00+02:00", - "2023-06-07T12:00:00+02:00", - "2023-06-07T12:05:00+02:00", - "2023-06-07T12:10:00+02:00", - "2023-06-07T12:15:00+02:00", - "2023-06-07T12:20:00+02:00", - "2023-06-07T12:25:00+02:00", - "2023-06-07T12:30:00+02:00", - "2023-06-07T12:35:00+02:00", - "2023-06-07T12:40:00+02:00", - "2023-06-07T12:45:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayForward.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayForward.json deleted file mode 100644 index ef73bb0a72..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayForward.json +++ /dev/null @@ -1,1338 +0,0 @@ -{ - "global": { - "title": "oracle-shared-spool-ratio graph on srv-oracle-users", - "start": "2023-06-07T09:27:07+02:00", - "end": "2023-06-08T09:27:07+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 0, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 4811, - "metric_id": 11758, - "metric": "connTime", - "metric_legend": "connTime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#ff99cc" - }, - "legend": "connTime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 0.05376, - 0.338, - 0.63248, - 0.18326666667, - 0.36706666667, - 0.099166666667, - 0.31305, - 0.37373333333, - 0.43933333333, - 0.464, - 0.35258333333, - 0.28791666667, - 0.56913333333, - 0.76703333333, - 0.67518333333, - 0.90208333333, - 0.32488333333, - 0.47813333333, - 0.071966666667, - 0.3686, - 0.8341, - 0.77396666667, - 0.34295, - 0.51203333333, - 0.23581666667, - 0.14966666667, - 0.53633333333, - 0.66725, - 0.44083333333, - 0.40603333333, - 0.76311666667, - 0.76126666667, - 0.20203333333, - 0.50725, - 0.37375, - 0.7752, - 0.71796666667, - 0.65141666667, - 0.63618333333, - 0.46131666667, - 0.63278333333, - 0.77115, - 0.47151666667, - 0.63983333333, - 0.6915, - 0.55061666667, - 0.7759, - 0.79126666667, - 0.38161666667, - 0.42606666667, - 0.75068333333, - 0.40968333333, - 0.6918, - 0.44128333333, - 0.46593333333, - 0.20545, - 0.61953333333, - 0.72133333333, - 0.61795, - 0.7154, - 0.30433333333, - 0.38171666667, - 0.17726666667, - 0.19431666667, - 0.33643333333, - 0.73506666667, - 0.90695, - 0.83988333333, - 0.92438333333, - 0.54573333333, - 0.3909, - 0.82456666667, - 0.5597, - 0.66463333333, - 0.66005, - 0.52756666667, - 0.67001666667, - 0.4347, - 0.20076666667, - 0.199, - 0.45465, - 0.7167, - 0.4992, - 0.7525, - 0.68343333333, - 0.18691666667, - 0.10928333333, - 0.49846666667, - 0.20756666667, - 0.57808333333, - 0.5091, - 0.21378333333, - 0.33466666667, - 0.35905, - 0.7782, - 0.31376666667, - 0.30773333333, - 0.55781666667, - 0.61033333333, - 0.61753333333, - 0.78033333333, - 0.67196666667, - 0.83675, - 0.5666, - 0.31156666667, - 0.74395, - 0.58471666667, - 0.73915, - 0.411, - 0.25175, - 0.44345, - 0.85811666667, - 0.78576666667, - 0.54195, - 0.6819, - 0.77463333333, - 0.53966666667, - 0.081583333333, - 0.0105, - 0.66158333333, - 0.19941666667, - 0.3885, - 0.72716666667, - 0.34625, - 0.15866666667, - 0.80133333333, - 0.35021666667, - 0.40711666667, - 0.31185, - 0.50205, - 0.88026666667, - 0.57613333333, - 0.43963333333, - 0.32051666667, - 0.50523333333, - 0.6505, - 0.55111666667, - 0.5942, - 0.72986666667, - 0.95238333333, - 0.68285, - 0.46565, - 0.63016666667, - 0.45605, - 0.38395, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null - ], - "prints": [ - [ - "Last:0.38" - ], - [ - "Min:0.01" - ], - [ - "Max:0.95" - ], - [ - "Average:0.51" - ] - ], - "last_value": 0.38, - "minimum_value": 0.01, - "maximum_value": 0.95, - "average_value": 0.51 - }, - { - "index_id": 4811, - "metric_id": 11757, - "metric": "querytime", - "metric_legend": "querytime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#6666ff" - }, - "legend": "querytime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 0.69412, - 0.29608, - 0.64332, - 0.78435, - 0.49911666667, - 0.26918333333, - 0.91718333333, - 0.5858, - 0.19691666667, - 0.44683333333, - 0.33975, - 0.23175, - 0.54105, - 0.58516666667, - 0.62908333333, - 0.21381666667, - 0.054433333333, - 0.41883333333, - 0.55065, - 0.74241666667, - 0.20685, - 0.73463333333, - 0.67131666667, - 0.27435, - 0.34288333333, - 0.7709, - 0.92633333333, - 0.6353, - 0.7674, - 0.79433333333, - 0.6929, - 0.36873333333, - 0.15238333333, - 0.45986666667, - 0.72241666667, - 0.71251666667, - 0.39875, - 0.70755, - 0.60123333333, - 0.83198333333, - 0.9789, - 0.57765, - 0.17835, - 0.5656, - 0.36398333333, - 0.46198333333, - 0.31618333333, - 0.3781, - 0.25323333333, - 0.1532, - 0.04195, - 0.23205, - 0.78596666667, - 0.43723333333, - 0.28218333333, - 0.72755, - 0.77603333333, - 0.68743333333, - 0.66741666667, - 0.34995, - 0.37335, - 0.69358333333, - 0.27455, - 0.28013333333, - 0.71015, - 0.50801666667, - 0.45211666667, - 0.76751666667, - 0.75243333333, - 0.2591, - 0.43015, - 0.36633333333, - 0.66898333333, - 0.79993333333, - 0.38278333333, - 0.43815, - 0.7089, - 0.57918333333, - 0.36856666667, - 0.65455, - 0.74285, - 0.91205, - 0.78031666667, - 0.71691666667, - 0.69246666667, - 0.5553, - 0.81631666667, - 0.82576666667, - 0.64196666667, - 0.35766666667, - 0.52513333333, - 0.59181666667, - 0.48015, - 0.17466666667, - 0.53273333333, - 0.78308333333, - 0.49533333333, - 0.71715, - 0.45326666667, - 0.34505, - 0.55813333333, - 0.58506666667, - 0.51556666667, - 0.25808333333, - 0.32178333333, - 0.87881666667, - 0.73263333333, - 0.29503333333, - 0.51955, - 0.80328333333, - 0.61133333333, - 0.88905, - 0.73008333333, - 0.46576666667, - 0.75335, - 0.64886666667, - 0.46566666667, - 0.23391666667, - 0.32333333333, - 0.06075, - 0.52183333333, - 0.75116666667, - 0.65341666667, - 0.41658333333, - 0.044, - 0.5455, - 0.66271666667, - 0.45943333333, - 0.34365, - 0.62895, - 0.69748333333, - 0.57913333333, - 0.42935, - 0.3825, - 0.5489, - 0.61453333333, - 0.52853333333, - 0.58836666667, - 0.70246666667, - 0.68868333333, - 0.69335, - 0.4246, - 0.40923333333, - 0.8041, - 0.6626, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null - ], - "prints": [ - [ - "Last:0.66" - ], - [ - "Min:0.04" - ], - [ - "Max:0.98" - ], - [ - "Average:0.54" - ] - ], - "last_value": 0.66, - "minimum_value": 0.04, - "maximum_value": 0.98, - "average_value": 0.54 - }, - { - "index_id": 4811, - "metric_id": 11756, - "metric": "used", - "metric_legend": "used", - "unit": "%", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 8, - "host_id": null, - "service_id": null, - "name": "Used", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": "used", - "ds_color_line": "#2B28D7", - "ds_color_line_mode": "0", - "ds_color_area": "#050AF9", - "ds_color_area_warn": null, - "ds_color_area_crit": null, - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "used", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 1, - "data": [ - 81.5376, - 82.84972, - 83.50108, - 84.304366667, - 85.243566667, - 84.993333333, - 85.029616667, - 85.006383333, - 87.494416667, - 87.404, - 85.760416667, - 84.159166667, - 84.6812, - 84.468933333, - 84.2907, - 85.632833333, - 86.488066667, - 86.844516667, - 85.46465, - 84.358816667, - 82.004933333, - 82.207066667, - 81.247933333, - 79.504016667, - 79.532266667, - 79.924433333, - 79.03195, - 78.851233333, - 79.726933333, - 78.68965, - 78.418016667, - 78.223866667, - 76.752933333, - 75.281316667, - 73.84245, - 74.192566667, - 73.325533333, - 72.3546, - 71.02525, - 70.578283333, - 70.88545, - 73.86865, - 74.6044, - 74.356266667, - 74.481966667, - 74.988183333, - 74.891383333, - 74.5475, - 75.7053, - 76.809883333, - 77.069633333, - 76.012033333, - 75.40825, - 74.519, - 73.10165, - 73.826416667, - 73.605316667, - 72.003283333, - 71.210116667, - 70.476483333, - 73.647933333, - 76.360233333, - 78.137116667, - 78.928, - 78.254366667, - 78.312233333, - 78.939166667, - 79.256566667, - 78.5502, - 77.899116667, - 77.274816667, - 77.20985, - 77.566733333, - 77.3999, - 78.054983333, - 77.6581, - 78.215916667, - 78.121733333, - 78.28725, - 78.265633333, - 79.1123, - 79.665216667, - 81.06855, - 81.349333333, - 81.25085, - 82.1874, - 82.52145, - 83.712433333, - 85.337816667, - 84.673283333, - 83.360283333, - 83.58445, - 84.609016667, - 84.876033333, - 86.26595, - 86.732966667, - 87.697766667, - 88.536166667, - 87.30565, - 86.810316667, - 87.667166667, - 88.473583333, - 88.096516667, - 87.201566667, - 87.690583333, - 88.866416667, - 88.943983333, - 87.828033333, - 86.688216667, - 85.928366667, - 85.887183333, - 86.7506, - 86.304166667, - 85.379783333, - 85.705133333, - 84.564433333, - 82.771166667, - 81.506916667, - 82.213583333, - 82.514333333, - 83.525916667, - 83.594916667, - 84.6655, - 85.179166667, - 85.782583333, - 84.465416667, - 83.6318, - 84.248066667, - 86.10535, - 87.008783333, - 87.892233333, - 89.5511, - 91.161083333, - 92.036366667, - 91.702066667, - 90.579833333, - 90.5435, - 90.649233333, - 90.199233333, - 90.253016667, - 91.326716667, - 93.229816667, - 93.5479, - 93.26945, - 93.073233333, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null - ], - "prints": [ - [ - "Last:93.07" - ], - [ - "Average:82.08" - ] - ], - "last_value": 93.07, - "minimum_value": null, - "maximum_value": null, - "average_value": 82.08 - } - ], - "times": [ - "2023-06-07T09:30:00+02:00", - "2023-06-07T09:35:00+02:00", - "2023-06-07T09:40:00+02:00", - "2023-06-07T09:45:00+02:00", - "2023-06-07T09:50:00+02:00", - "2023-06-07T09:55:00+02:00", - "2023-06-07T10:00:00+02:00", - "2023-06-07T10:05:00+02:00", - "2023-06-07T10:10:00+02:00", - "2023-06-07T10:15:00+02:00", - "2023-06-07T10:20:00+02:00", - "2023-06-07T10:25:00+02:00", - "2023-06-07T10:30:00+02:00", - "2023-06-07T10:35:00+02:00", - "2023-06-07T10:40:00+02:00", - "2023-06-07T10:45:00+02:00", - "2023-06-07T10:50:00+02:00", - "2023-06-07T10:55:00+02:00", - "2023-06-07T11:00:00+02:00", - "2023-06-07T11:05:00+02:00", - "2023-06-07T11:10:00+02:00", - "2023-06-07T11:15:00+02:00", - "2023-06-07T11:20:00+02:00", - "2023-06-07T11:25:00+02:00", - "2023-06-07T11:30:00+02:00", - "2023-06-07T11:35:00+02:00", - "2023-06-07T11:40:00+02:00", - "2023-06-07T11:45:00+02:00", - "2023-06-07T11:50:00+02:00", - "2023-06-07T11:55:00+02:00", - "2023-06-07T12:00:00+02:00", - "2023-06-07T12:05:00+02:00", - "2023-06-07T12:10:00+02:00", - "2023-06-07T12:15:00+02:00", - "2023-06-07T12:20:00+02:00", - "2023-06-07T12:25:00+02:00", - "2023-06-07T12:30:00+02:00", - "2023-06-07T12:35:00+02:00", - "2023-06-07T12:40:00+02:00", - "2023-06-07T12:45:00+02:00", - "2023-06-07T12:50:00+02:00", - "2023-06-07T12:55:00+02:00", - "2023-06-07T13:00:00+02:00", - "2023-06-07T13:05:00+02:00", - "2023-06-07T13:10:00+02:00", - "2023-06-07T13:15:00+02:00", - "2023-06-07T13:20:00+02:00", - "2023-06-07T13:25:00+02:00", - "2023-06-07T13:30:00+02:00", - "2023-06-07T13:35:00+02:00", - "2023-06-07T13:40:00+02:00", - "2023-06-07T13:45:00+02:00", - "2023-06-07T13:50:00+02:00", - "2023-06-07T13:55:00+02:00", - "2023-06-07T14:00:00+02:00", - "2023-06-07T14:05:00+02:00", - "2023-06-07T14:10:00+02:00", - "2023-06-07T14:15:00+02:00", - "2023-06-07T14:20:00+02:00", - "2023-06-07T14:25:00+02:00", - "2023-06-07T14:30:00+02:00", - "2023-06-07T14:35:00+02:00", - "2023-06-07T14:40:00+02:00", - "2023-06-07T14:45:00+02:00", - "2023-06-07T14:50:00+02:00", - "2023-06-07T14:55:00+02:00", - "2023-06-07T15:00:00+02:00", - "2023-06-07T15:05:00+02:00", - "2023-06-07T15:10:00+02:00", - "2023-06-07T15:15:00+02:00", - "2023-06-07T15:20:00+02:00", - "2023-06-07T15:25:00+02:00", - "2023-06-07T15:30:00+02:00", - "2023-06-07T15:35:00+02:00", - "2023-06-07T15:40:00+02:00", - "2023-06-07T15:45:00+02:00", - "2023-06-07T15:50:00+02:00", - "2023-06-07T15:55:00+02:00", - "2023-06-07T16:00:00+02:00", - "2023-06-07T16:05:00+02:00", - "2023-06-07T16:10:00+02:00", - "2023-06-07T16:15:00+02:00", - "2023-06-07T16:20:00+02:00", - "2023-06-07T16:25:00+02:00", - "2023-06-07T16:30:00+02:00", - "2023-06-07T16:35:00+02:00", - "2023-06-07T16:40:00+02:00", - "2023-06-07T16:45:00+02:00", - "2023-06-07T16:50:00+02:00", - "2023-06-07T16:55:00+02:00", - "2023-06-07T17:00:00+02:00", - "2023-06-07T17:05:00+02:00", - "2023-06-07T17:10:00+02:00", - "2023-06-07T17:15:00+02:00", - "2023-06-07T17:20:00+02:00", - "2023-06-07T17:25:00+02:00", - "2023-06-07T17:30:00+02:00", - "2023-06-07T17:35:00+02:00", - "2023-06-07T17:40:00+02:00", - "2023-06-07T17:45:00+02:00", - "2023-06-07T17:50:00+02:00", - "2023-06-07T17:55:00+02:00", - "2023-06-07T18:00:00+02:00", - "2023-06-07T18:05:00+02:00", - "2023-06-07T18:10:00+02:00", - "2023-06-07T18:15:00+02:00", - "2023-06-07T18:20:00+02:00", - "2023-06-07T18:25:00+02:00", - "2023-06-07T18:30:00+02:00", - "2023-06-07T18:35:00+02:00", - "2023-06-07T18:40:00+02:00", - "2023-06-07T18:45:00+02:00", - "2023-06-07T18:50:00+02:00", - "2023-06-07T18:55:00+02:00", - "2023-06-07T19:00:00+02:00", - "2023-06-07T19:05:00+02:00", - "2023-06-07T19:10:00+02:00", - "2023-06-07T19:15:00+02:00", - "2023-06-07T19:20:00+02:00", - "2023-06-07T19:25:00+02:00", - "2023-06-07T19:30:00+02:00", - "2023-06-07T19:35:00+02:00", - "2023-06-07T19:40:00+02:00", - "2023-06-07T19:45:00+02:00", - "2023-06-07T19:50:00+02:00", - "2023-06-07T19:55:00+02:00", - "2023-06-07T20:00:00+02:00", - "2023-06-07T20:05:00+02:00", - "2023-06-07T20:10:00+02:00", - "2023-06-07T20:15:00+02:00", - "2023-06-07T20:20:00+02:00", - "2023-06-07T20:25:00+02:00", - "2023-06-07T20:30:00+02:00", - "2023-06-07T20:35:00+02:00", - "2023-06-07T20:40:00+02:00", - "2023-06-07T20:45:00+02:00", - "2023-06-07T20:50:00+02:00", - "2023-06-07T20:55:00+02:00", - "2023-06-07T21:00:00+02:00", - "2023-06-07T21:05:00+02:00", - "2023-06-07T21:10:00+02:00", - "2023-06-07T21:15:00+02:00", - "2023-06-07T21:20:00+02:00", - "2023-06-07T21:25:00+02:00", - "2023-06-07T21:30:00+02:00", - "2023-06-07T21:35:00+02:00", - "2023-06-07T21:40:00+02:00", - "2023-06-07T21:45:00+02:00", - "2023-06-07T21:50:00+02:00", - "2023-06-07T21:55:00+02:00", - "2023-06-07T22:00:00+02:00", - "2023-06-07T22:05:00+02:00", - "2023-06-07T22:10:00+02:00", - "2023-06-07T22:15:00+02:00", - "2023-06-07T22:20:00+02:00", - "2023-06-07T22:25:00+02:00", - "2023-06-07T22:30:00+02:00", - "2023-06-07T22:35:00+02:00", - "2023-06-07T22:40:00+02:00", - "2023-06-07T22:45:00+02:00", - "2023-06-07T22:50:00+02:00", - "2023-06-07T22:55:00+02:00", - "2023-06-07T23:00:00+02:00", - "2023-06-07T23:05:00+02:00", - "2023-06-07T23:10:00+02:00", - "2023-06-07T23:15:00+02:00", - "2023-06-07T23:20:00+02:00", - "2023-06-07T23:25:00+02:00", - "2023-06-07T23:30:00+02:00", - "2023-06-07T23:35:00+02:00", - "2023-06-07T23:40:00+02:00", - "2023-06-07T23:45:00+02:00", - "2023-06-07T23:50:00+02:00", - "2023-06-07T23:55:00+02:00", - "2023-06-08T00:00:00+02:00", - "2023-06-08T00:05:00+02:00", - "2023-06-08T00:10:00+02:00", - "2023-06-08T00:15:00+02:00", - "2023-06-08T00:20:00+02:00", - "2023-06-08T00:25:00+02:00", - "2023-06-08T00:30:00+02:00", - "2023-06-08T00:35:00+02:00", - "2023-06-08T00:40:00+02:00", - "2023-06-08T00:45:00+02:00", - "2023-06-08T00:50:00+02:00", - "2023-06-08T00:55:00+02:00", - "2023-06-08T01:00:00+02:00", - "2023-06-08T01:05:00+02:00", - "2023-06-08T01:10:00+02:00", - "2023-06-08T01:15:00+02:00", - "2023-06-08T01:20:00+02:00", - "2023-06-08T01:25:00+02:00", - "2023-06-08T01:30:00+02:00", - "2023-06-08T01:35:00+02:00", - "2023-06-08T01:40:00+02:00", - "2023-06-08T01:45:00+02:00", - "2023-06-08T01:50:00+02:00", - "2023-06-08T01:55:00+02:00", - "2023-06-08T02:00:00+02:00", - "2023-06-08T02:05:00+02:00", - "2023-06-08T02:10:00+02:00", - "2023-06-08T02:15:00+02:00", - "2023-06-08T02:20:00+02:00", - "2023-06-08T02:25:00+02:00", - "2023-06-08T02:30:00+02:00", - "2023-06-08T02:35:00+02:00", - "2023-06-08T02:40:00+02:00", - "2023-06-08T02:45:00+02:00", - "2023-06-08T02:50:00+02:00", - "2023-06-08T02:55:00+02:00", - "2023-06-08T03:00:00+02:00", - "2023-06-08T03:05:00+02:00", - "2023-06-08T03:10:00+02:00", - "2023-06-08T03:15:00+02:00", - "2023-06-08T03:20:00+02:00", - "2023-06-08T03:25:00+02:00", - "2023-06-08T03:30:00+02:00", - "2023-06-08T03:35:00+02:00", - "2023-06-08T03:40:00+02:00", - "2023-06-08T03:45:00+02:00", - "2023-06-08T03:50:00+02:00", - "2023-06-08T03:55:00+02:00", - "2023-06-08T04:00:00+02:00", - "2023-06-08T04:05:00+02:00", - "2023-06-08T04:10:00+02:00", - "2023-06-08T04:15:00+02:00", - "2023-06-08T04:20:00+02:00", - "2023-06-08T04:25:00+02:00", - "2023-06-08T04:30:00+02:00", - "2023-06-08T04:35:00+02:00", - "2023-06-08T04:40:00+02:00", - "2023-06-08T04:45:00+02:00", - "2023-06-08T04:50:00+02:00", - "2023-06-08T04:55:00+02:00", - "2023-06-08T05:00:00+02:00", - "2023-06-08T05:05:00+02:00", - "2023-06-08T05:10:00+02:00", - "2023-06-08T05:15:00+02:00", - "2023-06-08T05:20:00+02:00", - "2023-06-08T05:25:00+02:00", - "2023-06-08T05:30:00+02:00", - "2023-06-08T05:35:00+02:00", - "2023-06-08T05:40:00+02:00", - "2023-06-08T05:45:00+02:00", - "2023-06-08T05:50:00+02:00", - "2023-06-08T05:55:00+02:00", - "2023-06-08T06:00:00+02:00", - "2023-06-08T06:05:00+02:00", - "2023-06-08T06:10:00+02:00", - "2023-06-08T06:15:00+02:00", - "2023-06-08T06:20:00+02:00", - "2023-06-08T06:25:00+02:00", - "2023-06-08T06:30:00+02:00", - "2023-06-08T06:35:00+02:00", - "2023-06-08T06:40:00+02:00", - "2023-06-08T06:45:00+02:00", - "2023-06-08T06:50:00+02:00", - "2023-06-08T06:55:00+02:00", - "2023-06-08T07:00:00+02:00", - "2023-06-08T07:05:00+02:00", - "2023-06-08T07:10:00+02:00", - "2023-06-08T07:15:00+02:00", - "2023-06-08T07:20:00+02:00", - "2023-06-08T07:25:00+02:00", - "2023-06-08T07:30:00+02:00", - "2023-06-08T07:35:00+02:00", - "2023-06-08T07:40:00+02:00", - "2023-06-08T07:45:00+02:00", - "2023-06-08T07:50:00+02:00", - "2023-06-08T07:55:00+02:00", - "2023-06-08T08:00:00+02:00", - "2023-06-08T08:05:00+02:00", - "2023-06-08T08:10:00+02:00", - "2023-06-08T08:15:00+02:00", - "2023-06-08T08:20:00+02:00", - "2023-06-08T08:25:00+02:00", - "2023-06-08T08:30:00+02:00", - "2023-06-08T08:35:00+02:00", - "2023-06-08T08:40:00+02:00", - "2023-06-08T08:45:00+02:00", - "2023-06-08T08:50:00+02:00", - "2023-06-08T08:55:00+02:00", - "2023-06-08T09:00:00+02:00", - "2023-06-08T09:05:00+02:00", - "2023-06-08T09:10:00+02:00", - "2023-06-08T09:15:00+02:00", - "2023-06-08T09:20:00+02:00", - "2023-06-08T09:25:00+02:00", - "2023-06-08T09:30:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayThreshold.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayThreshold.json deleted file mode 100644 index c75d4a4b88..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayThreshold.json +++ /dev/null @@ -1,2352 +0,0 @@ -{ - "global": { - "title": "anomaly-nbr-connect graph on fw-brasilia", - "start": "2023-06-14T17:31:46+02:00", - "end": "2023-06-15T17:31:46+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 1, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 152032, - "metric_id": 15165, - "metric": "connection", - "metric_legend": "connection", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#993366" - }, - "legend": "connection", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 120.88, - 119.98333333, - 161.63, - 136.94666667, - 152.69666667, - 52.246666667, - 16.236666667, - 14.796666667, - 20.576666667, - 24.39, - 26.593333333, - 24.61, - 24.796666667, - 13.846666667, - 25.34, - 28.203333333, - 17.643333333, - 25.356666667, - 17.643333333, - 24.56, - 19.033333333, - 20.983333333, - 18.813333333, - 25.17, - 13.456666667, - 25.136666667, - 29, - 14.66, - 24.543333333, - 21.626666667, - 14.423333333, - 18.576666667, - 20.796666667, - 25.78, - 20.626666667, - 15.813333333, - 18.186666667, - 25.373333333, - 14.253333333, - 21.356666667, - 18.423333333, - 21.78, - 22.203333333, - 27.576666667, - 27.406666667, - 22.22, - 25.78, - 15.846666667, - 15.39, - 22.373333333, - 20.813333333, - 23.983333333, - 28.186666667, - 26.61, - 26, - 22.813333333, - 18.016666667, - 13.813333333, - 16.186666667, - 17.796666667, - 21.983333333, - 14.236666667, - 23.153333333, - 17.236666667, - 15, - 20.576666667, - 22.796666667, - 27.78, - 28.203333333, - 27.203333333, - 14.253333333, - 13.39, - 21.17, - 19.813333333, - 22.186666667, - 14.236666667, - 22.356666667, - 15.44, - 14.593333333, - 12.61, - 24.746666667, - 24.813333333, - 17.626666667, - 12.813333333, - 16.78, - 20.39, - 21, - 17.813333333, - 20.983333333, - 25.186666667, - 17.236666667, - 21.373333333, - 19.813333333, - 21.39, - 14.033333333, - 10.406666667, - 22.746666667, - 21.22, - 23.983333333, - 13.846666667, - 16.576666667, - 20.39, - 13.033333333, - 24.543333333, - 22.423333333, - 24.186666667, - 27.39, - 16.05, - 23.356666667, - 18.033333333, - 20.78, - 18.016666667, - 18.593333333, - 26.17, - 21.626666667, - 16.016666667, - 14.203333333, - 17.186666667, - 25.966666667, - 24.813333333, - 27.983333333, - 24.22, - 12.643333333, - 21.95, - 21.016666667, - 19.203333333, - 20.593333333, - 21, - 22.593333333, - 19.016666667, - 17.203333333, - 11.423333333, - 18.763333333, - 21, - 19.406666667, - 13.446666667, - 16.76, - 25.14, - 27.793333333, - 24.826666667, - 20.033333333, - 22.173333333, - 25.38, - 18.066666667, - 18.38, - 16.62, - 12.033333333, - 12.586666667, - 13.793333333, - 11.62, - 11, - 18.933333333, - 25.76, - 15.1, - 15.173333333, - 21.553333333, - 27.76, - 24.24, - 15.86, - 17.966666667, - 24.553333333, - 16.48, - 24.313333333, - 22.24, - 22.586666667, - 27.76, - 18.686666667, - 19.966666667, - 23.38, - 13.686666667, - 23.693333333, - 23.033333333, - 25.173333333, - 22.826666667, - 19.62, - 11.86, - 17.14, - 18.206666667, - 19.586666667, - 26.346666667, - 28.793333333, - 18.686666667, - 11.24, - 16.346666667, - 15.62, - 83.226666667, - 127.96666667, - 104.84, - 108.50666667, - 148.44666667, - 161.2, - 132.94, - 119.67333333, - 139.44666667, - 161.86666667, - 169.49333333, - 133.61333333, - 133.35333333, - 137.84, - 137.44666667, - 153.29333333, - 147.60666667, - 168.1, - 150.2, - 128.70666667, - 133.62, - 113.96, - 131.78666667, - 99.693333333, - 148.62666667, - 94.873333333, - 88.126666667, - 101.25333333, - 126.34666667, - 160.09333333, - 165.65333333, - 137.51333333, - 152.64, - 159.82, - 116.34666667, - 150.28666667, - 148.14666667, - 90.506666667, - 124.84, - 131.21333333, - 175.1, - 155.07333333, - 116.39333333, - 101.31333333, - 141.41333333, - 156.46, - 131.38, - 162.25333333, - 182.70666667, - 181.82, - 124.62, - 96.646666667, - 96.413333333, - 124.22, - 146.96666667, - 140.75333333, - 106.12, - 144.83333333, - 152.43333333, - 97.293333333, - 96.44, - 142.32, - 142.33333333, - 103.74, - 118.54, - 145.55333333, - 122.16666667, - 109.15333333, - 134.74666667, - 117.19333333, - 122.83333333, - 152.28, - 170.50666667, - 93.506666667, - 122.23333333, - 95.353333333, - 114.72666667, - 164.26666667, - 130.64666667, - 121.90666667, - 110.93333333, - 119.96666667, - 119.16666667, - 104.02666667, - 121.52, - 109.9, - 125.09333333, - 130.84666667, - 116.08, - 174.16666667, - 151.1, - 144.02666667, - 162.48666667, - 145.42666667, - 131.92, - 169.31333333, - 87.253333333, - 115.05333333, - 145.20666667, - 96.966666667, - 104.28666667, - 111.42666667, - null, - null - ], - "prints": [ - [ - "Last:111.43" - ], - [ - "Min:10.41" - ], - [ - "Max:182.71" - ], - [ - "Average:61.78" - ] - ], - "last_value": 111.43, - "minimum_value": 10.41, - "maximum_value": 182.71, - "average_value": 61.78 - }, - { - "index_id": 152032, - "metric_id": 16196, - "metric": "connection_fit", - "metric_legend": "connection_fit", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#9933ff" - }, - "legend": "connection_fit", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 130.99763333, - 131.10763333, - 131.1778, - 131.08643333, - 130.95643333, - 125.59233333, - 98.3463, - 65.8563, - 37.923233333, - 29.0145, - 24.6645, - 21.015566667, - 20.31, - 20.31, - 20.270166667, - 20.060833333, - 19.810833333, - 19.5688, - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.139333333, - 19.3473, - 19.493566667, - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.139333333, - 19.3473, - 19.493566667, - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.139333333, - 19.3473, - 19.493566667, - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.139333333, - 19.3473, - 19.493566667, - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.139333333, - 19.3473, - 19.493566667, - 19.3527, - 19.1427, - 18.964566667, - 18.93, - 18.93, - 18.93, - 18.93, - 18.93, - 18.969833333, - 19.155266667, - 19.375266667, - 19.523566667, - 19.3827, - 19.1727, - 18.994566667, - 18.96, - 18.96, - 18.96, - 18.96, - 18.96, - 19.0556, - 19.550033333, - 20.140033333, - 20.634433333, - 20.73, - 20.73, - 20.722033333, - 20.656266667, - 20.584233333, - 20.554066667, - 20.6695, - 20.8195, - 20.8978, - 20.663033333, - 20.345066667, - 20.0888, - 20.04, - 20.04, - 20.04, - 20.047966667, - 20.057966667, - 20.1078, - 20.295266667, - 20.523233333, - 20.673566667, - 20.5088, - 20.276766667, - 20.078633333, - 20.04, - 20.04, - 20.04, - 20.047966667, - 20.057966667, - 20.1078, - 20.295266667, - 20.523233333, - 20.673566667, - 20.5096, - 20.2696, - 20.069266667, - 20.03, - 20.03, - 20.03, - 20.045866667, - 20.057933333, - 20.091733333, - 20.234866667, - 20.396933333, - 20.509333333, - 20.371333333, - 20.171333333, - 20.003066667, - 19.97, - 19.97, - 19.97, - 19.977933333, - 19.987933333, - 20.005866667, - 20.065533333, - 20.1276, - 20.179666667, - 20.150333333, - 20.108266667, - 20.0762, - 20.07, - 20.07, - 20.07, - 20.077933333, - 20.087933333, - 20.105866667, - 20.165533333, - 20.2276, - 20.24, - 20.041666667, - 19.783733333, - 19.571333333, - 19.53, - 19.53, - 19.537933333, - 19.547933333, - 19.557933333, - 19.567933333, - 19.5938, - 19.631733333, - 19.8304, - 20.7368, - 21.808866667, - 27.519866667, - 45.074866667, - 81.596266667, - 107.08186667, - 115.47386667, - 119.99193333, - 123.8156, - 124.61126667, - 124.72126667, - 125.02846667, - 126.20293333, - 127.56486667, - 128.757, - 129.16253333, - 129.38253333, - 129.5658, - 129.5842, - 129.5542, - 129.5474, - 129.64126667, - 129.75126667, - 129.93666667, - 130.456, - 131.056, - 131.56126667, - 131.65, - 131.65, - 131.64613333, - 131.6242, - 131.59613333, - 131.59546667, - 131.68126667, - 131.79126667, - 131.85486667, - 131.7152, - 131.5352, - 131.3842, - 131.36, - 131.36, - 131.35613333, - 131.3342, - 131.3042, - 131.2974, - 131.38933333, - 131.49126667, - 131.57226667, - 131.52453333, - 131.4426, - 131.36806667, - 131.36, - 131.36, - 131.35613333, - 131.3342, - 131.3042, - 131.2974, - 131.38933333, - 131.49126667, - 131.57226667, - 131.52453333, - 131.4426, - 131.36806667, - 131.36, - 131.36, - 131.35613333, - 131.3342, - 131.3042, - 131.2974, - 131.38933333, - 131.49126667, - 131.59546667, - 131.67353333, - 131.7416, - 131.79193333, - 131.8, - 131.8, - 131.79613333, - 131.77613333, - 131.7542, - 131.74546667, - 131.83126667, - 131.94126667, - 132.02226667, - 131.9726, - 131.88453333, - 131.81613333, - 131.8, - 131.8, - 131.79613333, - 131.77613333, - 131.7542, - 131.74546667, - 131.83126667, - 131.94126667, - 132.02226667, - 131.9726, - 131.88453333, - 131.81613333, - 131.8, - 131.8, - 131.79613333, - 131.77613333, - 131.7542, - null, - null - ], - "prints": [ - [ - "Last:131.75" - ], - [ - "Min:18.93" - ], - [ - "Max:132.02" - ], - [ - "Average:61.08" - ] - ], - "last_value": 131.75, - "minimum_value": 18.93, - "maximum_value": 132.02, - "average_value": 61.08 - }, - { - "index_id": 152032, - "metric_id": 16197, - "metric": "connection_lower_margin", - "metric_legend": "connection_lower_margin", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#00ff99" - }, - "legend": "connection_lower_margin", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -88.792933333, - -67.8513, - -42.869266667, - -21.928366667, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -17.88, - -21.9736, - -36.769466667, - -67.8514, - -88.9438, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - -92.84, - null, - null - ], - "prints": [ - [ - "Last:-92.84" - ], - [ - "Min:-92.84" - ], - [ - "Max:-17.88" - ], - [ - "Average:-45.81" - ] - ], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - }, - { - "index_id": 152032, - "metric_id": 16198, - "metric": "connection_upper_margin", - "metric_legend": "connection_upper_margin", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#9900ff" - }, - "legend": "connection_upper_margin", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 76.405833333, - 56.8458, - 33.497833333, - 13.932, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 10.15, - 13.9818, - 27.801, - 56.8424, - 76.543866667, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - 80.19, - null, - null - ], - "prints": [ - [ - "Last:80.19" - ], - [ - "Min:10.15" - ], - [ - "Max:80.19" - ], - [ - "Average:36.24" - ] - ], - "last_value": 80.19, - "minimum_value": 10.15, - "maximum_value": 80.19, - "average_value": 36.24 - }, - { - "index_id": 152032, - "metric_id": 15177, - "metric": "connection_lower_thresholds", - "metric_legend": "connection_lower_thresholds", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 50, - "host_id": null, - "service_id": null, - "name": "Anomaly Lower Threshold", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": ".*_lower_thresholds", - "ds_color_line": "#D728C9", - "ds_color_line_mode": "0", - "ds_color_area": "#FFFFFF", - "ds_color_area_warn": "#F8C706", - "ds_color_area_crit": "#F91E05", - "ds_filled": null, - "ds_max": null, - "ds_min": null, - "ds_minmax_int": null, - "ds_average": null, - "ds_last": null, - "ds_total": null, - "ds_tickness": 2, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": "Lower Threshold", - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "Lower Threshold", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - -147.52236667, - -147.41236667, - -147.3422, - -147.43356667, - -147.56356667, - -140.79443333, - -105.2176, - -62.745566667, - -27.859833333, - -24.6255, - -28.9755, - -32.624433333, - -33.33, - -33.33, - -33.369833333, - -33.579166667, - -33.829166667, - -34.0712, - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.4927, - -34.2827, - -34.1444, - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.4927, - -34.2827, - -34.1444, - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.4927, - -34.2827, - -34.1444, - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.4927, - -34.2827, - -34.1444, - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.4927, - -34.2827, - -34.1444, - -34.2873, - -34.4973, - -34.667466667, - -34.7, - -34.7, - -34.7, - -34.7, - -34.7, - -34.668133333, - -34.484733333, - -34.264733333, - -34.116433333, - -34.2573, - -34.4673, - -34.637466667, - -34.67, - -34.67, - -34.67, - -34.67, - -34.67, - -34.5744, - -34.079966667, - -33.497933333, - -33.005566667, - -32.91, - -32.91, - -32.917966667, - -32.975766667, - -33.045766667, - -33.0839, - -32.9705, - -32.8205, - -32.7422, - -32.976966667, - -33.286966667, - -33.549166667, - -33.6, - -33.6, - -33.6, - -33.592033333, - -33.582033333, - -33.5322, - -33.344733333, - -33.116766667, - -32.966433333, - -33.123233333, - -33.3612, - -33.561366667, - -33.6, - -33.6, - -33.6, - -33.592033333, - -33.582033333, - -33.5322, - -33.344733333, - -33.116766667, - -32.966433333, - -33.1304, - -33.3704, - -33.5628, - -33.6, - -33.6, - -33.6, - -33.592066667, - -33.582066667, - -33.548266667, - -33.405133333, - -33.235133333, - -33.1286, - -33.268666667, - -33.468666667, - -33.636933333, - -33.67, - -33.67, - -33.67, - -33.662066667, - -33.652066667, - -33.6262, - -33.5724, - -33.504466667, - -33.458266667, - -33.481733333, - -33.529666667, - -33.5638, - -33.57, - -33.57, - -33.57, - -33.562066667, - -33.552066667, - -33.5262, - -33.4724, - -33.404466667, - -33.39, - -33.596266667, - -33.848333333, - -34.058666667, - -34.1, - -34.1, - -34.1, - -34.092066667, - -34.082066667, - -34.064133333, - -34.0362, - -34.0062, - -33.801666667, - -32.901133333, - -31.831133333, - -38.408866667, - -65.231533333, - -121.966, - -159.74953333, - -163.04806667, - -158.53613333, - -154.7044, - -153.90873333, - -153.79873333, - -153.49346667, - -152.32513333, - -150.95513333, - -149.76493333, - -149.36553333, - -149.13746667, - -148.95613333, - -148.94386667, - -148.9658, - -148.97453333, - -148.88873333, - -148.77873333, - -148.5914, - -148.06593333, - -147.474, - -146.9668, - -146.87, - -146.87, - -146.87386667, - -146.8958, - -146.9258, - -146.9326, - -146.83873333, - -146.72873333, - -146.66513333, - -146.8048, - -146.9848, - -147.13773333, - -147.17, - -147.17, - -147.17386667, - -147.1958, - -147.22386667, - -147.22453333, - -147.13873333, - -147.02873333, - -146.94966667, - -147.00546667, - -147.08546667, - -147.15386667, - -147.17, - -147.17, - -147.17386667, - -147.1958, - -147.22386667, - -147.22453333, - -147.13873333, - -147.02873333, - -146.94966667, - -147.00546667, - -147.08546667, - -147.15386667, - -147.17, - -147.17, - -147.17386667, - -147.1958, - -147.22386667, - -147.22453333, - -147.13873333, - -147.02873333, - -146.92453333, - -146.8484, - -146.78646667, - -146.72806667, - -146.72, - -146.72, - -146.72386667, - -146.7458, - -146.77386667, - -146.77453333, - -146.68873333, - -146.57873333, - -146.49966667, - -146.55546667, - -146.63546667, - -146.70386667, - -146.72, - -146.72, - -146.72386667, - -146.7458, - -146.77386667, - -146.77453333, - -146.68873333, - -146.57873333, - -146.49966667, - -146.55546667, - -146.63546667, - -146.70386667, - -146.72, - -146.72, - -146.72386667, - -146.7458, - -146.77386667, - null, - null - ], - "prints": [], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - }, - { - "index_id": 152032, - "metric_id": 15178, - "metric": "connection_upper_thresholds", - "metric_legend": "connection_upper_thresholds", - "unit": "", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 51, - "host_id": null, - "service_id": null, - "name": "Anomaly Upper Threshold", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": ".*_upper_thresholds", - "ds_color_line": "#D728C9", - "ds_color_line_mode": "0", - "ds_color_area": "#FFFFFF", - "ds_color_area_warn": "#F8C706", - "ds_color_area_crit": "#F91E05", - "ds_filled": null, - "ds_max": null, - "ds_min": null, - "ds_minmax_int": null, - "ds_average": null, - "ds_last": null, - "ds_total": null, - "ds_tickness": 2, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": "Upper Threshold", - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "Upper Threshold", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_order": 1, - "data": [ - 371.55763333, - 371.66763333, - 371.7378, - 371.64643333, - 371.5244, - 354.80983333, - 268.86776667, - 166.34573333, - 79.7272, - 59.4745, - 55.1245, - 51.475566667, - 50.77, - 50.77, - 50.730166667, - 50.520833333, - 50.270833333, - 50.020833333, - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.421866667, - 49.5973, - 49.8073, - 49.9456, - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.421866667, - 49.5973, - 49.8073, - 49.9456, - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.421866667, - 49.5973, - 49.8073, - 49.9456, - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.421866667, - 49.5973, - 49.8073, - 49.9456, - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.421866667, - 49.5973, - 49.8073, - 49.9456, - 49.810666667, - 49.6027, - 49.424566667, - 49.39, - 49.39, - 49.39, - 49.39, - 49.39, - 49.429833333, - 49.6073, - 49.825266667, - 49.981533333, - 49.8427, - 49.6327, - 49.454566667, - 49.42, - 49.42, - 49.42, - 49.42, - 49.42, - 49.5156, - 50.010033333, - 50.600033333, - 51.094433333, - 51.19, - 51.19, - 51.174066667, - 51.114233333, - 51.044233333, - 51.0061, - 51.127466667, - 51.2795, - 51.349833333, - 51.113033333, - 50.803033333, - 50.540833333, - 50.49, - 50.49, - 50.497966667, - 50.507966667, - 50.517966667, - 50.559833333, - 50.753233333, - 50.983233333, - 51.133566667, - 50.9688, - 50.7288, - 50.528633333, - 50.49, - 50.49, - 50.497966667, - 50.507966667, - 50.517966667, - 50.559833333, - 50.753233333, - 50.983233333, - 51.133566667, - 50.9696, - 50.7296, - 50.529266667, - 50.49, - 50.49, - 50.49, - 50.497933333, - 50.507933333, - 50.549666667, - 50.686933333, - 50.854866667, - 50.9614, - 50.821333333, - 50.621333333, - 50.453066667, - 50.42, - 50.42, - 50.427933333, - 50.437933333, - 50.447933333, - 50.465866667, - 50.525533333, - 50.5876, - 50.631733333, - 50.608266667, - 50.568266667, - 50.528266667, - 50.52, - 50.52, - 50.527933333, - 50.537933333, - 50.547933333, - 50.565866667, - 50.625533333, - 50.6876, - 50.7, - 50.501666667, - 50.243733333, - 50.031333333, - 49.99, - 49.99, - 49.99, - 49.997933333, - 50.007933333, - 50.025866667, - 50.0538, - 50.0838, - 50.288333333, - 51.188866667, - 52.2668, - 69.4594, - 128.4818, - 252.1254, - 336.7196, - 356.03386667, - 360.55193333, - 364.3756, - 365.17126667, - 365.28126667, - 365.58846667, - 366.76293333, - 368.12486667, - 369.317, - 369.72253333, - 369.94446667, - 370.13386667, - 370.1442, - 370.1142, - 370.1074, - 370.20126667, - 370.31126667, - 370.49666667, - 371.016, - 371.616, - 372.12126667, - 372.21, - 372.21, - 372.20613333, - 372.1842, - 372.15613333, - 372.15546667, - 372.24126667, - 372.35126667, - 372.4168, - 372.28326667, - 372.0952, - 371.9442, - 371.92, - 371.92, - 371.91613333, - 371.8942, - 371.8642, - 371.8574, - 371.95126667, - 372.06126667, - 372.14033333, - 372.08453333, - 372.0026, - 371.92806667, - 371.92, - 371.92, - 371.91613333, - 371.8942, - 371.8642, - 371.8574, - 371.95126667, - 372.06126667, - 372.14033333, - 372.08453333, - 372.0026, - 371.92806667, - 371.92, - 371.92, - 371.91613333, - 371.8942, - 371.8642, - 371.8574, - 371.95126667, - 372.06126667, - 372.16353333, - 372.23353333, - 372.3016, - 372.35386667, - 372.37, - 372.37, - 372.3642, - 372.33613333, - 372.3142, - 372.30546667, - 372.39126667, - 372.50126667, - 372.58226667, - 372.5326, - 372.44453333, - 372.37806667, - 372.37, - 372.37, - 372.3642, - 372.33613333, - 372.3142, - 372.30546667, - 372.39126667, - 372.50126667, - 372.58226667, - 372.5326, - 372.44453333, - 372.37806667, - 372.37, - 372.37, - 372.3642, - 372.33613333, - 372.3142, - null, - null - ], - "prints": [], - "last_value": null, - "minimum_value": null, - "maximum_value": null, - "average_value": null - } - ], - "times": [ - "2023-06-14T17:35:00+02:00", - "2023-06-14T17:40:00+02:00", - "2023-06-14T17:45:00+02:00", - "2023-06-14T17:50:00+02:00", - "2023-06-14T17:55:00+02:00", - "2023-06-14T18:00:00+02:00", - "2023-06-14T18:05:00+02:00", - "2023-06-14T18:10:00+02:00", - "2023-06-14T18:15:00+02:00", - "2023-06-14T18:20:00+02:00", - "2023-06-14T18:25:00+02:00", - "2023-06-14T18:30:00+02:00", - "2023-06-14T18:35:00+02:00", - "2023-06-14T18:40:00+02:00", - "2023-06-14T18:45:00+02:00", - "2023-06-14T18:50:00+02:00", - "2023-06-14T18:55:00+02:00", - "2023-06-14T19:00:00+02:00", - "2023-06-14T19:05:00+02:00", - "2023-06-14T19:10:00+02:00", - "2023-06-14T19:15:00+02:00", - "2023-06-14T19:20:00+02:00", - "2023-06-14T19:25:00+02:00", - "2023-06-14T19:30:00+02:00", - "2023-06-14T19:35:00+02:00", - "2023-06-14T19:40:00+02:00", - "2023-06-14T19:45:00+02:00", - "2023-06-14T19:50:00+02:00", - "2023-06-14T19:55:00+02:00", - "2023-06-14T20:00:00+02:00", - "2023-06-14T20:05:00+02:00", - "2023-06-14T20:10:00+02:00", - "2023-06-14T20:15:00+02:00", - "2023-06-14T20:20:00+02:00", - "2023-06-14T20:25:00+02:00", - "2023-06-14T20:30:00+02:00", - "2023-06-14T20:35:00+02:00", - "2023-06-14T20:40:00+02:00", - "2023-06-14T20:45:00+02:00", - "2023-06-14T20:50:00+02:00", - "2023-06-14T20:55:00+02:00", - "2023-06-14T21:00:00+02:00", - "2023-06-14T21:05:00+02:00", - "2023-06-14T21:10:00+02:00", - "2023-06-14T21:15:00+02:00", - "2023-06-14T21:20:00+02:00", - "2023-06-14T21:25:00+02:00", - "2023-06-14T21:30:00+02:00", - "2023-06-14T21:35:00+02:00", - "2023-06-14T21:40:00+02:00", - "2023-06-14T21:45:00+02:00", - "2023-06-14T21:50:00+02:00", - "2023-06-14T21:55:00+02:00", - "2023-06-14T22:00:00+02:00", - "2023-06-14T22:05:00+02:00", - "2023-06-14T22:10:00+02:00", - "2023-06-14T22:15:00+02:00", - "2023-06-14T22:20:00+02:00", - "2023-06-14T22:25:00+02:00", - "2023-06-14T22:30:00+02:00", - "2023-06-14T22:35:00+02:00", - "2023-06-14T22:40:00+02:00", - "2023-06-14T22:45:00+02:00", - "2023-06-14T22:50:00+02:00", - "2023-06-14T22:55:00+02:00", - "2023-06-14T23:00:00+02:00", - "2023-06-14T23:05:00+02:00", - "2023-06-14T23:10:00+02:00", - "2023-06-14T23:15:00+02:00", - "2023-06-14T23:20:00+02:00", - "2023-06-14T23:25:00+02:00", - "2023-06-14T23:30:00+02:00", - "2023-06-14T23:35:00+02:00", - "2023-06-14T23:40:00+02:00", - "2023-06-14T23:45:00+02:00", - "2023-06-14T23:50:00+02:00", - "2023-06-14T23:55:00+02:00", - "2023-06-15T00:00:00+02:00", - "2023-06-15T00:05:00+02:00", - "2023-06-15T00:10:00+02:00", - "2023-06-15T00:15:00+02:00", - "2023-06-15T00:20:00+02:00", - "2023-06-15T00:25:00+02:00", - "2023-06-15T00:30:00+02:00", - "2023-06-15T00:35:00+02:00", - "2023-06-15T00:40:00+02:00", - "2023-06-15T00:45:00+02:00", - "2023-06-15T00:50:00+02:00", - "2023-06-15T00:55:00+02:00", - "2023-06-15T01:00:00+02:00", - "2023-06-15T01:05:00+02:00", - "2023-06-15T01:10:00+02:00", - "2023-06-15T01:15:00+02:00", - "2023-06-15T01:20:00+02:00", - "2023-06-15T01:25:00+02:00", - "2023-06-15T01:30:00+02:00", - "2023-06-15T01:35:00+02:00", - "2023-06-15T01:40:00+02:00", - "2023-06-15T01:45:00+02:00", - "2023-06-15T01:50:00+02:00", - "2023-06-15T01:55:00+02:00", - "2023-06-15T02:00:00+02:00", - "2023-06-15T02:05:00+02:00", - "2023-06-15T02:10:00+02:00", - "2023-06-15T02:15:00+02:00", - "2023-06-15T02:20:00+02:00", - "2023-06-15T02:25:00+02:00", - "2023-06-15T02:30:00+02:00", - "2023-06-15T02:35:00+02:00", - "2023-06-15T02:40:00+02:00", - "2023-06-15T02:45:00+02:00", - "2023-06-15T02:50:00+02:00", - "2023-06-15T02:55:00+02:00", - "2023-06-15T03:00:00+02:00", - "2023-06-15T03:05:00+02:00", - "2023-06-15T03:10:00+02:00", - "2023-06-15T03:15:00+02:00", - "2023-06-15T03:20:00+02:00", - "2023-06-15T03:25:00+02:00", - "2023-06-15T03:30:00+02:00", - "2023-06-15T03:35:00+02:00", - "2023-06-15T03:40:00+02:00", - "2023-06-15T03:45:00+02:00", - "2023-06-15T03:50:00+02:00", - "2023-06-15T03:55:00+02:00", - "2023-06-15T04:00:00+02:00", - "2023-06-15T04:05:00+02:00", - "2023-06-15T04:10:00+02:00", - "2023-06-15T04:15:00+02:00", - "2023-06-15T04:20:00+02:00", - "2023-06-15T04:25:00+02:00", - "2023-06-15T04:30:00+02:00", - "2023-06-15T04:35:00+02:00", - "2023-06-15T04:40:00+02:00", - "2023-06-15T04:45:00+02:00", - "2023-06-15T04:50:00+02:00", - "2023-06-15T04:55:00+02:00", - "2023-06-15T05:00:00+02:00", - "2023-06-15T05:05:00+02:00", - "2023-06-15T05:10:00+02:00", - "2023-06-15T05:15:00+02:00", - "2023-06-15T05:20:00+02:00", - "2023-06-15T05:25:00+02:00", - "2023-06-15T05:30:00+02:00", - "2023-06-15T05:35:00+02:00", - "2023-06-15T05:40:00+02:00", - "2023-06-15T05:45:00+02:00", - "2023-06-15T05:50:00+02:00", - "2023-06-15T05:55:00+02:00", - "2023-06-15T06:00:00+02:00", - "2023-06-15T06:05:00+02:00", - "2023-06-15T06:10:00+02:00", - "2023-06-15T06:15:00+02:00", - "2023-06-15T06:20:00+02:00", - "2023-06-15T06:25:00+02:00", - "2023-06-15T06:30:00+02:00", - "2023-06-15T06:35:00+02:00", - "2023-06-15T06:40:00+02:00", - "2023-06-15T06:45:00+02:00", - "2023-06-15T06:50:00+02:00", - "2023-06-15T06:55:00+02:00", - "2023-06-15T07:00:00+02:00", - "2023-06-15T07:05:00+02:00", - "2023-06-15T07:10:00+02:00", - "2023-06-15T07:15:00+02:00", - "2023-06-15T07:20:00+02:00", - "2023-06-15T07:25:00+02:00", - "2023-06-15T07:30:00+02:00", - "2023-06-15T07:35:00+02:00", - "2023-06-15T07:40:00+02:00", - "2023-06-15T07:45:00+02:00", - "2023-06-15T07:50:00+02:00", - "2023-06-15T07:55:00+02:00", - "2023-06-15T08:00:00+02:00", - "2023-06-15T08:05:00+02:00", - "2023-06-15T08:10:00+02:00", - "2023-06-15T08:15:00+02:00", - "2023-06-15T08:20:00+02:00", - "2023-06-15T08:25:00+02:00", - "2023-06-15T08:30:00+02:00", - "2023-06-15T08:35:00+02:00", - "2023-06-15T08:40:00+02:00", - "2023-06-15T08:45:00+02:00", - "2023-06-15T08:50:00+02:00", - "2023-06-15T08:55:00+02:00", - "2023-06-15T09:00:00+02:00", - "2023-06-15T09:05:00+02:00", - "2023-06-15T09:10:00+02:00", - "2023-06-15T09:15:00+02:00", - "2023-06-15T09:20:00+02:00", - "2023-06-15T09:25:00+02:00", - "2023-06-15T09:30:00+02:00", - "2023-06-15T09:35:00+02:00", - "2023-06-15T09:40:00+02:00", - "2023-06-15T09:45:00+02:00", - "2023-06-15T09:50:00+02:00", - "2023-06-15T09:55:00+02:00", - "2023-06-15T10:00:00+02:00", - "2023-06-15T10:05:00+02:00", - "2023-06-15T10:10:00+02:00", - "2023-06-15T10:15:00+02:00", - "2023-06-15T10:20:00+02:00", - "2023-06-15T10:25:00+02:00", - "2023-06-15T10:30:00+02:00", - "2023-06-15T10:35:00+02:00", - "2023-06-15T10:40:00+02:00", - "2023-06-15T10:45:00+02:00", - "2023-06-15T10:50:00+02:00", - "2023-06-15T10:55:00+02:00", - "2023-06-15T11:00:00+02:00", - "2023-06-15T11:05:00+02:00", - "2023-06-15T11:10:00+02:00", - "2023-06-15T11:15:00+02:00", - "2023-06-15T11:20:00+02:00", - "2023-06-15T11:25:00+02:00", - "2023-06-15T11:30:00+02:00", - "2023-06-15T11:35:00+02:00", - "2023-06-15T11:40:00+02:00", - "2023-06-15T11:45:00+02:00", - "2023-06-15T11:50:00+02:00", - "2023-06-15T11:55:00+02:00", - "2023-06-15T12:00:00+02:00", - "2023-06-15T12:05:00+02:00", - "2023-06-15T12:10:00+02:00", - "2023-06-15T12:15:00+02:00", - "2023-06-15T12:20:00+02:00", - "2023-06-15T12:25:00+02:00", - "2023-06-15T12:30:00+02:00", - "2023-06-15T12:35:00+02:00", - "2023-06-15T12:40:00+02:00", - "2023-06-15T12:45:00+02:00", - "2023-06-15T12:50:00+02:00", - "2023-06-15T12:55:00+02:00", - "2023-06-15T13:00:00+02:00", - "2023-06-15T13:05:00+02:00", - "2023-06-15T13:10:00+02:00", - "2023-06-15T13:15:00+02:00", - "2023-06-15T13:20:00+02:00", - "2023-06-15T13:25:00+02:00", - "2023-06-15T13:30:00+02:00", - "2023-06-15T13:35:00+02:00", - "2023-06-15T13:40:00+02:00", - "2023-06-15T13:45:00+02:00", - "2023-06-15T13:50:00+02:00", - "2023-06-15T13:55:00+02:00", - "2023-06-15T14:00:00+02:00", - "2023-06-15T14:05:00+02:00", - "2023-06-15T14:10:00+02:00", - "2023-06-15T14:15:00+02:00", - "2023-06-15T14:20:00+02:00", - "2023-06-15T14:25:00+02:00", - "2023-06-15T14:30:00+02:00", - "2023-06-15T14:35:00+02:00", - "2023-06-15T14:40:00+02:00", - "2023-06-15T14:45:00+02:00", - "2023-06-15T14:50:00+02:00", - "2023-06-15T14:55:00+02:00", - "2023-06-15T15:00:00+02:00", - "2023-06-15T15:05:00+02:00", - "2023-06-15T15:10:00+02:00", - "2023-06-15T15:15:00+02:00", - "2023-06-15T15:20:00+02:00", - "2023-06-15T15:25:00+02:00", - "2023-06-15T15:30:00+02:00", - "2023-06-15T15:35:00+02:00", - "2023-06-15T15:40:00+02:00", - "2023-06-15T15:45:00+02:00", - "2023-06-15T15:50:00+02:00", - "2023-06-15T15:55:00+02:00", - "2023-06-15T16:00:00+02:00", - "2023-06-15T16:05:00+02:00", - "2023-06-15T16:10:00+02:00", - "2023-06-15T16:15:00+02:00", - "2023-06-15T16:20:00+02:00", - "2023-06-15T16:25:00+02:00", - "2023-06-15T16:30:00+02:00", - "2023-06-15T16:35:00+02:00", - "2023-06-15T16:40:00+02:00", - "2023-06-15T16:45:00+02:00", - "2023-06-15T16:50:00+02:00", - "2023-06-15T16:55:00+02:00", - "2023-06-15T17:00:00+02:00", - "2023-06-15T17:05:00+02:00", - "2023-06-15T17:10:00+02:00", - "2023-06-15T17:15:00+02:00", - "2023-06-15T17:20:00+02:00", - "2023-06-15T17:25:00+02:00", - "2023-06-15T17:30:00+02:00", - "2023-06-15T17:35:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastMonth.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/lastMonth.json deleted file mode 100644 index b41d32b83c..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastMonth.json +++ /dev/null @@ -1,1674 +0,0 @@ -{ - "global": { - "title": "oracle-shared-spool-ratio graph on srv-oracle-crm", - "start": "2023-04-22T16:01:06+02:00", - "end": "2023-05-23T16:01:06+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 0, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 5320, - "metric_id": 12879, - "metric": "connTime", - "metric_legend": "connTime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#990033" - }, - "legend": "connTime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 0.50033458333, - 0.61945916667, - 0.51819333333, - 0.60382916667, - 0.49840361111, - 0.49933972222, - 0.55467208333, - 0.56382444444, - 0.62704972222, - 0.54424180556, - 0.50082777778, - 0.45984555556, - 0.49584861111, - 0.35677083333, - 0.47271861111, - 0.52795972222, - 0.45791944444, - 0.43084166667, - 0.502125, - 0.38325833333, - 0.594375, - 0.594125, - 0.45928333333, - 0.5255, - 0.41265, - 0.40810833333, - 0.5416, - 0.48815, - 0.42519166667, - 0.58961666667, - 0.41775833333, - 0.43450833333, - 0.4493, - 0.39341666667, - 0.49969166667, - 0.50023333333, - 0.46121305556, - 0.5069475, - 0.50755055556, - 0.44471013889, - 0.47222291667, - 0.45869027778, - 0.41597888889, - 0.59415055556, - 0.52623305556, - 0.54249277778, - 0.58356333333, - 0.46177041667, - 0.49658555556, - 0.60377222222, - 0.56200958333, - 0.63443444444, - 0.52070555556, - 0.6246475, - 0.52999069444, - 0.42607777778, - 0.55257444444, - 0.45891888889, - 0.51791611111, - 0.423755, - 0.45616666667, - 0.54159055556, - 0.46024222222, - 0.41285333333, - 0.48092277778, - 0.46342777778, - 0.57123, - 0.56956111111, - 0.58442833333, - 0.52641388889, - 0.46058166667, - 0.40469458333, - 0.54256736111, - 0.56656111111, - 0.54332777778, - 0.49598680556, - 0.59200763889, - 0.44712708333, - 0.55852083333, - 0.58329166667, - 0.53323611111, - 0.57300416667, - 0.52716597222, - 0.40442291667, - 0.42211111111, - 0.63572708333, - 0.55759166667, - 0.46749166667, - 0.37702361111, - 0.56483055556, - 0.47474236111, - 0.43567847222, - 0.50577638889, - 0.44973305556, - 0.52211083333, - 0.44430083333, - 0.48803333333, - 0.42062833333, - 0.5597925, - 0.50754166667, - 0.4506775, - 0.38088333333, - 0.53365583333, - 0.43125333333, - 0.44724166667, - 0.44108833333, - 0.49138916667, - 0.610585, - 0.578545, - 0.49276666667, - 0.51599833333, - 0.55685166667, - 0.50467416667, - 0.51643916667, - 0.50236833333, - 0.60251916667, - 0.38275916667, - 0.4105925, - 0.48575833333, - 0.43170166667, - 0.63278916667, - 0.416565, - 0.46697902778, - 0.4740475, - 0.44771, - 0.59884472222, - 0.4627625, - 0.4531975, - 0.60965916667, - 0.63874180556, - 0.51233305556, - 0.55861527778, - 0.50454416667, - 0.43259527778, - 0.51321444444, - 0.48314888889, - 0.59840555556, - 0.55625777778, - 0.46488611111, - 0.45740694444, - 0.51038611111, - 0.61267083333, - 0.51206944444, - 0.56741666667, - 0.58174305556, - 0.38422222222, - 0.55132083333, - 0.54504722222, - 0.48465, - 0.47887083333, - 0.46282638889, - 0.48750277778, - 0.53763055556, - 0.53980833333, - 0.42661527778, - 0.4728375, - 0.46515694444, - 0.50543333333, - 0.58466666667, - 0.4641875, - 0.42224305556, - 0.45730555556, - 0.53627777778, - 0.49995833333, - 0.53940972222, - 0.41956944444, - 0.45699305556, - 0.52835416667, - 0.50822222222, - 0.44841666667, - 0.43936111111, - 0.54340277778, - 0.46944444444, - 0.57169444444, - 0.52923611111, - 0.56581944444, - 0.56853472222, - 0.59384027778, - 0.46910555556, - 0.43805694444, - 0.58207083333, - 0.55213888889, - 0.44952777778, - 0.47930555556, - 0.44179861111, - 0.41134027778, - 0.42866666667, - 0.511375, - 0.50978472222, - 0.477875, - 0.53188194444, - 0.44010416667, - 0.48233333333, - 0.55613347222, - 0.47067416667, - 0.54952611111, - 0.52073277778, - 0.50571736111, - 0.61287555556, - 0.48102388889, - 0.49271569444, - 0.44343125, - 0.53625333333, - 0.563685, - 0.466765, - 0.49876166667, - 0.47815333333, - 0.49052666667, - 0.40544, - 0.558505, - 0.504925, - 0.56809666667, - 0.51643166667, - 0.500375, - 0.46229833333, - 0.41243, - 0.39154166667, - 0.46627166667, - 0.55276111111, - 0.39044694444, - 0.56729583333, - 0.56158388889, - 0.41965333333, - 0.52013361111, - 0.39681166667, - 0.50957805556, - 0.51941666667, - 0.55553763889, - 0.46638333333, - 0.44483722222, - 0.57280722222, - 0.68180791667, - 0.48812944444, - 0.59093375, - 0.54439763889, - 0.48189972222, - 0.49061152778, - 0.59989930556, - 0.58490055556, - 0.61258930556, - 0.60397902778, - 0.52981402778, - 0.50435, - 0.41884722222, - 0.45518055556, - 0.46851111111, - 0.61096944444, - 0.49326944444, - 0.419725, - 0.46484722222, - 0.48892222222, - 0.42955, - 0.53626388889, - 0.56575833333, - 0.50948888889, - 0.46735555556, - 0.51255555556, - 0.50625555556, - 0.49493333333, - 0.45309444444, - 0.44096111111, - 0.52035277778, - 0.41961388889, - 0.4463, - 0.48494444444, - 0.55550277778, - 0.51151111111, - 0.53519444444, - 0.39882902778, - 0.47607, - 0.47141388889, - 0.54625083333, - 0.49487166667, - 0.56357083333, - 0.54315833333, - 0.55606277778, - 0.46999027778, - 0.60634083333, - 0.45837861111, - 0.46508805556, - 0.46517861111, - 0.50517722222, - 0.49639833333, - 0.45971111111, - 0.53749027778, - 0.42077611111, - 0.36337027778, - 0.57174166667, - 0.51783333333, - 0.46205166667, - 0.54008333333, - 0.46243833333, - 0.49854333333, - 0.52208666667, - 0.45309833333, - 0.54164166667, - 0.50293666667, - 0.58052444444, - 0.48480416667, - 0.44963611111, - 0.57046319444, - 0.49653611111, - 0.55977222222, - 0.46650694444, - 0.57683680556, - 0.37171111111, - 0.46325, - 0.48231680556, - 0.48979055556, - 0.51859361111, - 0.50016222222, - 0.45968583333, - 0.51421583333, - 0.56765638889, - 0.57335111111, - 0.41111875, - 0.50796958333, - 0.395305, - 0.48056722222, - 0.49464361111, - 0.46999875, - 0.44863527778, - 0.44513208333, - 0.52571097222, - 0.59808069444, - 0.51411833333, - 0.61205444444, - 0.52014583333, - 0.44387916667, - 0.47595416667, - 0.4776, - 0.54218333333, - 0.42116666667, - 0.41662916667, - 0.47499583333, - 0.55535416667, - 0.44424583333, - 0.4812375, - 0.54995, - 0.4826875, - 0.46228333333, - 0.42069166667, - 0.50894583333, - 0.52455305556, - 0.43574513889, - 0.47146680556, - 0.52494444444, - 0.61506833333, - 0.34888958333, - 0.53983305556, - 0.51920916667, - 0.46683319444, - 0.58013, - 0.39148333333, - 0.52852666667, - 0.49618611111, - 0.42079, - 0.44302666667, - 0.61560833333, - 0.40733777778, - 0.55178333333, - 0.5079175, - 0.47183541667, - 0.517075, - 0.38027541667, - 0.51537569444, - 0.40031805556, - 0.51048138889, - 0.59283166667, - 0.49227166667, - 0.48328611111, - 0.52946541667, - null - ], - "prints": [ - [ - "Last:0.53" - ], - [ - "Min:0.35" - ], - [ - "Max:0.68" - ], - [ - "Average:0.50" - ] - ], - "last_value": 0.53, - "minimum_value": 0.35, - "maximum_value": 0.68, - "average_value": 0.5 - }, - { - "index_id": 5320, - "metric_id": 12878, - "metric": "querytime", - "metric_legend": "querytime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#ff3333" - }, - "legend": "querytime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 0.4820075, - 0.54786666667, - 0.537675, - 0.44466583333, - 0.56231069444, - 0.51092194444, - 0.50375861111, - 0.51052875, - 0.50798208333, - 0.44864861111, - 0.4147725, - 0.50207305556, - 0.49094888889, - 0.50487722222, - 0.51480555556, - 0.60383333333, - 0.57061194444, - 0.56269166667, - 0.50226666667, - 0.36955, - 0.48694166667, - 0.5011, - 0.50590833333, - 0.39789166667, - 0.43364166667, - 0.46898333333, - 0.5747, - 0.43391666667, - 0.58044166667, - 0.55174166667, - 0.462675, - 0.52405833333, - 0.46514166667, - 0.57273333333, - 0.52735833333, - 0.5592, - 0.51948305556, - 0.50549694444, - 0.50488861111, - 0.36735625, - 0.53613972222, - 0.50677708333, - 0.44981055556, - 0.43704833333, - 0.45431930556, - 0.56507055556, - 0.41380861111, - 0.55419958333, - 0.45757708333, - 0.45671305556, - 0.4972675, - 0.38788166667, - 0.53776583333, - 0.52779277778, - 0.53221736111, - 0.47106277778, - 0.56903944444, - 0.4783, - 0.48126111111, - 0.54720222222, - 0.474135, - 0.45746888889, - 0.51297277778, - 0.606045, - 0.41071444444, - 0.41101222222, - 0.552105, - 0.45999388889, - 0.51995777778, - 0.56436611111, - 0.50154, - 0.47195055556, - 0.43405972222, - 0.5065, - 0.51008125, - 0.52819375, - 0.48212777778, - 0.49300902778, - 0.57922916667, - 0.46563888889, - 0.4014375, - 0.49352152778, - 0.46820347222, - 0.3917, - 0.50307152778, - 0.43910972222, - 0.57312708333, - 0.56125138889, - 0.50412708333, - 0.53868194444, - 0.51587361111, - 0.60080208333, - 0.47862986111, - 0.48106152778, - 0.38717166667, - 0.526345, - 0.40869833333, - 0.4253675, - 0.5569475, - 0.46934416667, - 0.50617083333, - 0.44834, - 0.51131333333, - 0.55684916667, - 0.51484166667, - 0.56658, - 0.41325583333, - 0.54179416667, - 0.57034416667, - 0.47756916667, - 0.62718666667, - 0.5509725, - 0.5502525, - 0.47039333333, - 0.42288916667, - 0.53411083333, - 0.5683725, - 0.602335, - 0.47520916667, - 0.50628583333, - 0.521265, - 0.52259861111, - 0.48722541667, - 0.53608763889, - 0.59789305556, - 0.44855902778, - 0.53649930556, - 0.54616166667, - 0.58590708333, - 0.45782208333, - 0.4642825, - 0.49553166667, - 0.67386, - 0.50180402778, - 0.47037763889, - 0.46473833333, - 0.41795972222, - 0.47257958333, - 0.53391527778, - 0.57262361111, - 0.48405138889, - 0.4508, - 0.54903055556, - 0.42190694444, - 0.43467777778, - 0.53279027778, - 0.58740972222, - 0.56928333333, - 0.63375833333, - 0.5663125, - 0.46767638889, - 0.57531388889, - 0.45455277778, - 0.39892222222, - 0.5952875, - 0.44328333333, - 0.49716944444, - 0.49061111111, - 0.55089583333, - 0.542875, - 0.44646527778, - 0.47390277778, - 0.495, - 0.55122222222, - 0.54713888889, - 0.47925694444, - 0.645625, - 0.58602083333, - 0.54818055556, - 0.58030555556, - 0.5108125, - 0.48620138889, - 0.44344444444, - 0.62082638889, - 0.53688888889, - 0.4769375, - 0.45626388889, - 0.43636111111, - 0.48725416667, - 0.56865277778, - 0.47129722222, - 0.50325, - 0.48446527778, - 0.55102083333, - 0.58122916667, - 0.45869444444, - 0.55117361111, - 0.38622916667, - 0.49203472222, - 0.39611111111, - 0.52322222222, - 0.50911111111, - 0.545875, - 0.49933166667, - 0.51926611111, - 0.49907486111, - 0.50863486111, - 0.53831486111, - 0.53933319444, - 0.57828930556, - 0.47896819444, - 0.40125291667, - 0.504445, - 0.53565, - 0.28999666667, - 0.48051666667, - 0.44803833333, - 0.42531, - 0.54171166667, - 0.484515, - 0.46153833333, - 0.47544666667, - 0.43798, - 0.401075, - 0.407455, - 0.41547666667, - 0.54620333333, - 0.45932666667, - 0.45051930556, - 0.57091819444, - 0.46523319444, - 0.43658833333, - 0.48776138889, - 0.53602388889, - 0.51612527778, - 0.51619833333, - 0.49428416667, - 0.43790222222, - 0.44653958333, - 0.43712486111, - 0.40300513889, - 0.56234097222, - 0.474555, - 0.44655097222, - 0.54056597222, - 0.45041430556, - 0.52533972222, - 0.52445375, - 0.63305347222, - 0.48278055556, - 0.52841361111, - 0.53922430556, - 0.56528333333, - 0.44198055556, - 0.49815555556, - 0.44740277778, - 0.53225, - 0.47143611111, - 0.50535, - 0.50532222222, - 0.38877222222, - 0.45349166667, - 0.4699, - 0.527325, - 0.48013055556, - 0.45149444444, - 0.51115555556, - 0.47300555556, - 0.40672222222, - 0.54794722222, - 0.57065555556, - 0.43134444444, - 0.54095555556, - 0.46501388889, - 0.53646111111, - 0.52628611111, - 0.55696944444, - 0.33851666667, - 0.56513861111, - 0.39431041667, - 0.48249513889, - 0.53899666667, - 0.54166638889, - 0.50782888889, - 0.52590805556, - 0.45245333333, - 0.45541916667, - 0.47155583333, - 0.51281972222, - 0.44810166667, - 0.50835138889, - 0.58544388889, - 0.52371805556, - 0.44599805556, - 0.43898777778, - 0.47267722222, - 0.52452208333, - 0.61510333333, - 0.50854166667, - 0.46054833333, - 0.56622, - 0.42615, - 0.53491666667, - 0.52652833333, - 0.527335, - 0.67556333333, - 0.45109166667, - 0.59083541667, - 0.45191319444, - 0.54146805556, - 0.48338333333, - 0.53249097222, - 0.44949444444, - 0.51941736111, - 0.58977708333, - 0.50848402778, - 0.40556944444, - 0.42585305556, - 0.5207375, - 0.4586325, - 0.40217944444, - 0.56245944444, - 0.55036388889, - 0.472395, - 0.40083444444, - 0.46645652778, - 0.47231375, - 0.61049125, - 0.43026055556, - 0.49318791667, - 0.49176569444, - 0.50923013889, - 0.65010805556, - 0.60687861111, - 0.48488833333, - 0.54808833333, - 0.57673444444, - 0.52415, - 0.3968375, - 0.4255625, - 0.49525, - 0.635625, - 0.54183333333, - 0.47456666667, - 0.35498333333, - 0.53386666667, - 0.51248333333, - 0.557225, - 0.51565833333, - 0.46278333333, - 0.5115125, - 0.53826666667, - 0.54737347222, - 0.50048930556, - 0.55215569444, - 0.52576833333, - 0.45016569444, - 0.36885777778, - 0.45052347222, - 0.45691166667, - 0.47295736111, - 0.48539277778, - 0.53254333333, - 0.62901055556, - 0.524615, - 0.49281166667, - 0.48531888889, - 0.52359944444, - 0.52044388889, - 0.482585, - 0.45909666667, - 0.56092263889, - 0.51403375, - 0.56277125, - 0.53915708333, - 0.49189180556, - 0.54154763889, - 0.50087736111, - 0.44601666667, - 0.48657333333, - 0.52078888889, - 0.47333972222, - null - ], - "prints": [ - [ - "Last:0.47" - ], - [ - "Min:0.29" - ], - [ - "Max:0.68" - ], - [ - "Average:0.50" - ] - ], - "last_value": 0.47, - "minimum_value": 0.29, - "maximum_value": 0.68, - "average_value": 0.5 - }, - { - "index_id": 5320, - "metric_id": 12877, - "metric": "used", - "metric_legend": "used", - "unit": "%", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 8, - "host_id": null, - "service_id": null, - "name": "Used", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": "used", - "ds_color_line": "#2B28D7", - "ds_color_line_mode": "0", - "ds_color_area": "#050AF9", - "ds_color_area_warn": null, - "ds_color_area_crit": null, - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "used", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 1, - "data": [ - 93.53473625, - 95.4705575, - 90.78131625, - 88.229732917, - 91.46288, - 96.404586389, - 90.425950694, - 92.482070417, - 95.38929375, - 98.065868472, - 91.3271225, - 92.991402361, - 96.059254028, - 95.253403889, - 92.0200325, - 86.169484583, - 91.723414306, - 95.545441667, - 91.213633333, - 96.978266667, - 92.047108333, - 94.362, - 97.349091667, - 91.6958, - 90.930558333, - 92.126758333, - 92.515791667, - 90.98285, - 94.291941667, - 94.6313, - 93.0995, - 96.032566667, - 97.73195, - 97.437383333, - 97.234416667, - 97.020591667, - 92.502736528, - 92.181365972, - 91.755329306, - 89.611361389, - 81.009381389, - 82.697088333, - 82.949993889, - 92.676847917, - 92.367398889, - 90.054948889, - 88.724102778, - 95.362512083, - 98.273312639, - 94.797704722, - 91.9214025, - 93.706965556, - 95.219553889, - 98.321218333, - 97.808040972, - 97.677885, - 96.704646111, - 93.720406667, - 92.002689444, - 89.145115, - 96.180838889, - 98.572950556, - 91.615067778, - 92.582652222, - 96.859334444, - 90.42448, - 91.813913889, - 92.037367778, - 91.581648889, - 79.763948889, - 73.738103333, - 72.813350972, - 74.061651389, - 78.564606944, - 73.625989583, - 74.61276875, - 75.664770833, - 84.789911111, - 91.562385417, - 92.0473125, - 90.717729167, - 84.731822917, - 84.325086111, - 84.78401875, - 86.0260625, - 87.469259028, - 88.298977778, - 86.075078472, - 86.349101389, - 88.635159028, - 89.006238889, - 91.320934722, - 88.318921528, - 77.251426528, - 73.456744167, - 81.2534625, - 84.409346667, - 85.268703333, - 86.337475833, - 83.730001667, - 79.989916667, - 86.847673333, - 93.467304167, - 95.524714167, - 94.551674167, - 87.080203333, - 80.839834167, - 79.757945, - 81.624870833, - 88.540388333, - 96.682811667, - 96.2668275, - 95.1485025, - 90.362938333, - 88.677029167, - 89.1434075, - 88.386136667, - 94.904750833, - 97.1479475, - 90.782644167, - 88.3413525, - 89.247638056, - 92.222419444, - 82.727468889, - 81.888297083, - 85.957462222, - 89.885201806, - 97.087708472, - 93.182506389, - 84.728676111, - 83.442598056, - 81.057695972, - 73.105455972, - 77.261483333, - 86.681160278, - 90.515781111, - 83.858407917, - 84.912508194, - 89.196070833, - 89.980515278, - 88.662130556, - 90.962719444, - 90.9171, - 97.05835, - 97.970702778, - 94.598463889, - 97.041998611, - 97.571281944, - 90.000070833, - 84.775991667, - 77.098211111, - 73.768095833, - 87.708554167, - 95.292305556, - 92.661397222, - 91.698375, - 94.734926389, - 85.569593056, - 78.765402778, - 73.1415625, - 75.643798611, - 79.100340278, - 80.757395833, - 75.441020833, - 74.254395833, - 75.555159722, - 73.148548611, - 74.245520833, - 80.435673611, - 78.429381944, - 73.619902778, - 73.574881944, - 74.838986111, - 76.178506944, - 73.361840278, - 73.252270833, - 74.580708333, - 77.323736111, - 89.248868056, - 95.394506944, - 83.555773611, - 73.377284722, - 72.989409722, - 72.345833333, - 77.278854167, - 77.246506944, - 75.3070625, - 74.816506944, - 73.262715278, - 78.040527778, - 75.361666667, - 79.701270833, - 80.888388889, - 77.274089722, - 78.965599028, - 76.581835833, - 81.1598125, - 82.532069722, - 81.2063575, - 79.699761389, - 84.279743333, - 82.0001075, - 77.98224, - 80.77859, - 77.558431667, - 75.035186667, - 79.77859, - 76.498343333, - 75.270236667, - 74.502018333, - 76.987243333, - 77.314198333, - 73.739925, - 76.768341667, - 80.002403333, - 79.50922, - 79.793135, - 83.32031, - 90.690696528, - 91.855036111, - 95.152990556, - 90.662471667, - 87.878877778, - 86.474365833, - 93.031389722, - 91.1510425, - 89.524025, - 87.79133125, - 83.196835417, - 86.905329028, - 84.796714861, - 86.477819306, - 90.215054722, - 90.689078611, - 90.069447917, - 94.064490972, - 92.910771806, - 90.168341389, - 86.005012778, - 82.007541389, - 82.4444, - 84.725972361, - 81.079969444, - 82.071788889, - 74.344436111, - 73.304477778, - 73.895147222, - 76.732205556, - 81.682944444, - 86.026041667, - 87.382563889, - 88.904291667, - 87.770433333, - 80.927844444, - 77.038666667, - 81.157086111, - 82.575377778, - 91.568616667, - 96.412636111, - 96.376172222, - 91.875827778, - 95.524025, - 97.76045, - 96.818305556, - 92.319038889, - 89.773883333, - 80.555247222, - 85.832455556, - 77.946490833, - 82.205994583, - 88.74038125, - 83.006198333, - 78.297281111, - 74.590896667, - 75.900935833, - 74.595134722, - 78.369969722, - 81.004014167, - 85.035468056, - 81.22037, - 84.639056944, - 84.586663333, - 78.015843889, - 80.189820833, - 76.739529722, - 78.387696111, - 78.584917361, - 84.938538333, - 90.97361, - 90.789226667, - 90.425228333, - 91.381495, - 96.852533333, - 91.220391667, - 97.581593333, - 97.245176667, - 95.096153333, - 95.391049444, - 93.119884028, - 81.892788889, - 77.476779861, - 80.188209028, - 80.098774306, - 86.978205556, - 94.64235625, - 97.311053472, - 97.048621528, - 90.545117639, - 88.905369444, - 93.880626944, - 93.685805556, - 96.881301944, - 96.753013056, - 97.337800278, - 95.696868611, - 97.011245139, - 96.984615833, - 87.825530556, - 90.718932639, - 92.912039028, - 86.380014028, - 84.796867639, - 92.66191625, - 91.698228056, - 90.882975, - 96.128683194, - 98.014940139, - 96.4936875, - 93.528679167, - 97.463633333, - 95.379266667, - 90.4649625, - 89.087520833, - 86.6875375, - 77.421904167, - 74.396995833, - 73.215158333, - 76.235308333, - 76.3625, - 80.6953625, - 82.4897875, - 86.9769875, - 92.331467222, - 94.825957917, - 89.40248875, - 89.796999167, - 91.073693194, - 92.296046667, - 97.467716528, - 90.982410139, - 92.016604583, - 91.068401389, - 86.059646667, - 81.936524444, - 81.474296111, - 75.121141667, - 76.126827778, - 78.021423333, - 79.388627778, - 72.908920556, - 76.873109444, - 88.14395875, - 92.47338, - 90.283409167, - 87.865566667, - 84.918092222, - 78.515823889, - 73.144546111, - 77.194361667, - 74.75668, - 83.207912778, - 81.414109306, - null - ], - "prints": [ - [ - "Last:81.41" - ], - [ - "Average:86.52" - ] - ], - "last_value": 81.41, - "minimum_value": null, - "maximum_value": null, - "average_value": 86.52 - } - ], - "times": [ - "2023-04-22T18:00:00+02:00", - "2023-04-22T20:00:00+02:00", - "2023-04-22T22:00:00+02:00", - "2023-04-23T00:00:00+02:00", - "2023-04-23T02:00:00+02:00", - "2023-04-23T04:00:00+02:00", - "2023-04-23T06:00:00+02:00", - "2023-04-23T08:00:00+02:00", - "2023-04-23T10:00:00+02:00", - "2023-04-23T12:00:00+02:00", - "2023-04-23T14:00:00+02:00", - "2023-04-23T16:00:00+02:00", - "2023-04-23T18:00:00+02:00", - "2023-04-23T20:00:00+02:00", - "2023-04-23T22:00:00+02:00", - "2023-04-24T00:00:00+02:00", - "2023-04-24T02:00:00+02:00", - "2023-04-24T04:00:00+02:00", - "2023-04-24T06:00:00+02:00", - "2023-04-24T08:00:00+02:00", - "2023-04-24T10:00:00+02:00", - "2023-04-24T12:00:00+02:00", - "2023-04-24T14:00:00+02:00", - "2023-04-24T16:00:00+02:00", - "2023-04-24T18:00:00+02:00", - "2023-04-24T20:00:00+02:00", - "2023-04-24T22:00:00+02:00", - "2023-04-25T00:00:00+02:00", - "2023-04-25T02:00:00+02:00", - "2023-04-25T04:00:00+02:00", - "2023-04-25T06:00:00+02:00", - "2023-04-25T08:00:00+02:00", - "2023-04-25T10:00:00+02:00", - "2023-04-25T12:00:00+02:00", - "2023-04-25T14:00:00+02:00", - "2023-04-25T16:00:00+02:00", - "2023-04-25T18:00:00+02:00", - "2023-04-25T20:00:00+02:00", - "2023-04-25T22:00:00+02:00", - "2023-04-26T00:00:00+02:00", - "2023-04-26T02:00:00+02:00", - "2023-04-26T04:00:00+02:00", - "2023-04-26T06:00:00+02:00", - "2023-04-26T08:00:00+02:00", - "2023-04-26T10:00:00+02:00", - "2023-04-26T12:00:00+02:00", - "2023-04-26T14:00:00+02:00", - "2023-04-26T16:00:00+02:00", - "2023-04-26T18:00:00+02:00", - "2023-04-26T20:00:00+02:00", - "2023-04-26T22:00:00+02:00", - "2023-04-27T00:00:00+02:00", - "2023-04-27T02:00:00+02:00", - "2023-04-27T04:00:00+02:00", - "2023-04-27T06:00:00+02:00", - "2023-04-27T08:00:00+02:00", - "2023-04-27T10:00:00+02:00", - "2023-04-27T12:00:00+02:00", - "2023-04-27T14:00:00+02:00", - "2023-04-27T16:00:00+02:00", - "2023-04-27T18:00:00+02:00", - "2023-04-27T20:00:00+02:00", - "2023-04-27T22:00:00+02:00", - "2023-04-28T00:00:00+02:00", - "2023-04-28T02:00:00+02:00", - "2023-04-28T04:00:00+02:00", - "2023-04-28T06:00:00+02:00", - "2023-04-28T08:00:00+02:00", - "2023-04-28T10:00:00+02:00", - "2023-04-28T12:00:00+02:00", - "2023-04-28T14:00:00+02:00", - "2023-04-28T16:00:00+02:00", - "2023-04-28T18:00:00+02:00", - "2023-04-28T20:00:00+02:00", - "2023-04-28T22:00:00+02:00", - "2023-04-29T00:00:00+02:00", - "2023-04-29T02:00:00+02:00", - "2023-04-29T04:00:00+02:00", - "2023-04-29T06:00:00+02:00", - "2023-04-29T08:00:00+02:00", - "2023-04-29T10:00:00+02:00", - "2023-04-29T12:00:00+02:00", - "2023-04-29T14:00:00+02:00", - "2023-04-29T16:00:00+02:00", - "2023-04-29T18:00:00+02:00", - "2023-04-29T20:00:00+02:00", - "2023-04-29T22:00:00+02:00", - "2023-04-30T00:00:00+02:00", - "2023-04-30T02:00:00+02:00", - "2023-04-30T04:00:00+02:00", - "2023-04-30T06:00:00+02:00", - "2023-04-30T08:00:00+02:00", - "2023-04-30T10:00:00+02:00", - "2023-04-30T12:00:00+02:00", - "2023-04-30T14:00:00+02:00", - "2023-04-30T16:00:00+02:00", - "2023-04-30T18:00:00+02:00", - "2023-04-30T20:00:00+02:00", - "2023-04-30T22:00:00+02:00", - "2023-05-01T00:00:00+02:00", - "2023-05-01T02:00:00+02:00", - "2023-05-01T04:00:00+02:00", - "2023-05-01T06:00:00+02:00", - "2023-05-01T08:00:00+02:00", - "2023-05-01T10:00:00+02:00", - "2023-05-01T12:00:00+02:00", - "2023-05-01T14:00:00+02:00", - "2023-05-01T16:00:00+02:00", - "2023-05-01T18:00:00+02:00", - "2023-05-01T20:00:00+02:00", - "2023-05-01T22:00:00+02:00", - "2023-05-02T00:00:00+02:00", - "2023-05-02T02:00:00+02:00", - "2023-05-02T04:00:00+02:00", - "2023-05-02T06:00:00+02:00", - "2023-05-02T08:00:00+02:00", - "2023-05-02T10:00:00+02:00", - "2023-05-02T12:00:00+02:00", - "2023-05-02T14:00:00+02:00", - "2023-05-02T16:00:00+02:00", - "2023-05-02T18:00:00+02:00", - "2023-05-02T20:00:00+02:00", - "2023-05-02T22:00:00+02:00", - "2023-05-03T00:00:00+02:00", - "2023-05-03T02:00:00+02:00", - "2023-05-03T04:00:00+02:00", - "2023-05-03T06:00:00+02:00", - "2023-05-03T08:00:00+02:00", - "2023-05-03T10:00:00+02:00", - "2023-05-03T12:00:00+02:00", - "2023-05-03T14:00:00+02:00", - "2023-05-03T16:00:00+02:00", - "2023-05-03T18:00:00+02:00", - "2023-05-03T20:00:00+02:00", - "2023-05-03T22:00:00+02:00", - "2023-05-04T00:00:00+02:00", - "2023-05-04T02:00:00+02:00", - "2023-05-04T04:00:00+02:00", - "2023-05-04T06:00:00+02:00", - "2023-05-04T08:00:00+02:00", - "2023-05-04T10:00:00+02:00", - "2023-05-04T12:00:00+02:00", - "2023-05-04T14:00:00+02:00", - "2023-05-04T16:00:00+02:00", - "2023-05-04T18:00:00+02:00", - "2023-05-04T20:00:00+02:00", - "2023-05-04T22:00:00+02:00", - "2023-05-05T00:00:00+02:00", - "2023-05-05T02:00:00+02:00", - "2023-05-05T04:00:00+02:00", - "2023-05-05T06:00:00+02:00", - "2023-05-05T08:00:00+02:00", - "2023-05-05T10:00:00+02:00", - "2023-05-05T12:00:00+02:00", - "2023-05-05T14:00:00+02:00", - "2023-05-05T16:00:00+02:00", - "2023-05-05T18:00:00+02:00", - "2023-05-05T20:00:00+02:00", - "2023-05-05T22:00:00+02:00", - "2023-05-06T00:00:00+02:00", - "2023-05-06T02:00:00+02:00", - "2023-05-06T04:00:00+02:00", - "2023-05-06T06:00:00+02:00", - "2023-05-06T08:00:00+02:00", - "2023-05-06T10:00:00+02:00", - "2023-05-06T12:00:00+02:00", - "2023-05-06T14:00:00+02:00", - "2023-05-06T16:00:00+02:00", - "2023-05-06T18:00:00+02:00", - "2023-05-06T20:00:00+02:00", - "2023-05-06T22:00:00+02:00", - "2023-05-07T00:00:00+02:00", - "2023-05-07T02:00:00+02:00", - "2023-05-07T04:00:00+02:00", - "2023-05-07T06:00:00+02:00", - "2023-05-07T08:00:00+02:00", - "2023-05-07T10:00:00+02:00", - "2023-05-07T12:00:00+02:00", - "2023-05-07T14:00:00+02:00", - "2023-05-07T16:00:00+02:00", - "2023-05-07T18:00:00+02:00", - "2023-05-07T20:00:00+02:00", - "2023-05-07T22:00:00+02:00", - "2023-05-08T00:00:00+02:00", - "2023-05-08T02:00:00+02:00", - "2023-05-08T04:00:00+02:00", - "2023-05-08T06:00:00+02:00", - "2023-05-08T08:00:00+02:00", - "2023-05-08T10:00:00+02:00", - "2023-05-08T12:00:00+02:00", - "2023-05-08T14:00:00+02:00", - "2023-05-08T16:00:00+02:00", - "2023-05-08T18:00:00+02:00", - "2023-05-08T20:00:00+02:00", - "2023-05-08T22:00:00+02:00", - "2023-05-09T00:00:00+02:00", - "2023-05-09T02:00:00+02:00", - "2023-05-09T04:00:00+02:00", - "2023-05-09T06:00:00+02:00", - "2023-05-09T08:00:00+02:00", - "2023-05-09T10:00:00+02:00", - "2023-05-09T12:00:00+02:00", - "2023-05-09T14:00:00+02:00", - "2023-05-09T16:00:00+02:00", - "2023-05-09T18:00:00+02:00", - "2023-05-09T20:00:00+02:00", - "2023-05-09T22:00:00+02:00", - "2023-05-10T00:00:00+02:00", - "2023-05-10T02:00:00+02:00", - "2023-05-10T04:00:00+02:00", - "2023-05-10T06:00:00+02:00", - "2023-05-10T08:00:00+02:00", - "2023-05-10T10:00:00+02:00", - "2023-05-10T12:00:00+02:00", - "2023-05-10T14:00:00+02:00", - "2023-05-10T16:00:00+02:00", - "2023-05-10T18:00:00+02:00", - "2023-05-10T20:00:00+02:00", - "2023-05-10T22:00:00+02:00", - "2023-05-11T00:00:00+02:00", - "2023-05-11T02:00:00+02:00", - "2023-05-11T04:00:00+02:00", - "2023-05-11T06:00:00+02:00", - "2023-05-11T08:00:00+02:00", - "2023-05-11T10:00:00+02:00", - "2023-05-11T12:00:00+02:00", - "2023-05-11T14:00:00+02:00", - "2023-05-11T16:00:00+02:00", - "2023-05-11T18:00:00+02:00", - "2023-05-11T20:00:00+02:00", - "2023-05-11T22:00:00+02:00", - "2023-05-12T00:00:00+02:00", - "2023-05-12T02:00:00+02:00", - "2023-05-12T04:00:00+02:00", - "2023-05-12T06:00:00+02:00", - "2023-05-12T08:00:00+02:00", - "2023-05-12T10:00:00+02:00", - "2023-05-12T12:00:00+02:00", - "2023-05-12T14:00:00+02:00", - "2023-05-12T16:00:00+02:00", - "2023-05-12T18:00:00+02:00", - "2023-05-12T20:00:00+02:00", - "2023-05-12T22:00:00+02:00", - "2023-05-13T00:00:00+02:00", - "2023-05-13T02:00:00+02:00", - "2023-05-13T04:00:00+02:00", - "2023-05-13T06:00:00+02:00", - "2023-05-13T08:00:00+02:00", - "2023-05-13T10:00:00+02:00", - "2023-05-13T12:00:00+02:00", - "2023-05-13T14:00:00+02:00", - "2023-05-13T16:00:00+02:00", - "2023-05-13T18:00:00+02:00", - "2023-05-13T20:00:00+02:00", - "2023-05-13T22:00:00+02:00", - "2023-05-14T00:00:00+02:00", - "2023-05-14T02:00:00+02:00", - "2023-05-14T04:00:00+02:00", - "2023-05-14T06:00:00+02:00", - "2023-05-14T08:00:00+02:00", - "2023-05-14T10:00:00+02:00", - "2023-05-14T12:00:00+02:00", - "2023-05-14T14:00:00+02:00", - "2023-05-14T16:00:00+02:00", - "2023-05-14T18:00:00+02:00", - "2023-05-14T20:00:00+02:00", - "2023-05-14T22:00:00+02:00", - "2023-05-15T00:00:00+02:00", - "2023-05-15T02:00:00+02:00", - "2023-05-15T04:00:00+02:00", - "2023-05-15T06:00:00+02:00", - "2023-05-15T08:00:00+02:00", - "2023-05-15T10:00:00+02:00", - "2023-05-15T12:00:00+02:00", - "2023-05-15T14:00:00+02:00", - "2023-05-15T16:00:00+02:00", - "2023-05-15T18:00:00+02:00", - "2023-05-15T20:00:00+02:00", - "2023-05-15T22:00:00+02:00", - "2023-05-16T00:00:00+02:00", - "2023-05-16T02:00:00+02:00", - "2023-05-16T04:00:00+02:00", - "2023-05-16T06:00:00+02:00", - "2023-05-16T08:00:00+02:00", - "2023-05-16T10:00:00+02:00", - "2023-05-16T12:00:00+02:00", - "2023-05-16T14:00:00+02:00", - "2023-05-16T16:00:00+02:00", - "2023-05-16T18:00:00+02:00", - "2023-05-16T20:00:00+02:00", - "2023-05-16T22:00:00+02:00", - "2023-05-17T00:00:00+02:00", - "2023-05-17T02:00:00+02:00", - "2023-05-17T04:00:00+02:00", - "2023-05-17T06:00:00+02:00", - "2023-05-17T08:00:00+02:00", - "2023-05-17T10:00:00+02:00", - "2023-05-17T12:00:00+02:00", - "2023-05-17T14:00:00+02:00", - "2023-05-17T16:00:00+02:00", - "2023-05-17T18:00:00+02:00", - "2023-05-17T20:00:00+02:00", - "2023-05-17T22:00:00+02:00", - "2023-05-18T00:00:00+02:00", - "2023-05-18T02:00:00+02:00", - "2023-05-18T04:00:00+02:00", - "2023-05-18T06:00:00+02:00", - "2023-05-18T08:00:00+02:00", - "2023-05-18T10:00:00+02:00", - "2023-05-18T12:00:00+02:00", - "2023-05-18T14:00:00+02:00", - "2023-05-18T16:00:00+02:00", - "2023-05-18T18:00:00+02:00", - "2023-05-18T20:00:00+02:00", - "2023-05-18T22:00:00+02:00", - "2023-05-19T00:00:00+02:00", - "2023-05-19T02:00:00+02:00", - "2023-05-19T04:00:00+02:00", - "2023-05-19T06:00:00+02:00", - "2023-05-19T08:00:00+02:00", - "2023-05-19T10:00:00+02:00", - "2023-05-19T12:00:00+02:00", - "2023-05-19T14:00:00+02:00", - "2023-05-19T16:00:00+02:00", - "2023-05-19T18:00:00+02:00", - "2023-05-19T20:00:00+02:00", - "2023-05-19T22:00:00+02:00", - "2023-05-20T00:00:00+02:00", - "2023-05-20T02:00:00+02:00", - "2023-05-20T04:00:00+02:00", - "2023-05-20T06:00:00+02:00", - "2023-05-20T08:00:00+02:00", - "2023-05-20T10:00:00+02:00", - "2023-05-20T12:00:00+02:00", - "2023-05-20T14:00:00+02:00", - "2023-05-20T16:00:00+02:00", - "2023-05-20T18:00:00+02:00", - "2023-05-20T20:00:00+02:00", - "2023-05-20T22:00:00+02:00", - "2023-05-21T00:00:00+02:00", - "2023-05-21T02:00:00+02:00", - "2023-05-21T04:00:00+02:00", - "2023-05-21T06:00:00+02:00", - "2023-05-21T08:00:00+02:00", - "2023-05-21T10:00:00+02:00", - "2023-05-21T12:00:00+02:00", - "2023-05-21T14:00:00+02:00", - "2023-05-21T16:00:00+02:00", - "2023-05-21T18:00:00+02:00", - "2023-05-21T20:00:00+02:00", - "2023-05-21T22:00:00+02:00", - "2023-05-22T00:00:00+02:00", - "2023-05-22T02:00:00+02:00", - "2023-05-22T04:00:00+02:00", - "2023-05-22T06:00:00+02:00", - "2023-05-22T08:00:00+02:00", - "2023-05-22T10:00:00+02:00", - "2023-05-22T12:00:00+02:00", - "2023-05-22T14:00:00+02:00", - "2023-05-22T16:00:00+02:00", - "2023-05-22T18:00:00+02:00", - "2023-05-22T20:00:00+02:00", - "2023-05-22T22:00:00+02:00", - "2023-05-23T00:00:00+02:00", - "2023-05-23T02:00:00+02:00", - "2023-05-23T04:00:00+02:00", - "2023-05-23T06:00:00+02:00", - "2023-05-23T08:00:00+02:00", - "2023-05-23T10:00:00+02:00", - "2023-05-23T12:00:00+02:00", - "2023-05-23T14:00:00+02:00", - "2023-05-23T16:00:00+02:00", - "2023-05-23T18:00:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastWeek.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/lastWeek.json deleted file mode 100644 index e3cb9f7a57..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastWeek.json +++ /dev/null @@ -1,2202 +0,0 @@ -{ - "global": { - "title": "oracle-shared-spool-ratio graph on srv-oracle-users", - "start": "2023-05-31T21:38:30+02:00", - "end": "2023-06-07T21:38:30+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 0, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 4811, - "metric_id": 11758, - "metric": "connTime", - "metric_legend": "connTime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#ff99cc" - }, - "legend": "connTime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - null, - 0.717525, - 0.3018625, - 0.6411125, - 0.6719375, - 0.5789875, - 0.375325, - 0.434875, - 0.7254375, - 0.41635, - 0.5296625, - 0.5241625, - 0.5008125, - 0.328025, - 0.24695, - 0.5298875, - 0.5998875, - 0.5346, - 0.508, - 0.5056375, - 0.4966125, - 0.5914375, - 0.701275, - 0.3506625, - 0.63425, - 0.5625, - 0.504375, - 0.6008125, - 0.3560625, - 0.3476125, - 0.6056125, - 0.4730875, - 0.4119875, - 0.3657125, - 0.3893625, - 0.546625, - 0.4844125, - 0.490725, - 0.61925, - 0.38985, - 0.6627375, - 0.63485, - 0.6175375, - 0.6968625, - 0.5562375, - 0.5588125, - 0.538375, - 0.4368875, - 0.3541, - 0.5216625, - 0.6249375, - 0.503875, - 0.6219, - 0.522975, - 0.5200125, - 0.2984625, - 0.5670125, - 0.5595875, - 0.552775, - 0.2506625, - 0.6193875, - 0.6573125, - 0.409525, - 0.59644833333, - 0.36721, - 0.62277333333, - 0.47325666667, - 0.61849, - 0.4591, - 0.33787, - 0.38395, - 0.34516666667, - 0.59038333333, - 0.51955333333, - 0.47505333333, - 0.43277666667, - 0.59717, - 0.70510333333, - 0.66649, - 0.46514, - 0.46619333333, - 0.40967, - 0.42753666667, - 0.56417333333, - 0.44391333333, - 0.22163333333, - 0.41199, - 0.31270666667, - 0.12166333333, - 0.45610333333, - 0.58512333333, - 0.29505333333, - 0.44652333333, - 0.38225416667, - 0.55458916667, - 0.55572166667, - 0.70581083333, - 0.38728666667, - 0.33232083333, - 0.44731583333, - 0.46990666667, - 0.5206225, - 0.35315583333, - 0.23610666667, - 0.5165575, - 0.67101083333, - 0.54885083333, - 0.64442083333, - 0.5659775, - 0.51162166667, - 0.6147, - 0.29876833333, - 0.2973525, - 0.60096416667, - 0.4574825, - 0.23486, - 0.38384916667, - 0.65109333333, - 0.51326333333, - 0.52025916667, - 0.65400666667, - 0.61474333333, - 0.550155, - 0.495895, - 0.5000875, - 0.29316166667, - 0.42695416667, - 0.54268916667, - 0.40367333333, - 0.70920166667, - 0.47661666667, - 0.78255833333, - 0.63996833333, - 0.23638833333, - 0.62122166667, - 0.30513333333, - 0.48345333333, - 0.54869083333, - 0.58614, - 0.39769583333, - 0.53929416667, - 0.69158416667, - 0.37134333333, - 0.4304575, - 0.35328833333, - 0.54430333333, - 0.33399583333, - 0.3304475, - 0.49739083333, - 0.52327, - 0.44271583333, - 0.62411083333, - 0.33883916667, - 0.57436083333, - 0.372225, - 0.47777083333, - 0.50257083333, - 0.39460083333, - 0.3795, - 0.45644333333, - 0.48521833333, - 0.25798083333, - 0.43766083333, - 0.5164875, - 0.390385, - 0.43386166667, - 0.71189833333, - 0.65404416667, - 0.336205, - 0.24493833333, - 0.57420333333, - 0.62064333333, - 0.54600666667, - 0.63159083333, - 0.50600083333, - 0.628085, - 0.42937, - 0.355585, - 0.637485, - 0.45999166667, - 0.38066166667, - 0.38246416667, - 0.45208416667, - 0.52603666667, - 0.58880416667, - 0.5446225, - 0.4066625, - 0.75533666667, - 0.499815, - 0.52572166667, - 0.32579166667, - 0.50101583333, - 0.17458583333, - 0.56188333333, - 0.62301666667, - 0.56505, - 0.5881, - 0.5673, - 0.36425, - 0.42038333333, - 0.37036666667, - 0.58353333333, - 0.50581666667, - 0.5374, - 0.22163333333, - 0.53886666667, - 0.41891666667, - 0.67956666667, - 0.5002, - 0.31088333333, - 0.62308333333, - 0.53451666667, - 0.4744, - 0.3157, - 0.77371666667, - 0.35426666667, - 0.51916666667, - 0.60275, - 0.58133333333, - 0.46916666667, - 0.40691666667, - 0.80266666667, - 0.59691666667, - 0.46365, - 0.84005, - 0.51505, - 0.61381666667, - 0.48591666667, - 0.28575, - 0.37908333333, - 0.5565, - 0.6975, - 0.47025, - 0.466, - 0.35141666667, - 0.52208333333, - 0.37233333333, - 0.34675, - 0.42075, - 0.64435, - 0.24191666667, - 0.61901666667, - 0.55591666667, - 0.51921666667, - 0.5654, - 0.38245, - 0.46736666667, - 0.65755, - 0.50645, - 0.55333333333, - 0.37858333333, - 0.50808333333, - 0.58433333333, - 0.35175, - 0.42908333333, - 0.36233333333, - 0.56158333333, - 0.31195, - 0.68023333333, - 0.59651666667, - 0.64825, - 0.71858333333, - 0.54138333333, - 0.73991666667, - 0.55478333333, - 0.4892, - 0.56783333333, - 0.63965, - 0.47205, - 0.27215, - 0.25745, - 0.70008333333, - 0.59661666667, - 0.5026, - 0.49326666667, - 0.3655, - 0.60356333333, - 0.2132275, - 0.8226925, - 0.36787, - 0.4914825, - 0.3909675, - 0.5646075, - 0.3643125, - 0.457405, - 0.471935, - 0.4731125, - 0.7753075, - 0.49163, - 0.244405, - 0.557185, - 0.4107075, - 0.54546666667, - 0.64036666667, - 0.29668, - 0.3992, - 0.63089666667, - 0.75758666667, - 0.56485, - 0.413955, - 0.5602, - 0.431975, - 0.43485666667, - 0.30827166667, - 0.39586333333, - 0.37732833333, - 0.51866333333, - 0.52611333333, - 0.31280166667, - 0.50100333333, - 0.549735, - 0.42203833333, - 0.45060333333, - 0.42550666667, - 0.54967666667, - 0.37341666667, - 0.38782333333, - 0.51425166667, - 0.51834, - 0.45271833333, - 0.711285, - 0.577775, - 0.47911833333, - 0.44316666667, - 0.34324666667, - 0.33805833333, - 0.27513166667, - 0.53801166667, - 0.77332333333, - 0.47316, - 0.574345, - 0.60672666667, - 0.62811833333, - 0.50659, - 0.42655083333, - 0.2728925, - 0.67187, - 0.3979, - 0.50411166667, - 0.65740666667, - 0.63976833333, - 0.6468725, - 0.47726833333, - 0.4558775, - 0.30631666667, - 0.5109975, - 0.5717275, - 0.66228083333, - 0.69612166667, - 0.426675, - 0.35191333333, - 0.38965666667, - 0.2744825, - 0.5117825, - 0.55155416667, - 0.41036583333, - 0.46853916667, - 0.62363833333, - 0.3687475, - 0.44296916667, - 0.24307666667, - 0.765635, - 0.63333083333, - 0.4951, - 0.3801225, - 0.4771775, - 0.39723416667, - 0.4643, - 0.4289525, - 0.44795416667, - 0.76632583333, - 0.59939916667, - 0.2934925, - 0.19469416667, - 0.19469333333, - 0.492425, - 0.63350833333, - 0.33733833333, - 0.52109916667, - 0.7505775, - 0.40881, - 0.69642, - 0.76366, - 0.58523, - 0.44103, - 0.6813, - 0.65428, - 0.50898, - 0.58906, - 0.26844, - 0.38626, - 0.44927, - 0.40626, - 0.43084, - 0.54353, - 0.15838, - 0.66925, - 0.37817, - 0.4707, - 0.51832, - 0.5091, - 0.8043, - 0.40112, - 0.4939, - 0.54619, - 0.55022, - 0.59386, - 0.32591, - 0.2247, - 0.52951, - 0.51087, - 0.45835, - 0.33692, - 0.67881, - 0.62172, - 0.52216, - 0.45299, - 0.56436, - 0.49893, - 0.55314, - 0.49332, - 0.46613, - 0.23186, - 0.5636, - 0.11787, - 0.55091, - 0.44308, - 0.39479, - 0.25959, - 0.46345, - 0.41195, - 0.64631, - 0.78474, - 0.5461, - 0.60538, - 0.36694, - 0.61858, - 0.62356, - 0.72798, - 0.65403, - 0.44993, - 0.41512, - 0.408, - 0.57437, - 0.52494, - 0.56954, - 0.61914, - 0.41972, - 0.56292, - 0.66072, - 0.60597, - 0.3471, - 0.50783, - 0.55257, - 0.61786, - 0.43487, - 0.50873, - 0.4697, - 0.67452, - 0.63891, - 0.42052, - 0.50675, - 0.65396, - 0.44012, - 0.49093, - 0.62349, - 0.24831, - 0.40325, - 0.3517, - 0.2406375, - 0.4074125, - 0.57481666667, - 0.44426666667, - 0.57990416667, - 0.3584625, - 0.56930833333, - 0.461075, - 0.69519166667, - 0.58419166667, - 0.6644625, - 0.58740833333, - 0.502175, - 0.54106666667, - 0.39467916667, - 0.54319166667, - 0.675225, - 0.6772375, - 0.4582625, - 0.4673875, - 0.43303333333, - 0.44830416667, - 0.421425, - 0.4474125, - 0.72664583333, - 0.55170833333, - 0.4613375, - 0.71693333333, - 0.35159583333, - 0.49416666667, - 0.41411666667, - 0.52532083333, - 0.46037916667, - 0.63142083333, - 0.6827625, - 0.40663333333 - ], - "prints": [ - [ - "Last:0.41" - ], - [ - "Min:0.12" - ], - [ - "Max:0.84" - ], - [ - "Average:0.50" - ] - ], - "last_value": 0.41, - "minimum_value": 0.12, - "maximum_value": 0.84, - "average_value": 0.5 - }, - { - "index_id": 4811, - "metric_id": 11757, - "metric": "querytime", - "metric_legend": "querytime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#6666ff" - }, - "legend": "querytime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - null, - 0.3822375, - 0.338175, - 0.729925, - 0.6532, - 0.6622875, - 0.45505, - 0.60315, - 0.401275, - 0.54565, - 0.4648375, - 0.56345, - 0.2957375, - 0.4214125, - 0.5022875, - 0.52665, - 0.3344125, - 0.634875, - 0.33875, - 0.5235, - 0.43645, - 0.45645, - 0.61025, - 0.653525, - 0.44325, - 0.398125, - 0.350875, - 0.3941875, - 0.4985875, - 0.2608125, - 0.269875, - 0.4928875, - 0.292925, - 0.43555, - 0.6956375, - 0.615925, - 0.3165375, - 0.6310875, - 0.5219875, - 0.5560875, - 0.5781875, - 0.427875, - 0.272275, - 0.7289, - 0.5525875, - 0.626725, - 0.6548, - 0.56645, - 0.3159625, - 0.5493, - 0.5752875, - 0.46215, - 0.3014875, - 0.3867625, - 0.539775, - 0.6039375, - 0.4355875, - 0.411425, - 0.4830375, - 0.3762125, - 0.71735, - 0.269, - 0.567975, - 0.49262833333, - 0.40225333333, - 0.62421, - 0.34907333333, - 0.66614, - 0.64291666667, - 0.47280333333, - 0.5396, - 0.39403, - 0.44625666667, - 0.72860333333, - 0.22214666667, - 0.76609, - 0.47886666667, - 0.50008, - 0.70910666667, - 0.52188, - 0.44055, - 0.36468666667, - 0.36503333333, - 0.41122, - 0.5653, - 0.22648, - 0.47388333333, - 0.40938666667, - 0.54979333333, - 0.4558, - 0.27218, - 0.84006333333, - 0.25509833333, - 0.34533916667, - 0.37986833333, - 0.41476833333, - 0.36977166667, - 0.24393166667, - 0.5005625, - 0.374215, - 0.85380833333, - 0.4801225, - 0.31904166667, - 0.4585075, - 0.752745, - 0.21556833333, - 0.4998575, - 0.60881666667, - 0.40523416667, - 0.48311333333, - 0.6045525, - 0.20181833333, - 0.59113666667, - 0.61002333333, - 0.480365, - 0.37949833333, - 0.24222583333, - 0.7307925, - 0.38327416667, - 0.40005166667, - 0.50885, - 0.44563666667, - 0.55531166667, - 0.49530833333, - 0.36818666667, - 0.5764775, - 0.64380083333, - 0.42206, - 0.29359166667, - 0.49560666667, - 0.443325, - 0.25875833333, - 0.30041833333, - 0.3564575, - 0.58502416667, - 0.74223416667, - 0.50057833333, - 0.4538275, - 0.34179333333, - 0.29270583333, - 0.60702083333, - 0.4216275, - 0.25602583333, - 0.56200416667, - 0.41060916667, - 0.3873225, - 0.7328475, - 0.44749666667, - 0.48708083333, - 0.31724666667, - 0.542455, - 0.32911083333, - 0.24504166667, - 0.4943, - 0.69643166667, - 0.45696916667, - 0.57769166667, - 0.53687416667, - 0.34264083333, - 0.46102416667, - 0.47288583333, - 0.581615, - 0.65317833333, - 0.46009833333, - 0.52495416667, - 0.41317166667, - 0.55043333333, - 0.57696583333, - 0.48937083333, - 0.18298166667, - 0.656815, - 0.54156916667, - 0.62982333333, - 0.55033916667, - 0.60631083333, - 0.76121, - 0.18459, - 0.76492, - 0.66709, - 0.50244, - 0.39493, - 0.65535666667, - 0.35731916667, - 0.64019916667, - 0.456475, - 0.55792416667, - 0.66605916667, - 0.21065083333, - 0.4248575, - 0.850955, - 0.53539416667, - 0.40172916667, - 0.606185, - 0.58081666667, - 0.54806666667, - 0.33323333333, - 0.51793333333, - 0.55431666667, - 0.59668333333, - 0.49018333333, - 0.59998333333, - 0.44546666667, - 0.33053333333, - 0.26628333333, - 0.28708333333, - 0.39905, - 0.6059, - 0.66223333333, - 0.61336666667, - 0.64191666667, - 0.64243333333, - 0.2932, - 0.46686666667, - 0.6745, - 0.43336666667, - 0.44585, - 0.55441666667, - 0.39591666667, - 0.59966666667, - 0.53675, - 0.15408333333, - 0.418, - 0.6015, - 0.5368, - 0.60053333333, - 0.59256666667, - 0.49055, - 0.51608333333, - 0.56116666667, - 0.48791666667, - 0.27166666667, - 0.44933333333, - 0.30175, - 0.532, - 0.29925, - 0.68191666667, - 0.69808333333, - 0.39383333333, - 0.64958333333, - 0.59386666667, - 0.60863333333, - 0.4553, - 0.44306666667, - 0.35461666667, - 0.23823333333, - 0.39873333333, - 0.31028333333, - 0.28183333333, - 0.51358333333, - 0.53908333333, - 0.38191666667, - 0.6085, - 0.557, - 0.55133333333, - 0.46758333333, - 0.43775, - 0.45041666667, - 0.52871666667, - 0.62766666667, - 0.16445, - 0.56378333333, - 0.6319, - 0.71301666667, - 0.19243333333, - 0.36086666667, - 0.52955, - 0.56008333333, - 0.46958333333, - 0.61478333333, - 0.5179, - 0.37285, - 0.54513333333, - 0.89198333333, - 0.34831666667, - 0.79711666667, - 0.46571666667, - 0.45108583333, - 0.65635, - 0.710995, - 0.62707, - 0.3558975, - 0.49199, - 0.3899075, - 0.34151, - 0.380945, - 0.455615, - 0.5316275, - 0.4313475, - 0.560775, - 0.4743425, - 0.5747375, - 0.4835775, - 0.65969916667, - 0.42680333333, - 0.600725, - 0.32630666667, - 0.64745666667, - 0.31762833333, - 0.42268333333, - 0.35116833333, - 0.47142, - 0.26832333333, - 0.34496666667, - 0.688725, - 0.49774833333, - 0.34480666667, - 0.54177, - 0.55014166667, - 0.37234166667, - 0.60997, - 0.59000833333, - 0.565245, - 0.37924666667, - 0.389445, - 0.35244833333, - 0.827515, - 0.41951166667, - 0.65853166667, - 0.42363333333, - 0.68144666667, - 0.44951, - 0.26957, - 0.33074833333, - 0.72332666667, - 0.50786833333, - 0.42016166667, - 0.59982, - 0.66384833333, - 0.3585, - 0.622105, - 0.5329, - 0.44583666667, - 0.39592083333, - 0.675235, - 0.71880166667, - 0.43023166667, - 0.35486, - 0.53464583333, - 0.33980833333, - 0.5025275, - 0.73073, - 0.37100083333, - 0.458425, - 0.16272833333, - 0.66322666667, - 0.46470333333, - 0.5706925, - 0.51309583333, - 0.4167775, - 0.51913833333, - 0.36356833333, - 0.67057583333, - 0.46865333333, - 0.56207416667, - 0.64422833333, - 0.55513166667, - 0.69586833333, - 0.64558416667, - 0.39396166667, - 0.70361083333, - 0.38941333333, - 0.46966833333, - 0.479135, - 0.51729916667, - 0.34119666667, - 0.52859583333, - 0.4759925, - 0.28715, - 0.47405416667, - 0.27516, - 0.23419833333, - 0.31827916667, - 0.46054416667, - 0.64301333333, - 0.52912333333, - 0.45455166667, - 0.73102333333, - 0.40912583333, - 0.3304225, - 0.4438325, - 0.34953, - 0.53485, - 0.81125, - 0.25488, - 0.55834, - 0.35964, - 0.26034, - 0.37592, - 0.39875, - 0.66929, - 0.66451, - 0.5947, - 0.27555, - 0.68353, - 0.49617, - 0.653, - 0.48443, - 0.39418, - 0.36428, - 0.53593, - 0.3297, - 0.43443, - 0.46853, - 0.64149, - 0.38523, - 0.39072, - 0.44623, - 0.36313, - 0.50542, - 0.43385, - 0.55568, - 0.79068, - 0.46728, - 0.54486, - 0.60739, - 0.46496, - 0.61119, - 0.38873, - 0.56806, - 0.747, - 0.53613, - 0.53121, - 0.46506, - 0.59626, - 0.69317, - 0.68011, - 0.51598, - 0.50257, - 0.54439, - 0.40571, - 0.2189, - 0.64132, - 0.29015, - 0.43577, - 0.37661, - 0.46952, - 0.45527, - 0.66985, - 0.40971, - 0.63007, - 0.63755, - 0.65143, - 0.57865, - 0.65552, - 0.36992, - 0.23763, - 0.48393, - 0.36113, - 0.39058, - 0.40755, - 0.56333, - 0.48995, - 0.55673, - 0.37367, - 0.48381, - 0.40106, - 0.48643, - 0.51592, - 0.29743, - 0.5026, - 0.42763, - 0.46854, - 0.41662, - 0.50732, - 0.385, - 0.61506, - 0.49011, - 0.36046, - 0.5442, - 0.61745833333, - 0.392325, - 0.4967625, - 0.30943333333, - 0.58880416667, - 0.57861666667, - 0.72248333333, - 0.42585, - 0.6050125, - 0.64172083333, - 0.4269375, - 0.20662083333, - 0.43435833333, - 0.71460833333, - 0.42285833333, - 0.48760416667, - 0.5523, - 0.55450833333, - 0.5237, - 0.77244166667, - 0.69525, - 0.58763333333, - 0.44484166667, - 0.61220833333, - 0.50095416667, - 0.54782916667, - 0.5573, - 0.7095625, - 0.41794583333, - 0.49679166667, - 0.4172, - 0.53237916667, - 0.48497083333, - 0.608475, - 0.55396666667, - 0.62546666667 - ], - "prints": [ - [ - "Last:0.63" - ], - [ - "Min:0.15" - ], - [ - "Max:0.89" - ], - [ - "Average:0.49" - ] - ], - "last_value": 0.63, - "minimum_value": 0.15, - "maximum_value": 0.89, - "average_value": 0.49 - }, - { - "index_id": 4811, - "metric_id": 11756, - "metric": "used", - "metric_legend": "used", - "unit": "%", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 8, - "host_id": null, - "service_id": null, - "name": "Used", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": "used", - "ds_color_line": "#2B28D7", - "ds_color_line_mode": "0", - "ds_color_area": "#050AF9", - "ds_color_area_warn": null, - "ds_color_area_crit": null, - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "used", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 1, - "data": [ - null, - 75.3011875, - 72.701875, - 76.0167625, - 77.1073125, - 77.69285, - 80.2417, - 78.7382375, - 79.45205, - 81.0908625, - 80.5548625, - 80.668475, - 78.979675, - 79.0966875, - 82.8746, - 83.72185, - 84.4060125, - 88.59015, - 90.0966875, - 89.238625, - 87.6741375, - 86.301075, - 85.9866375, - 84.2715875, - 80.7764375, - 81.1740625, - 80.62725, - 82.847125, - 84.5257125, - 79.901275, - 79.2864875, - 80.3480625, - 80.181925, - 80.396225, - 82.583625, - 84.016875, - 84.045875, - 86.91195, - 87.9055, - 86.8288875, - 81.1321375, - 77.683675, - 80.9037, - 81.4005125, - 80.3968625, - 80.5861125, - 80.9034875, - 80.96685, - 77.6486125, - 78.8831625, - 80.6013125, - 82.2192125, - 83.39895, - 84.18365, - 86.6931625, - 87.6480875, - 88.556875, - 86.548725, - 85.8728875, - 87.7177, - 87.7906, - 88.5137875, - 86.34185, - 84.619306667, - 86.954396667, - 87.26102, - 85.965446667, - 81.80268, - 78.111126667, - 74.197206667, - 77.399083333, - 78.85909, - 79.281386667, - 82.736843333, - 85.45574, - 85.426433333, - 89.254713333, - 91.27352, - 92.164943333, - 90.351, - 90.002126667, - 91.9092, - 95.647476667, - 97.08391, - 98.31337, - 95.339653333, - 95.52575, - 93.628453333, - 93.64629, - 94.364876667, - 91.26281, - 94.746766667, - 91.7748525, - 88.535216667, - 90.4502975, - 91.635938333, - 94.736506667, - 95.6047775, - 97.476596667, - 94.989260833, - 95.033961667, - 96.242233333, - 93.5059225, - 94.352619167, - 92.387683333, - 94.498268333, - 94.36248, - 94.02465, - 92.065673333, - 90.508024167, - 89.030559167, - 87.58097, - 89.509935, - 92.812699167, - 91.202060833, - 91.9585075, - 94.023786667, - 92.90212, - 90.4467425, - 89.739971667, - 92.775635, - 93.825290833, - 90.636063333, - 89.875763333, - 86.827475, - 88.0182975, - 91.871829167, - 91.756616667, - 91.505121667, - 89.615869167, - 91.229351667, - 94.891750833, - 94.960114167, - 95.58294, - 95.994029167, - 95.9366675, - 96.498086667, - 97.487198333, - 93.075826667, - 94.302755833, - 93.073150833, - 90.271178333, - 89.814095, - 87.417926667, - 86.022469167, - 85.3772725, - 85.730900833, - 87.691193333, - 88.513690833, - 89.176271667, - 89.875075, - 92.313001667, - 94.845433333, - 96.612829167, - 94.3659575, - 94.697136667, - 96.204745833, - 97.567138333, - 97.420164167, - 98.677866667, - 98.801283333, - 98.172911667, - 97.751070833, - 96.347039167, - 94.636588333, - 92.814395, - 92.377689167, - 92.916798333, - 93.032718333, - 94.1146975, - 93.295709167, - 90.99396, - 92.248504167, - 93.131444167, - 91.676540833, - 93.38632, - 95.87702, - 95.42711, - 96.049845, - 98.458085833, - 98.224996667, - 95.8955225, - 93.5389625, - 90.5482675, - 88.2340275, - 87.588475, - 85.262625833, - 86.147955, - 85.77075, - 86.131816667, - 86.20979, - 84.288503333, - 86.749560833, - 82.449683333, - 79.403566667, - 80.40625, - 77.62185, - 77.505733333, - 75.580283333, - 75.1924, - 74.935433333, - 75.530216667, - 76.428483333, - 75.221, - 75.210733333, - 75.364483333, - 74.642916667, - 72.729216667, - 72.219733333, - 72.1265, - 76.7763, - 80.489316667, - 81.445283333, - 79.979783333, - 81.412816667, - 84.612216667, - 87.098833333, - 89.32225, - 91.17525, - 91.2465, - 88.707333333, - 88.058916667, - 87.372083333, - 84.8882, - 84.867116667, - 85.636633333, - 83.310733333, - 82.562333333, - 81.755333333, - 79.718333333, - 77.312666667, - 77.36875, - 79.187666667, - 80.764166667, - 82.968083333, - 81.657916667, - 80.852166667, - 82.371916667, - 85.612, - 84.52515, - 81.67235, - 83.9048, - 85.694816667, - 88.53345, - 88.750566667, - 87.80635, - 87.07455, - 87.095933333, - 84.714483333, - 84.81275, - 88.785, - 90.634, - 91.73825, - 93.27175, - 91.766333333, - 90.315, - 86.82625, - 86.059816667, - 90.49965, - 90.212416667, - 91.374283333, - 92.0294, - 91.482916667, - 94.464233333, - 95.869833333, - 97.885783333, - 98.732733333, - 97.9996, - 97.174766667, - 96.148283333, - 97.29175, - 96.05795, - 96.3868, - 97.399783333, - 95.241033333, - 96.880383333, - 97.934975833, - 95.40756, - 93.9280425, - 92.8780525, - 90.131495, - 89.3369225, - 88.7673325, - 87.5925, - 88.31823, - 92.36844, - 90.9536425, - 91.4629525, - 88.317385, - 86.5111225, - 85.572935, - 84.9701425, - 86.193996667, - 87.876206667, - 91.04955, - 92.813215, - 92.907306667, - 92.374458333, - 93.688358333, - 93.683388333, - 93.016803333, - 92.019563333, - 93.503391667, - 90.542578333, - 92.529488333, - 92.534118333, - 93.654428333, - 92.217821667, - 93.979301667, - 93.334701667, - 90.995645, - 89.265961667, - 90.142598333, - 92.359028333, - 92.355875, - 90.124831667, - 90.137076667, - 91.351265, - 92.609895, - 94.423845, - 95.92939, - 96.94342, - 97.658953333, - 98.350373333, - 98.860638333, - 97.971453333, - 95.972083333, - 92.49751, - 90.06317, - 90.96775, - 92.706511667, - 91.154745833, - 93.041470833, - 95.212069167, - 95.547953333, - 93.797341667, - 94.932218333, - 94.738048333, - 92.303049167, - 93.12273, - 95.324159167, - 97.788798333, - 96.461085, - 97.918005, - 97.656589167, - 95.453511667, - 93.404599167, - 96.0549925, - 96.180735, - 92.732435833, - 90.8238375, - 91.933284167, - 91.178560833, - 92.574173333, - 91.4252825, - 87.24002, - 86.583490833, - 86.893840833, - 87.912079167, - 85.586765, - 78.548946667, - 77.958821667, - 79.511501667, - 82.340836667, - 81.43414, - 82.6612425, - 85.1368525, - 84.618974167, - 83.406545833, - 83.217361667, - 84.796903333, - 88.710369167, - 89.576425, - 87.697465, - 85.419298333, - 89.328040833, - 89.288233333, - 89.594449167, - 89.396855833, - 89.352433333, - 87.07019, - 84.88146, - 84.18839, - 83.16835, - 79.62206, - 79.43043, - 79.3563, - 79.27835, - 79.17697, - 76.76732, - 75.29581, - 75.70572, - 77.68538, - 76.74653, - 77.60974, - 79.9725, - 83.84825, - 85.77623, - 88.76174, - 86.57208, - 88.47665, - 90.85134, - 90.79955, - 87.98236, - 89.54416, - 86.85839, - 84.23926, - 84.02244, - 79.67462, - 79.58342, - 82.33326, - 82.35789, - 81.01324, - 81.55955, - 81.87204, - 83.22185, - 81.36665, - 81.08699, - 84.38985, - 86.73615, - 85.82253, - 86.40703, - 89.32901, - 88.43318, - 91.59042, - 91.78025, - 93.31614, - 96.78994, - 98.67566, - 98.30026, - 96.97067, - 96.7663, - 94.81573, - 95.48175, - 98.94147, - 97.88792, - 96.25044, - 95.91016, - 95.94154, - 98.28326, - 97.84947, - 96.28364, - 97.1102, - 95.14073, - 93.46838, - 96.50306, - 98.20423, - 98.88803, - 98.65825, - 98.88318, - 98.68902, - 97.16819, - 95.18848, - 94.46906, - 95.27017, - 93.6273, - 90.02585, - 88.44419, - 86.68886, - 87.13106, - 88.26944, - 86.24131, - 85.55237, - 82.99216, - 82.86858, - 84.60967, - 83.1773, - 83.97271, - 82.51906, - 84.892720833, - 86.416304167, - 84.4, - 86.107516667, - 82.4546875, - 79.498166667, - 78.921458333, - 76.025141667, - 72.7244875, - 72.484195833, - 74.67945, - 76.033079167, - 74.760233333, - 72.661283333, - 74.655441667, - 78.608441667, - 78.245175, - 77.557866667, - 78.07075, - 79.527925, - 81.827258333, - 84.270954167, - 84.8338625, - 87.5681375, - 87.761895833, - 88.1756375, - 86.58295, - 86.034920833, - 82.764025, - 83.575166667, - 84.764741667, - 86.313608333, - 91.112654167, - 90.49295, - 92.0893625, - 92.936327778 - ], - "prints": [ - [ - "Last:92.94" - ], - [ - "Average:88.05" - ] - ], - "last_value": 92.94, - "minimum_value": null, - "maximum_value": null, - "average_value": 88.05 - } - ], - "times": [ - "2023-05-31T21:40:00+02:00", - "2023-05-31T22:00:00+02:00", - "2023-05-31T22:20:00+02:00", - "2023-05-31T22:40:00+02:00", - "2023-05-31T23:00:00+02:00", - "2023-05-31T23:20:00+02:00", - "2023-05-31T23:40:00+02:00", - "2023-06-01T00:00:00+02:00", - "2023-06-01T00:20:00+02:00", - "2023-06-01T00:40:00+02:00", - "2023-06-01T01:00:00+02:00", - "2023-06-01T01:20:00+02:00", - "2023-06-01T01:40:00+02:00", - "2023-06-01T02:00:00+02:00", - "2023-06-01T02:20:00+02:00", - "2023-06-01T02:40:00+02:00", - "2023-06-01T03:00:00+02:00", - "2023-06-01T03:20:00+02:00", - "2023-06-01T03:40:00+02:00", - "2023-06-01T04:00:00+02:00", - "2023-06-01T04:20:00+02:00", - "2023-06-01T04:40:00+02:00", - "2023-06-01T05:00:00+02:00", - "2023-06-01T05:20:00+02:00", - "2023-06-01T05:40:00+02:00", - "2023-06-01T06:00:00+02:00", - "2023-06-01T06:20:00+02:00", - "2023-06-01T06:40:00+02:00", - "2023-06-01T07:00:00+02:00", - "2023-06-01T07:20:00+02:00", - "2023-06-01T07:40:00+02:00", - "2023-06-01T08:00:00+02:00", - "2023-06-01T08:20:00+02:00", - "2023-06-01T08:40:00+02:00", - "2023-06-01T09:00:00+02:00", - "2023-06-01T09:20:00+02:00", - "2023-06-01T09:40:00+02:00", - "2023-06-01T10:00:00+02:00", - "2023-06-01T10:20:00+02:00", - "2023-06-01T10:40:00+02:00", - "2023-06-01T11:00:00+02:00", - "2023-06-01T11:20:00+02:00", - "2023-06-01T11:40:00+02:00", - "2023-06-01T12:00:00+02:00", - "2023-06-01T12:20:00+02:00", - "2023-06-01T12:40:00+02:00", - "2023-06-01T13:00:00+02:00", - "2023-06-01T13:20:00+02:00", - "2023-06-01T13:40:00+02:00", - "2023-06-01T14:00:00+02:00", - "2023-06-01T14:20:00+02:00", - "2023-06-01T14:40:00+02:00", - "2023-06-01T15:00:00+02:00", - "2023-06-01T15:20:00+02:00", - "2023-06-01T15:40:00+02:00", - "2023-06-01T16:00:00+02:00", - "2023-06-01T16:20:00+02:00", - "2023-06-01T16:40:00+02:00", - "2023-06-01T17:00:00+02:00", - "2023-06-01T17:20:00+02:00", - "2023-06-01T17:40:00+02:00", - "2023-06-01T18:00:00+02:00", - "2023-06-01T18:20:00+02:00", - "2023-06-01T18:40:00+02:00", - "2023-06-01T19:00:00+02:00", - "2023-06-01T19:20:00+02:00", - "2023-06-01T19:40:00+02:00", - "2023-06-01T20:00:00+02:00", - "2023-06-01T20:20:00+02:00", - "2023-06-01T20:40:00+02:00", - "2023-06-01T21:00:00+02:00", - "2023-06-01T21:20:00+02:00", - "2023-06-01T21:40:00+02:00", - "2023-06-01T22:00:00+02:00", - "2023-06-01T22:20:00+02:00", - "2023-06-01T22:40:00+02:00", - "2023-06-01T23:00:00+02:00", - "2023-06-01T23:20:00+02:00", - "2023-06-01T23:40:00+02:00", - "2023-06-02T00:00:00+02:00", - "2023-06-02T00:20:00+02:00", - "2023-06-02T00:40:00+02:00", - "2023-06-02T01:00:00+02:00", - "2023-06-02T01:20:00+02:00", - "2023-06-02T01:40:00+02:00", - "2023-06-02T02:00:00+02:00", - "2023-06-02T02:20:00+02:00", - "2023-06-02T02:40:00+02:00", - "2023-06-02T03:00:00+02:00", - "2023-06-02T03:20:00+02:00", - "2023-06-02T03:40:00+02:00", - "2023-06-02T04:00:00+02:00", - "2023-06-02T04:20:00+02:00", - "2023-06-02T04:40:00+02:00", - "2023-06-02T05:00:00+02:00", - "2023-06-02T05:20:00+02:00", - "2023-06-02T05:40:00+02:00", - "2023-06-02T06:00:00+02:00", - "2023-06-02T06:20:00+02:00", - "2023-06-02T06:40:00+02:00", - "2023-06-02T07:00:00+02:00", - "2023-06-02T07:20:00+02:00", - "2023-06-02T07:40:00+02:00", - "2023-06-02T08:00:00+02:00", - "2023-06-02T08:20:00+02:00", - "2023-06-02T08:40:00+02:00", - "2023-06-02T09:00:00+02:00", - "2023-06-02T09:20:00+02:00", - "2023-06-02T09:40:00+02:00", - "2023-06-02T10:00:00+02:00", - "2023-06-02T10:20:00+02:00", - "2023-06-02T10:40:00+02:00", - "2023-06-02T11:00:00+02:00", - "2023-06-02T11:20:00+02:00", - "2023-06-02T11:40:00+02:00", - "2023-06-02T12:00:00+02:00", - "2023-06-02T12:20:00+02:00", - "2023-06-02T12:40:00+02:00", - "2023-06-02T13:00:00+02:00", - "2023-06-02T13:20:00+02:00", - "2023-06-02T13:40:00+02:00", - "2023-06-02T14:00:00+02:00", - "2023-06-02T14:20:00+02:00", - "2023-06-02T14:40:00+02:00", - "2023-06-02T15:00:00+02:00", - "2023-06-02T15:20:00+02:00", - "2023-06-02T15:40:00+02:00", - "2023-06-02T16:00:00+02:00", - "2023-06-02T16:20:00+02:00", - "2023-06-02T16:40:00+02:00", - "2023-06-02T17:00:00+02:00", - "2023-06-02T17:20:00+02:00", - "2023-06-02T17:40:00+02:00", - "2023-06-02T18:00:00+02:00", - "2023-06-02T18:20:00+02:00", - "2023-06-02T18:40:00+02:00", - "2023-06-02T19:00:00+02:00", - "2023-06-02T19:20:00+02:00", - "2023-06-02T19:40:00+02:00", - "2023-06-02T20:00:00+02:00", - "2023-06-02T20:20:00+02:00", - "2023-06-02T20:40:00+02:00", - "2023-06-02T21:00:00+02:00", - "2023-06-02T21:20:00+02:00", - "2023-06-02T21:40:00+02:00", - "2023-06-02T22:00:00+02:00", - "2023-06-02T22:20:00+02:00", - "2023-06-02T22:40:00+02:00", - "2023-06-02T23:00:00+02:00", - "2023-06-02T23:20:00+02:00", - "2023-06-02T23:40:00+02:00", - "2023-06-03T00:00:00+02:00", - "2023-06-03T00:20:00+02:00", - "2023-06-03T00:40:00+02:00", - "2023-06-03T01:00:00+02:00", - "2023-06-03T01:20:00+02:00", - "2023-06-03T01:40:00+02:00", - "2023-06-03T02:00:00+02:00", - "2023-06-03T02:20:00+02:00", - "2023-06-03T02:40:00+02:00", - "2023-06-03T03:00:00+02:00", - "2023-06-03T03:20:00+02:00", - "2023-06-03T03:40:00+02:00", - "2023-06-03T04:00:00+02:00", - "2023-06-03T04:20:00+02:00", - "2023-06-03T04:40:00+02:00", - "2023-06-03T05:00:00+02:00", - "2023-06-03T05:20:00+02:00", - "2023-06-03T05:40:00+02:00", - "2023-06-03T06:00:00+02:00", - "2023-06-03T06:20:00+02:00", - "2023-06-03T06:40:00+02:00", - "2023-06-03T07:00:00+02:00", - "2023-06-03T07:20:00+02:00", - "2023-06-03T07:40:00+02:00", - "2023-06-03T08:00:00+02:00", - "2023-06-03T08:20:00+02:00", - "2023-06-03T08:40:00+02:00", - "2023-06-03T09:00:00+02:00", - "2023-06-03T09:20:00+02:00", - "2023-06-03T09:40:00+02:00", - "2023-06-03T10:00:00+02:00", - "2023-06-03T10:20:00+02:00", - "2023-06-03T10:40:00+02:00", - "2023-06-03T11:00:00+02:00", - "2023-06-03T11:20:00+02:00", - "2023-06-03T11:40:00+02:00", - "2023-06-03T12:00:00+02:00", - "2023-06-03T12:20:00+02:00", - "2023-06-03T12:40:00+02:00", - "2023-06-03T13:00:00+02:00", - "2023-06-03T13:20:00+02:00", - "2023-06-03T13:40:00+02:00", - "2023-06-03T14:00:00+02:00", - "2023-06-03T14:20:00+02:00", - "2023-06-03T14:40:00+02:00", - "2023-06-03T15:00:00+02:00", - "2023-06-03T15:20:00+02:00", - "2023-06-03T15:40:00+02:00", - "2023-06-03T16:00:00+02:00", - "2023-06-03T16:20:00+02:00", - "2023-06-03T16:40:00+02:00", - "2023-06-03T17:00:00+02:00", - "2023-06-03T17:20:00+02:00", - "2023-06-03T17:40:00+02:00", - "2023-06-03T18:00:00+02:00", - "2023-06-03T18:20:00+02:00", - "2023-06-03T18:40:00+02:00", - "2023-06-03T19:00:00+02:00", - "2023-06-03T19:20:00+02:00", - "2023-06-03T19:40:00+02:00", - "2023-06-03T20:00:00+02:00", - "2023-06-03T20:20:00+02:00", - "2023-06-03T20:40:00+02:00", - "2023-06-03T21:00:00+02:00", - "2023-06-03T21:20:00+02:00", - "2023-06-03T21:40:00+02:00", - "2023-06-03T22:00:00+02:00", - "2023-06-03T22:20:00+02:00", - "2023-06-03T22:40:00+02:00", - "2023-06-03T23:00:00+02:00", - "2023-06-03T23:20:00+02:00", - "2023-06-03T23:40:00+02:00", - "2023-06-04T00:00:00+02:00", - "2023-06-04T00:20:00+02:00", - "2023-06-04T00:40:00+02:00", - "2023-06-04T01:00:00+02:00", - "2023-06-04T01:20:00+02:00", - "2023-06-04T01:40:00+02:00", - "2023-06-04T02:00:00+02:00", - "2023-06-04T02:20:00+02:00", - "2023-06-04T02:40:00+02:00", - "2023-06-04T03:00:00+02:00", - "2023-06-04T03:20:00+02:00", - "2023-06-04T03:40:00+02:00", - "2023-06-04T04:00:00+02:00", - "2023-06-04T04:20:00+02:00", - "2023-06-04T04:40:00+02:00", - "2023-06-04T05:00:00+02:00", - "2023-06-04T05:20:00+02:00", - "2023-06-04T05:40:00+02:00", - "2023-06-04T06:00:00+02:00", - "2023-06-04T06:20:00+02:00", - "2023-06-04T06:40:00+02:00", - "2023-06-04T07:00:00+02:00", - "2023-06-04T07:20:00+02:00", - "2023-06-04T07:40:00+02:00", - "2023-06-04T08:00:00+02:00", - "2023-06-04T08:20:00+02:00", - "2023-06-04T08:40:00+02:00", - "2023-06-04T09:00:00+02:00", - "2023-06-04T09:20:00+02:00", - "2023-06-04T09:40:00+02:00", - "2023-06-04T10:00:00+02:00", - "2023-06-04T10:20:00+02:00", - "2023-06-04T10:40:00+02:00", - "2023-06-04T11:00:00+02:00", - "2023-06-04T11:20:00+02:00", - "2023-06-04T11:40:00+02:00", - "2023-06-04T12:00:00+02:00", - "2023-06-04T12:20:00+02:00", - "2023-06-04T12:40:00+02:00", - "2023-06-04T13:00:00+02:00", - "2023-06-04T13:20:00+02:00", - "2023-06-04T13:40:00+02:00", - "2023-06-04T14:00:00+02:00", - "2023-06-04T14:20:00+02:00", - "2023-06-04T14:40:00+02:00", - "2023-06-04T15:00:00+02:00", - "2023-06-04T15:20:00+02:00", - "2023-06-04T15:40:00+02:00", - "2023-06-04T16:00:00+02:00", - "2023-06-04T16:20:00+02:00", - "2023-06-04T16:40:00+02:00", - "2023-06-04T17:00:00+02:00", - "2023-06-04T17:20:00+02:00", - "2023-06-04T17:40:00+02:00", - "2023-06-04T18:00:00+02:00", - "2023-06-04T18:20:00+02:00", - "2023-06-04T18:40:00+02:00", - "2023-06-04T19:00:00+02:00", - "2023-06-04T19:20:00+02:00", - "2023-06-04T19:40:00+02:00", - "2023-06-04T20:00:00+02:00", - "2023-06-04T20:20:00+02:00", - "2023-06-04T20:40:00+02:00", - "2023-06-04T21:00:00+02:00", - "2023-06-04T21:20:00+02:00", - "2023-06-04T21:40:00+02:00", - "2023-06-04T22:00:00+02:00", - "2023-06-04T22:20:00+02:00", - "2023-06-04T22:40:00+02:00", - "2023-06-04T23:00:00+02:00", - "2023-06-04T23:20:00+02:00", - "2023-06-04T23:40:00+02:00", - "2023-06-05T00:00:00+02:00", - "2023-06-05T00:20:00+02:00", - "2023-06-05T00:40:00+02:00", - "2023-06-05T01:00:00+02:00", - "2023-06-05T01:20:00+02:00", - "2023-06-05T01:40:00+02:00", - "2023-06-05T02:00:00+02:00", - "2023-06-05T02:20:00+02:00", - "2023-06-05T02:40:00+02:00", - "2023-06-05T03:00:00+02:00", - "2023-06-05T03:20:00+02:00", - "2023-06-05T03:40:00+02:00", - "2023-06-05T04:00:00+02:00", - "2023-06-05T04:20:00+02:00", - "2023-06-05T04:40:00+02:00", - "2023-06-05T05:00:00+02:00", - "2023-06-05T05:20:00+02:00", - "2023-06-05T05:40:00+02:00", - "2023-06-05T06:00:00+02:00", - "2023-06-05T06:20:00+02:00", - "2023-06-05T06:40:00+02:00", - "2023-06-05T07:00:00+02:00", - "2023-06-05T07:20:00+02:00", - "2023-06-05T07:40:00+02:00", - "2023-06-05T08:00:00+02:00", - "2023-06-05T08:20:00+02:00", - "2023-06-05T08:40:00+02:00", - "2023-06-05T09:00:00+02:00", - "2023-06-05T09:20:00+02:00", - "2023-06-05T09:40:00+02:00", - "2023-06-05T10:00:00+02:00", - "2023-06-05T10:20:00+02:00", - "2023-06-05T10:40:00+02:00", - "2023-06-05T11:00:00+02:00", - "2023-06-05T11:20:00+02:00", - "2023-06-05T11:40:00+02:00", - "2023-06-05T12:00:00+02:00", - "2023-06-05T12:20:00+02:00", - "2023-06-05T12:40:00+02:00", - "2023-06-05T13:00:00+02:00", - "2023-06-05T13:20:00+02:00", - "2023-06-05T13:40:00+02:00", - "2023-06-05T14:00:00+02:00", - "2023-06-05T14:20:00+02:00", - "2023-06-05T14:40:00+02:00", - "2023-06-05T15:00:00+02:00", - "2023-06-05T15:20:00+02:00", - "2023-06-05T15:40:00+02:00", - "2023-06-05T16:00:00+02:00", - "2023-06-05T16:20:00+02:00", - "2023-06-05T16:40:00+02:00", - "2023-06-05T17:00:00+02:00", - "2023-06-05T17:20:00+02:00", - "2023-06-05T17:40:00+02:00", - "2023-06-05T18:00:00+02:00", - "2023-06-05T18:20:00+02:00", - "2023-06-05T18:40:00+02:00", - "2023-06-05T19:00:00+02:00", - "2023-06-05T19:20:00+02:00", - "2023-06-05T19:40:00+02:00", - "2023-06-05T20:00:00+02:00", - "2023-06-05T20:20:00+02:00", - "2023-06-05T20:40:00+02:00", - "2023-06-05T21:00:00+02:00", - "2023-06-05T21:20:00+02:00", - "2023-06-05T21:40:00+02:00", - "2023-06-05T22:00:00+02:00", - "2023-06-05T22:20:00+02:00", - "2023-06-05T22:40:00+02:00", - "2023-06-05T23:00:00+02:00", - "2023-06-05T23:20:00+02:00", - "2023-06-05T23:40:00+02:00", - "2023-06-06T00:00:00+02:00", - "2023-06-06T00:20:00+02:00", - "2023-06-06T00:40:00+02:00", - "2023-06-06T01:00:00+02:00", - "2023-06-06T01:20:00+02:00", - "2023-06-06T01:40:00+02:00", - "2023-06-06T02:00:00+02:00", - "2023-06-06T02:20:00+02:00", - "2023-06-06T02:40:00+02:00", - "2023-06-06T03:00:00+02:00", - "2023-06-06T03:20:00+02:00", - "2023-06-06T03:40:00+02:00", - "2023-06-06T04:00:00+02:00", - "2023-06-06T04:20:00+02:00", - "2023-06-06T04:40:00+02:00", - "2023-06-06T05:00:00+02:00", - "2023-06-06T05:20:00+02:00", - "2023-06-06T05:40:00+02:00", - "2023-06-06T06:00:00+02:00", - "2023-06-06T06:20:00+02:00", - "2023-06-06T06:40:00+02:00", - "2023-06-06T07:00:00+02:00", - "2023-06-06T07:20:00+02:00", - "2023-06-06T07:40:00+02:00", - "2023-06-06T08:00:00+02:00", - "2023-06-06T08:20:00+02:00", - "2023-06-06T08:40:00+02:00", - "2023-06-06T09:00:00+02:00", - "2023-06-06T09:20:00+02:00", - "2023-06-06T09:40:00+02:00", - "2023-06-06T10:00:00+02:00", - "2023-06-06T10:20:00+02:00", - "2023-06-06T10:40:00+02:00", - "2023-06-06T11:00:00+02:00", - "2023-06-06T11:20:00+02:00", - "2023-06-06T11:40:00+02:00", - "2023-06-06T12:00:00+02:00", - "2023-06-06T12:20:00+02:00", - "2023-06-06T12:40:00+02:00", - "2023-06-06T13:00:00+02:00", - "2023-06-06T13:20:00+02:00", - "2023-06-06T13:40:00+02:00", - "2023-06-06T14:00:00+02:00", - "2023-06-06T14:20:00+02:00", - "2023-06-06T14:40:00+02:00", - "2023-06-06T15:00:00+02:00", - "2023-06-06T15:20:00+02:00", - "2023-06-06T15:40:00+02:00", - "2023-06-06T16:00:00+02:00", - "2023-06-06T16:20:00+02:00", - "2023-06-06T16:40:00+02:00", - "2023-06-06T17:00:00+02:00", - "2023-06-06T17:20:00+02:00", - "2023-06-06T17:40:00+02:00", - "2023-06-06T18:00:00+02:00", - "2023-06-06T18:20:00+02:00", - "2023-06-06T18:40:00+02:00", - "2023-06-06T19:00:00+02:00", - "2023-06-06T19:20:00+02:00", - "2023-06-06T19:40:00+02:00", - "2023-06-06T20:00:00+02:00", - "2023-06-06T20:20:00+02:00", - "2023-06-06T20:40:00+02:00", - "2023-06-06T21:00:00+02:00", - "2023-06-06T21:20:00+02:00", - "2023-06-06T21:40:00+02:00", - "2023-06-06T22:00:00+02:00", - "2023-06-06T22:20:00+02:00", - "2023-06-06T22:40:00+02:00", - "2023-06-06T23:00:00+02:00", - "2023-06-06T23:20:00+02:00", - "2023-06-06T23:40:00+02:00", - "2023-06-07T00:00:00+02:00", - "2023-06-07T00:20:00+02:00", - "2023-06-07T00:40:00+02:00", - "2023-06-07T01:00:00+02:00", - "2023-06-07T01:20:00+02:00", - "2023-06-07T01:40:00+02:00", - "2023-06-07T02:00:00+02:00", - "2023-06-07T02:20:00+02:00", - "2023-06-07T02:40:00+02:00", - "2023-06-07T03:00:00+02:00", - "2023-06-07T03:20:00+02:00", - "2023-06-07T03:40:00+02:00", - "2023-06-07T04:00:00+02:00", - "2023-06-07T04:20:00+02:00", - "2023-06-07T04:40:00+02:00", - "2023-06-07T05:00:00+02:00", - "2023-06-07T05:20:00+02:00", - "2023-06-07T05:40:00+02:00", - "2023-06-07T06:00:00+02:00", - "2023-06-07T06:20:00+02:00", - "2023-06-07T06:40:00+02:00", - "2023-06-07T07:00:00+02:00", - "2023-06-07T07:20:00+02:00", - "2023-06-07T07:40:00+02:00", - "2023-06-07T08:00:00+02:00", - "2023-06-07T08:20:00+02:00", - "2023-06-07T08:40:00+02:00", - "2023-06-07T09:00:00+02:00", - "2023-06-07T09:20:00+02:00", - "2023-06-07T09:40:00+02:00", - "2023-06-07T10:00:00+02:00", - "2023-06-07T10:20:00+02:00", - "2023-06-07T10:40:00+02:00", - "2023-06-07T11:00:00+02:00", - "2023-06-07T11:20:00+02:00", - "2023-06-07T11:40:00+02:00", - "2023-06-07T12:00:00+02:00", - "2023-06-07T12:20:00+02:00", - "2023-06-07T12:40:00+02:00", - "2023-06-07T13:00:00+02:00", - "2023-06-07T13:20:00+02:00", - "2023-06-07T13:40:00+02:00", - "2023-06-07T14:00:00+02:00", - "2023-06-07T14:20:00+02:00", - "2023-06-07T14:40:00+02:00", - "2023-06-07T15:00:00+02:00", - "2023-06-07T15:20:00+02:00", - "2023-06-07T15:40:00+02:00", - "2023-06-07T16:00:00+02:00", - "2023-06-07T16:20:00+02:00", - "2023-06-07T16:40:00+02:00", - "2023-06-07T17:00:00+02:00", - "2023-06-07T17:20:00+02:00", - "2023-06-07T17:40:00+02:00", - "2023-06-07T18:00:00+02:00", - "2023-06-07T18:20:00+02:00", - "2023-06-07T18:40:00+02:00", - "2023-06-07T19:00:00+02:00", - "2023-06-07T19:20:00+02:00", - "2023-06-07T19:40:00+02:00", - "2023-06-07T20:00:00+02:00", - "2023-06-07T20:20:00+02:00", - "2023-06-07T20:40:00+02:00", - "2023-06-07T21:00:00+02:00", - "2023-06-07T21:20:00+02:00", - "2023-06-07T21:40:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/zoomPreview.json b/centreon/packages/ui/src/Graph/LineChart/mockedData/zoomPreview.json deleted file mode 100644 index f18cc61891..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/zoomPreview.json +++ /dev/null @@ -1,742 +0,0 @@ -{ - "global": { - "title": "oracle-shared-spool-ratio graph on srv-oracle-users", - "start": "2023-06-01T23:54:23+02:00", - "end": "2023-06-02T11:29:24+02:00", - "vertical-label": "Value", - "base": 1000, - "width": 550, - "height": 140, - "scaled": 0, - "multiple_services": false - }, - "metrics": [ - { - "index_id": 4811, - "metric_id": 11758, - "metric": "connTime", - "metric_legend": "connTime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#ff99cc" - }, - "legend": "connTime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 0.56718666667, - 0.30173333333, - 0.25002666667, - 0.49318666667, - 0.38298666667, - 0.73857333333, - 0.12757333333, - 0.87394666667, - 0.25628, - 0.38088, - 0.70997333333, - 0.38341333333, - 0.22105333333, - 0.39570666667, - 0.26684, - 0.81090666667, - 0.56462666667, - 0.61432, - 0.037693333333, - 0.73582666667, - 0.76090666667, - 0.24122666667, - 0.24229333333, - 0.078333333333, - 0.28768, - 0.27822666667, - 0.20410666667, - 0.27005333333, - 0.5438, - 0.63, - 0.16918666667, - 0.33612, - 0.18606666667, - 0.55945333333, - 0.24682666667, - 0.14942666667, - 0.063586666667, - 0.026813333333, - 0.1102, - 0.80133333333, - 0.49825333333, - 0.41462666667, - 0.066413333333, - 0.77688, - 0.53873333333, - 0.95846666667, - 0.202, - 0.34449333333, - 0.53013333333, - 0.10358666667, - 0.91396, - 0.25573333333, - 0.17638, - 0.44002, - 0.50977, - 0.098876666667, - 0.16456, - 0.75581, - 0.67874333333, - 0.10694333333, - 0.88898333333, - 0.54368666667, - 0.96525333333, - 0.72881, - 0.30359333333, - 0.22523, - 0.51537666667, - 0.48394666667, - 0.96304333333, - 0.86087666667, - 0.15870666667, - 0.42924333333, - 0.88948, - 0.071716666667, - 0.14552, - 0.02565, - 0.27741666667, - 0.88069666667, - 0.73016333333, - 0.15583, - 0.82667, - 0.0766, - 0.70442666667, - 0.51388333333, - 0.12266666667, - 0.53865, - 0.45085666667, - 0.60248, - 0.72897333333, - 0.30018, - 0.58435666667, - 0.25868333333, - 0.03707, - 0.53251333333, - 0.11963333333, - 0.10149, - 0.61234333333, - 0.11096, - 0.28370333333, - 0.025263333333, - 0.83724666667, - 0.92001666667, - 0.22016, - 0.77135666667, - 0.85794, - 0.83458666667, - 0.6349, - 0.60224666667, - 0.26517333333, - 0.69308333333, - 0.94262666667, - 0.94751, - 0.60268333333, - 0.084863333333, - 0.77193333333, - 0.49709666667, - 0.41857, - 0.57631, - 0.55958666667, - 0.22972, - 0.34301, - 0.91417, - 0.15937333333, - 0.94685, - 0.80927666667, - 0.5433, - 0.68836666667, - 0.045213333333, - 0.20221333333, - 0.25928, - 0.028996666667, - 0.55647333333, - 0.53334333333, - 0.070596666667, - 0.37599666667, - 0.55636666667, - 0.92541, - 0.54608333333, - 0.40597, - 0.78954 - ], - "prints": [ - [ - "Last:0.79" - ], - [ - "Min:0.03" - ], - [ - "Max:0.97" - ], - [ - "Average:0.45" - ] - ], - "last_value": 0.79, - "minimum_value": 0.03, - "maximum_value": 0.97, - "average_value": 0.45 - }, - { - "index_id": 4811, - "metric_id": 11757, - "metric": "querytime", - "metric_legend": "querytime", - "unit": "s", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "ds_min": "1", - "ds_max": "1", - "ds_minmax_int": "0", - "ds_last": "1", - "ds_average": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_color_line_mode": "1", - "ds_color_line": "#6666ff" - }, - "legend": "querytime", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 0, - "data": [ - 0.21217333333, - 0.87482666667, - 0.37050666667, - 0.22261333333, - 0.27658666667, - 0.89249333333, - 0.42810666667, - 0.17090666667, - 0.19776, - 0.66197333333, - 0.74858666667, - 0.16696, - 0.069626666667, - 0.47496, - 0.2282, - 0.0994, - 0.64774666667, - 0.66953333333, - 0.77124, - 0.3936, - 0.15710666667, - 0.93925333333, - 0.20773333333, - 0.071226666667, - 0.41626666667, - 0.21069333333, - 0.6382, - 0.44053333333, - 0.60597333333, - 0.21082666667, - 0.47862666667, - 0.29146666667, - 0.209, - 0.65845333333, - 0.04784, - 0.76081333333, - 0.65816, - 0.73236, - 0.28733333333, - 0.59522666667, - 0.62157333333, - 0.31906666667, - 0.18461333333, - 0.26982666667, - 0.040226666667, - 0.59405333333, - 0.90810666667, - 0.78957333333, - 0.80093333333, - 0.86164, - 0.1834, - 0.018146666667, - 0.72887666667, - 0.08997, - 0.00938, - 0.26547333333, - 0.70833, - 0.39817333333, - 0.76854, - 0.04771, - 0.083183333333, - 0.62004, - 0.63879333333, - 0.82478, - 0.11057666667, - 0.084923333333, - 0.49069, - 0.54518666667, - 0.23475666667, - 0.20845333333, - 0.23913, - 0.13912, - 0.51599333333, - 0.081483333333, - 0.69169333333, - 0.74981, - 0.28310666667, - 0.27764, - 0.67425666667, - 0.26406666667, - 0.16725, - 0.39128666667, - 0.76818333333, - 0.89565333333, - 0.85860666667, - 0.89279, - 0.55445666667, - 0.45664666667, - 0.85574666667, - 0.05364, - 0.59358333333, - 0.29600333333, - 0.050543333333, - 0.33603666667, - 0.05402, - 0.63879, - 0.65424666667, - 0.48697333333, - 0.57888, - 0.87366, - 0.76553666667, - 0.79290333333, - 0.19598333333, - 0.070383333333, - 0.51874333333, - 0.077163333333, - 0.81027, - 0.29754666667, - 0.74227, - 0.14934333333, - 0.27802666667, - 0.43610333333, - 0.76007333333, - 0.96106333333, - 0.30789333333, - 0.44346, - 0.66247666667, - 0.20710666667, - 0.91763, - 0.39694333333, - 0.43186333333, - 0.18601666667, - 0.22477, - 0.93644333333, - 0.53752, - 0.71947666667, - 0.15373666667, - 0.28785666667, - 0.09141, - 0.27427, - 0.76049666667, - 0.46826666667, - 0.54427666667, - 0.59150666667, - 0.72795333333, - 0.67562666667, - 0.97103666667, - 0.065476666667, - 0.35148666667, - 0.81253666667 - ], - "prints": [ - [ - "Last:0.81" - ], - [ - "Min:0.01" - ], - [ - "Max:0.97" - ], - [ - "Average:0.45" - ] - ], - "last_value": 0.81, - "minimum_value": 0.01, - "maximum_value": 0.97, - "average_value": 0.45 - }, - { - "index_id": 4811, - "metric_id": 11756, - "metric": "used", - "metric_legend": "used", - "unit": "%", - "hidden": 0, - "min": null, - "max": null, - "virtual": 0, - "ds_data": { - "compo_id": 8, - "host_id": null, - "service_id": null, - "name": "Used", - "ds_order": 1, - "ds_hidecurve": null, - "ds_name": "used", - "ds_color_line": "#2B28D7", - "ds_color_line_mode": "0", - "ds_color_area": "#050AF9", - "ds_color_area_warn": null, - "ds_color_area_crit": null, - "ds_filled": "1", - "ds_max": null, - "ds_min": null, - "ds_minmax_int": "0", - "ds_average": "1", - "ds_last": "1", - "ds_total": "0", - "ds_tickness": 1, - "ds_transparency": "80", - "ds_invert": null, - "ds_legend": null, - "ds_jumpline": "0", - "ds_stack": null, - "default_tpl1": null, - "comment": null - }, - "legend": "used", - "stack": 0, - "warn": null, - "warn_low": null, - "crit": null, - "crit_low": null, - "ds_color_area_warn": "#ff9a13", - "ds_color_area_crit": "#e00b3d", - "ds_order": 1, - "data": [ - 91.596026667, - 90.088853333, - 89.076053333, - 90.53204, - 90.893426667, - 89.506986667, - 90.81108, - 90.729013333, - 92.19964, - 93.897066667, - 95.224346667, - 94.630386667, - 95.821773333, - 96.9134, - 97.077026667, - 97.41528, - 97.024093333, - 96.81924, - 97.259613333, - 98.342426667, - 99.564506667, - 98.086933333, - 96.482493333, - 95.24396, - 95.435546667, - 94.196613333, - 95.7448, - 96.646346667, - 95.380866667, - 94.330986667, - 93.289573333, - 94.292373333, - 93.915586667, - 93.01628, - 93.919346667, - 92.278466667, - 93.340773333, - 95.046573333, - 95.62464, - 94.912653333, - 93.616666667, - 93.305546667, - 91.418546667, - 90.48372, - 91.884453333, - 91.26452, - 93.03976, - 94.966226667, - 95.96928, - 95.0118, - 93.965733333, - 92.588453333, - 90.644313333, - 89.90091, - 88.758356667, - 88.809916667, - 87.401056667, - 89.171536667, - 88.56418, - 90.24447, - 92.145993333, - 90.846546667, - 89.730936667, - 91.40096, - 92.009683333, - 93.402173333, - 94.77448, - 94.395426667, - 95.178323333, - 94.597796667, - 93.762883333, - 94.440423333, - 96.117853333, - 98.09795, - 98.096856667, - 98.0051, - 97.2076, - 96.59683, - 95.66872, - 94.895236667, - 94.183176667, - 95.20991, - 93.487326667, - 95.11196, - 96.17254, - 95.36402, - 95.04598, - 95.81108, - 96.592856667, - 97.519016667, - 95.694766667, - 93.71986, - 92.31186, - 92.297203333, - 93.977303333, - 94.92134, - 94.19941, - 94.312423333, - 93.282446667, - 92.786066667, - 91.01389, - 92.46833, - 93.794936667, - 93.967106667, - 95.2182, - 95.01283, - 94.80073, - 93.796613333, - 93.586066667, - 95.26651, - 94.24732, - 94.895046667, - 94.41728, - 92.538953333, - 91.597866667, - 91.568753333, - 92.31712, - 92.778953333, - 91.32957, - 90.589156667, - 89.515163333, - 90.598206667, - 89.587826667, - 88.00329, - 89.227006667, - 89.304113333, - 89.37475, - 87.6527, - 87.395236667, - 85.901193333, - 87.65716, - 89.258466667, - 90.305483333, - 90.81863, - 92.16478, - 93.21469, - 93.78806, - 92.083266667, - 92.926106667, - 91.584036667 - ], - "prints": [ - [ - "Last:91.58" - ], - [ - "Average:93.26" - ] - ], - "last_value": 91.58, - "minimum_value": null, - "maximum_value": null, - "average_value": 93.26 - } - ], - "times": [ - "2023-06-01T23:55:00+02:00", - "2023-06-02T00:00:00+02:00", - "2023-06-02T00:05:00+02:00", - "2023-06-02T00:10:00+02:00", - "2023-06-02T00:15:00+02:00", - "2023-06-02T00:20:00+02:00", - "2023-06-02T00:25:00+02:00", - "2023-06-02T00:30:00+02:00", - "2023-06-02T00:35:00+02:00", - "2023-06-02T00:40:00+02:00", - "2023-06-02T00:45:00+02:00", - "2023-06-02T00:50:00+02:00", - "2023-06-02T00:55:00+02:00", - "2023-06-02T01:00:00+02:00", - "2023-06-02T01:05:00+02:00", - "2023-06-02T01:10:00+02:00", - "2023-06-02T01:15:00+02:00", - "2023-06-02T01:20:00+02:00", - "2023-06-02T01:25:00+02:00", - "2023-06-02T01:30:00+02:00", - "2023-06-02T01:35:00+02:00", - "2023-06-02T01:40:00+02:00", - "2023-06-02T01:45:00+02:00", - "2023-06-02T01:50:00+02:00", - "2023-06-02T01:55:00+02:00", - "2023-06-02T02:00:00+02:00", - "2023-06-02T02:05:00+02:00", - "2023-06-02T02:10:00+02:00", - "2023-06-02T02:15:00+02:00", - "2023-06-02T02:20:00+02:00", - "2023-06-02T02:25:00+02:00", - "2023-06-02T02:30:00+02:00", - "2023-06-02T02:35:00+02:00", - "2023-06-02T02:40:00+02:00", - "2023-06-02T02:45:00+02:00", - "2023-06-02T02:50:00+02:00", - "2023-06-02T02:55:00+02:00", - "2023-06-02T03:00:00+02:00", - "2023-06-02T03:05:00+02:00", - "2023-06-02T03:10:00+02:00", - "2023-06-02T03:15:00+02:00", - "2023-06-02T03:20:00+02:00", - "2023-06-02T03:25:00+02:00", - "2023-06-02T03:30:00+02:00", - "2023-06-02T03:35:00+02:00", - "2023-06-02T03:40:00+02:00", - "2023-06-02T03:45:00+02:00", - "2023-06-02T03:50:00+02:00", - "2023-06-02T03:55:00+02:00", - "2023-06-02T04:00:00+02:00", - "2023-06-02T04:05:00+02:00", - "2023-06-02T04:10:00+02:00", - "2023-06-02T04:15:00+02:00", - "2023-06-02T04:20:00+02:00", - "2023-06-02T04:25:00+02:00", - "2023-06-02T04:30:00+02:00", - "2023-06-02T04:35:00+02:00", - "2023-06-02T04:40:00+02:00", - "2023-06-02T04:45:00+02:00", - "2023-06-02T04:50:00+02:00", - "2023-06-02T04:55:00+02:00", - "2023-06-02T05:00:00+02:00", - "2023-06-02T05:05:00+02:00", - "2023-06-02T05:10:00+02:00", - "2023-06-02T05:15:00+02:00", - "2023-06-02T05:20:00+02:00", - "2023-06-02T05:25:00+02:00", - "2023-06-02T05:30:00+02:00", - "2023-06-02T05:35:00+02:00", - "2023-06-02T05:40:00+02:00", - "2023-06-02T05:45:00+02:00", - "2023-06-02T05:50:00+02:00", - "2023-06-02T05:55:00+02:00", - "2023-06-02T06:00:00+02:00", - "2023-06-02T06:05:00+02:00", - "2023-06-02T06:10:00+02:00", - "2023-06-02T06:15:00+02:00", - "2023-06-02T06:20:00+02:00", - "2023-06-02T06:25:00+02:00", - "2023-06-02T06:30:00+02:00", - "2023-06-02T06:35:00+02:00", - "2023-06-02T06:40:00+02:00", - "2023-06-02T06:45:00+02:00", - "2023-06-02T06:50:00+02:00", - "2023-06-02T06:55:00+02:00", - "2023-06-02T07:00:00+02:00", - "2023-06-02T07:05:00+02:00", - "2023-06-02T07:10:00+02:00", - "2023-06-02T07:15:00+02:00", - "2023-06-02T07:20:00+02:00", - "2023-06-02T07:25:00+02:00", - "2023-06-02T07:30:00+02:00", - "2023-06-02T07:35:00+02:00", - "2023-06-02T07:40:00+02:00", - "2023-06-02T07:45:00+02:00", - "2023-06-02T07:50:00+02:00", - "2023-06-02T07:55:00+02:00", - "2023-06-02T08:00:00+02:00", - "2023-06-02T08:05:00+02:00", - "2023-06-02T08:10:00+02:00", - "2023-06-02T08:15:00+02:00", - "2023-06-02T08:20:00+02:00", - "2023-06-02T08:25:00+02:00", - "2023-06-02T08:30:00+02:00", - "2023-06-02T08:35:00+02:00", - "2023-06-02T08:40:00+02:00", - "2023-06-02T08:45:00+02:00", - "2023-06-02T08:50:00+02:00", - "2023-06-02T08:55:00+02:00", - "2023-06-02T09:00:00+02:00", - "2023-06-02T09:05:00+02:00", - "2023-06-02T09:10:00+02:00", - "2023-06-02T09:15:00+02:00", - "2023-06-02T09:20:00+02:00", - "2023-06-02T09:25:00+02:00", - "2023-06-02T09:30:00+02:00", - "2023-06-02T09:35:00+02:00", - "2023-06-02T09:40:00+02:00", - "2023-06-02T09:45:00+02:00", - "2023-06-02T09:50:00+02:00", - "2023-06-02T09:55:00+02:00", - "2023-06-02T10:00:00+02:00", - "2023-06-02T10:05:00+02:00", - "2023-06-02T10:10:00+02:00", - "2023-06-02T10:15:00+02:00", - "2023-06-02T10:20:00+02:00", - "2023-06-02T10:25:00+02:00", - "2023-06-02T10:30:00+02:00", - "2023-06-02T10:35:00+02:00", - "2023-06-02T10:40:00+02:00", - "2023-06-02T10:45:00+02:00", - "2023-06-02T10:50:00+02:00", - "2023-06-02T10:55:00+02:00", - "2023-06-02T11:00:00+02:00", - "2023-06-02T11:05:00+02:00", - "2023-06-02T11:10:00+02:00", - "2023-06-02T11:15:00+02:00", - "2023-06-02T11:20:00+02:00", - "2023-06-02T11:25:00+02:00", - "2023-06-02T11:30:00+02:00" - ] -} \ No newline at end of file diff --git a/centreon/packages/ui/src/Graph/LineChart/models.ts b/centreon/packages/ui/src/Graph/LineChart/models.ts deleted file mode 100644 index 5ddd6ca4b3..0000000000 --- a/centreon/packages/ui/src/Graph/LineChart/models.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { ReactNode } from 'react'; - -import { ScaleLinear } from 'd3-scale'; - -import { Line, TimeValue } from '../common/timeSeries/models'; -import { LineChartData } from '../common/models'; - -import { - AxisX, - Axis as AxisYLeft, - AxisYRight -} from './BasicComponents/Axes/models'; -import { - AreaRegularLines, - AreaStackedLines -} from './BasicComponents/Lines/models'; -import { TimelineEvent } from './InteractiveComponents/Annotations/models'; -import { FactorsVariation } from './BasicComponents/Lines/Threshold/models'; - -export interface LineChartEndpoint { - baseUrl: string; - queryParameters: GraphInterval; -} -export interface Data { - baseAxis: number; - lines: Array; - timeSeries: Array; - title: string; -} - -export enum GraphIntervalProperty { - end = 'end', - start = 'start' -} - -export interface Interval { - end: Date; - start: Date; -} - -export interface GraphInterval { - end?: string; - start?: string; -} - -export interface ShapeLines { - areaRegularLines?: AreaRegularLines; - areaStackedLines?: AreaStackedLines; -} - -export interface LineChartAxis { - axisX?: AxisX; - axisYLeft?: AxisYLeft; - axisYRight?: AxisYRight; - gridLinesType?: 'horizontal' | 'vertical' | 'all'; - isCenteredZero?: boolean; - scale?: 'linear' | 'logarithimc'; - scaleLogarithmicBase?: number; - showBorder?: boolean; - showGridLines?: boolean; - yAxisTickLabelRotation?: number; -} - -export interface InteractedZone { - enable?: boolean; - getInterval?: (data: Interval) => void; -} - -export interface TooltipData { - data: Date; - hideTooltip: () => void; - tooltipOpen: boolean; -} -export interface Tooltip { - mode: 'all' | 'single' | 'hidden'; - renderComponent?: (args: TooltipData) => ReactNode; - sortOrder: 'name' | 'ascending' | 'descending'; -} - -export interface AnnotationEvent { - data?: Array; -} - -export interface LineChartHeader { - displayTitle?: boolean; - extraComponent?: ReactNode; -} - -export interface DisplayAnchor { - displayGuidingLines?: boolean; - displayTooltipsGuidingLines?: boolean; -} - -export interface LineStyle { - areaTransparency?: number; - curve?: 'linear' | 'step' | 'natural'; - dashLength?: number; - dashOffset?: number; - dotOffset?: number; - lineWidth?: number; - pathStyle?: 'solid' | 'dash' | 'dotted'; - showArea?: boolean; - showPoints?: boolean; -} - -export interface LineChartProps { - annotationEvent?: AnnotationEvent; - axis?: LineChartAxis; - displayAnchor?: DisplayAnchor; - header?: LineChartHeader; - height?: number | null; - legend?: LegendModel; - lineStyle?: LineStyle; - timeShiftZones?: InteractedZone; - tooltip?: Tooltip; - width: number; - zoomPreview?: InteractedZone; -} - -export interface Area { - display: boolean; -} - -export type PatternOrientation = - | 'diagonal' - | 'diagonalRightToLeft' - | 'horizontal' - | 'vertical'; - -export enum ThresholdType { - basic = 'basic', - pattern = 'pattern', - variation = 'variation' -} - -export interface PatternThreshold { - data: Array; - orientation?: Array; - type: ThresholdType.pattern; -} -export interface VariationThreshold { - displayCircles?: boolean; - factors: FactorsVariation; - getCountDisplayedCircles?: (value: number) => void; - type: ThresholdType.variation; -} - -export interface BasicThreshold { - type: ThresholdType.basic; -} - -export interface GlobalAreaLines { - areaRegularLines?: Area; - areaStackedLines?: Area; - areaThresholdLines?: Array< - PatternThreshold | VariationThreshold | BasicThreshold - >; -} -export interface LegendModel { - display?: boolean; - mode: 'grid' | 'list'; - placement: 'bottom' | 'left' | 'right'; - renderExtraComponent?: ReactNode; -} - -export interface GetDate { - positionX: number; - timeSeries: Array; - xScale: ScaleLinear; -} - -export interface GraphTooltipData { - date: string; - highlightedMetricId: number | null; - metrics: Array<{ - color: string; - id: number; - name: string; - unit: string; - value: number; - }>; -} diff --git a/centreon/packages/ui/src/Graph/PieChart/PieChart.cypress.spec.tsx b/centreon/packages/ui/src/Graph/PieChart/PieChart.cypress.spec.tsx index 9f99c7888f..c6548dc0c9 100644 --- a/centreon/packages/ui/src/Graph/PieChart/PieChart.cypress.spec.tsx +++ b/centreon/packages/ui/src/Graph/PieChart/PieChart.cypress.spec.tsx @@ -72,8 +72,6 @@ describe('Pie chart', () => { it('renders as a pie when variant is set to "pie"', () => { initialize({ variant: 'pie' }); cy.get('[data-variant="pie"]').should('exist'); - - cy.makeSnapshot(); }); it('displays tooltip with correct information on hover', () => { @@ -134,8 +132,6 @@ describe('Pie chart', () => { initialize({}); cy.findByTestId('Title').should('not.exist'); - - cy.makeSnapshot(); }); it('adjusts outer radius when chart dimensions are too small', () => { @@ -147,7 +143,7 @@ describe('Pie chart', () => { width: '120px' }); - cy.get('[data-variant="donut"]').should('have.css', 'width', '100px'); + cy.get('[data-variant="donut"]').should('have.css', 'width', '76px'); cy.makeSnapshot(); }); diff --git a/centreon/packages/ui/src/Graph/PieChart/PieChart.stories.tsx b/centreon/packages/ui/src/Graph/PieChart/PieChart.stories.tsx index 8732513f0c..e4870ea6a6 100644 --- a/centreon/packages/ui/src/Graph/PieChart/PieChart.stories.tsx +++ b/centreon/packages/ui/src/Graph/PieChart/PieChart.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react'; -import { ArcType } from './models'; import ResponsivePie from './ResponsivePie'; +import { ArcType } from './models'; const data = [ { color: '#88B922', label: 'Ok', value: 148 }, @@ -144,6 +144,10 @@ const TemplateForSmallDimensions = (args): JSX.Element => { return ; }; +const SmallTemplate = (args): JSX.Element => { + return ; +}; + export const PieWithSmallDimensions: Story = { args: { data, @@ -188,3 +192,13 @@ export const donutWithOneNoZeroValue: Story = { }, render: Template }; + +export const smallDisplay: Story = { + args: { + data, + displayLegend: false, + title: 'hosts', + variant: 'donut' + }, + render: SmallTemplate +}; diff --git a/centreon/packages/ui/src/Graph/PieChart/PieChart.styles.ts b/centreon/packages/ui/src/Graph/PieChart/PieChart.styles.ts index 91a902eee2..fe13408d9a 100644 --- a/centreon/packages/ui/src/Graph/PieChart/PieChart.styles.ts +++ b/centreon/packages/ui/src/Graph/PieChart/PieChart.styles.ts @@ -1,8 +1,8 @@ import { lt } from 'ramda'; import { makeStyles } from 'tss-react/mui'; -export const usePieStyles = makeStyles<{ svgSize: number }>()( - (theme, { svgSize }) => ({ +export const usePieStyles = makeStyles<{ reverse: boolean; svgSize: number }>()( + (theme, { reverse, svgSize }) => ({ container: { alignItems: 'center', display: 'flex', @@ -25,7 +25,7 @@ export const usePieStyles = makeStyles<{ svgSize: number }>()( svgWrapper: { alignItems: 'center', display: 'flex', - flexDirection: 'column', + flexDirection: reverse ? 'column-reverse' : 'column', gap: theme.spacing(1), justifyContent: 'center' }, diff --git a/centreon/packages/ui/src/Graph/PieChart/ResponsivePie.tsx b/centreon/packages/ui/src/Graph/PieChart/ResponsivePie.tsx index 22bfcef746..1af40a5933 100644 --- a/centreon/packages/ui/src/Graph/PieChart/ResponsivePie.tsx +++ b/centreon/packages/ui/src/Graph/PieChart/ResponsivePie.tsx @@ -1,7 +1,7 @@ import { useRef } from 'react'; -import { Pie } from '@visx/shape'; import { Group } from '@visx/group'; +import { Pie } from '@visx/shape'; import { Text } from '@visx/text'; import numeral from 'numeral'; import { always, equals, gt, ifElse, lt } from 'ramda'; @@ -14,11 +14,11 @@ import { Legend as LegendComponent } from '../Legend'; import { LegendProps } from '../Legend/models'; import { getValueByUnit } from '../common/utils'; -import { PieProps } from './models'; import { usePieStyles } from './PieChart.styles'; +import { PieProps } from './models'; import { useResponsivePie } from './useResponsivePie'; -const DefaultLengd = ({ scale, direction }: LegendProps): JSX.Element => ( +const DefaultLegend = ({ scale, direction }: LegendProps): JSX.Element => ( ); @@ -42,18 +42,25 @@ const getTooltipPlacement = ({ radianX, radianY }): Placement => { const ResponsivePie = ({ title, + titlePosition, + displayTitle = true, variant = 'pie', width, height, data, unit = 'number', - Legend = DefaultLengd, + Legend = DefaultLegend, displayLegend = true, + displayTotal = true, innerRadius: defaultInnerRadius = 40, + innerRadiusNoLimit = false, onArcClick, + padAngle = 0, displayValues, TooltipContent, - legendDirection = 'column' + legendDirection = 'column', + tooltipProps = {}, + opacity = 1 }: PieProps & { height: number; width: number }): JSX.Element => { const { t } = useTranslation(); const theme = useTheme(); @@ -66,7 +73,6 @@ const ResponsivePie = ({ legendScale, svgContainerSize, svgSize, - svgWrapperWidth, total, innerRadius, isContainsExactlyOneNonZeroValue @@ -74,34 +80,46 @@ const ResponsivePie = ({ data, defaultInnerRadius, height, + innerRadiusNoLimit, legendRef, titleRef, unit, width }); - const { classes } = usePieStyles({ svgSize }); + const isTooSmallForLegend = lt(width, 170); + + const isSmall = lt(width, 130); + const mustDisplayLegend = isTooSmallForLegend ? false : displayLegend; + + const { classes } = usePieStyles({ + reverse: equals(titlePosition, 'bottom'), + svgSize + }); return (
- {equals(variant, 'pie') && title && ( -
- {`${numeral(total).format('0a').toUpperCase()} `} {t(title)} -
- )} + {(equals(variant, 'pie') || + isSmall || + (equals(variant, 'donut') && equals(titlePosition, 'bottom'))) && + title && + displayTitle && ( +
+ {`${displayTotal ? numeral(total).format('0a').toUpperCase() : ''} `} + {t(title)} +
+ )}
- + { - return equals(variant, 'pie') ? 0 : half - innerRadius; + const iRadius = innerRadiusNoLimit + ? innerRadius + : half - innerRadius; + + return equals(variant, 'pie') ? 0 : iRadius; }} outerRadius={half} + padAngle={padAngle} pieValue={(items) => items.value} > {(pie) => { @@ -157,6 +184,7 @@ const ResponsivePie = ({ title={title} total={total} value={arc.data.value} + {...tooltipProps} /> ) } @@ -166,7 +194,11 @@ const ResponsivePie = ({ radianY: Math.sin(midAngle) })} > - + undefined} + > - {equals(variant, 'donut') && title && ( - <> - - {numeral(total).format('0a').toUpperCase()} - - - {t(title)} - - - )} + {equals(variant, 'donut') && + !isSmall && + title && + displayTitle && + !equals(titlePosition, 'bottom') && ( + <> + + {numeral(total).format('0a').toUpperCase()} + + + {t(title)} + + + )}
- {displayLegend && ( + {mustDisplayLegend && (
JSX.Element | boolean | null; data: Array; displayLegend?: boolean; + displayTitle?: boolean; + displayTotal?: boolean; displayValues?: boolean; innerRadius?: number; + innerRadiusNoLimit?: boolean; legendDirection?: 'row' | 'column'; - onArcClick?: (ardata) => void; + onArcClick?: (arcData) => void; + opacity: number; + padAngle?: number; title?: string; + titlePosition?: 'default' | 'bottom'; + tooltipProps?: object; unit?: 'percentage' | 'number'; variant?: 'pie' | 'donut'; } diff --git a/centreon/packages/ui/src/Graph/PieChart/useResponsivePie.ts b/centreon/packages/ui/src/Graph/PieChart/useResponsivePie.ts index 0c45bdcebb..63d6a3f37f 100644 --- a/centreon/packages/ui/src/Graph/PieChart/useResponsivePie.ts +++ b/centreon/packages/ui/src/Graph/PieChart/useResponsivePie.ts @@ -9,6 +9,7 @@ interface ResponsivePieProps { data: Array; defaultInnerRadius: number; height: number; + innerRadiusNoLimit: boolean; legendRef; titleRef; unit: 'percentage' | 'number'; @@ -22,7 +23,6 @@ interface ResponsivePieState { legendScale: LegendScale; svgContainerSize: number; svgSize: number; - svgWrapperWidth: number; total: number; } export const useResponsivePie = ({ @@ -32,7 +32,8 @@ export const useResponsivePie = ({ width, data, unit, - defaultInnerRadius + defaultInnerRadius, + innerRadiusNoLimit }: ResponsivePieProps): ResponsivePieState => { const heightOfTitle = titleRef.current?.offsetHeight || 0; const widthOfLegend = legendRef.current?.offsetWidth || 0; @@ -44,7 +45,6 @@ export const useResponsivePie = ({ height - heightOfTitle - verticalGap, width - widthOfLegend - horizontalGap ); - const svgWrapperWidth = svgContainerSize; const outerRadius = Math.min(32, svgContainerSize / 6); @@ -54,7 +54,11 @@ export const useResponsivePie = ({ const total = Math.floor(data.reduce((acc, { value }) => acc + value, 0)); - const innerRadius = Math.min(defaultInnerRadius, svgSize / 5); + let innerRadius = Math.min(defaultInnerRadius, svgSize / 5); + + if (innerRadiusNoLimit) { + innerRadius = half * defaultInnerRadius * 0.01; + } const legendScale = { domain: data.map(({ value }) => getValueByUnit({ total, unit, value })), @@ -75,7 +79,6 @@ export const useResponsivePie = ({ legendScale, svgContainerSize, svgSize, - svgWrapperWidth, total }; }; diff --git a/centreon/packages/ui/src/Graph/SingleBar/ResponsiveSingleBar.tsx b/centreon/packages/ui/src/Graph/SingleBar/ResponsiveSingleBar.tsx index 667b1db811..db10aa0601 100644 --- a/centreon/packages/ui/src/Graph/SingleBar/ResponsiveSingleBar.tsx +++ b/centreon/packages/ui/src/Graph/SingleBar/ResponsiveSingleBar.tsx @@ -1,35 +1,32 @@ import { useMemo, useRef } from 'react'; -import { Group, Tooltip } from '@visx/visx'; +import { animated, useSpring } from '@react-spring/web'; import { scaleLinear } from '@visx/scale'; -import { equals, flatten, head, pluck } from 'ramda'; import { Bar } from '@visx/shape'; -import { useSpring, animated } from '@react-spring/web'; +import { Group, Tooltip } from '@visx/visx'; +import { equals, flatten, head, lt, pluck } from 'ramda'; -import { alpha, Box, Fade, useTheme } from '@mui/material'; +import { Box, alpha, useTheme } from '@mui/material'; +import { Tooltip as MuiTooltip } from '../../components/Tooltip'; +import { margins } from '../common/margins'; import { formatMetricValueWithUnit, getMetricWithLatestData } from '../common/timeSeries'; import { Metric } from '../common/timeSeries/models'; +import { useTooltipStyles } from '../common/useTooltipStyles'; import { getColorFromDataAndTresholds } from '../common/utils'; -import { margins } from '../common/margins'; -import { SingleBarProps } from './models'; -import Thresholds, { groupMargin } from './Thresholds'; import { barHeights } from './ThresholdLine'; +import Thresholds, { groupMargin } from './Thresholds'; +import { SingleBarProps } from './models'; interface Props extends SingleBarProps { height: number; width: number; } -const baseStyles = { - ...Tooltip.defaultStyles, - textAlign: 'center' -}; - const ResponsiveSingleBar = ({ data, thresholds, @@ -40,8 +37,11 @@ const ResponsiveSingleBar = ({ size = 'medium', showLabels = true }: Props): JSX.Element => { + const { classes } = useTooltipStyles(); const theme = useTheme(); + const isSmallHeight = lt(height, 150); + const metric = getMetricWithLatestData(data) as Metric; const latestMetricData = head(metric.data) as number; const thresholdValues = thresholds.enabled @@ -57,14 +57,8 @@ const ResponsiveSingleBar = ({ head(metric.data) as number ); - const { - showTooltip, - hideTooltip, - tooltipOpen, - tooltipLeft, - tooltipTop, - tooltipData - } = Tooltip.useTooltip(); + const { showTooltip, hideTooltip, tooltipOpen, tooltipData } = + Tooltip.useTooltip(); const svgRef = useRef(null); const barColor = useMemo( @@ -78,13 +72,11 @@ const ResponsiveSingleBar = ({ [latestMetricData, thresholds, theme] ); - const isSmall = equals(size, 'small'); + const isSmall = equals(size, 'small') || isSmallHeight; + + const textStyle = isSmall ? theme.typography.h6 : theme.typography.h4; - const textStyle = isSmall - ? { - ...theme.typography.h6 - } - : theme.typography.h3; + const textHeight = isSmall ? 46 : 27; const text = showLabels && ( height + ? height - textHeight - 2 * margins.top + : barHeight; + return (
- - - {text} - - - {thresholds.enabled && ( - - )} - - - - - - {tooltipData} - - + + + {text} + + + {thresholds.enabled && ( + + )} + + + +
); }; diff --git a/centreon/packages/ui/src/Graph/SingleBar/SingleBar.cypress.spec.tsx b/centreon/packages/ui/src/Graph/SingleBar/SingleBar.cypress.spec.tsx index f3a8e4e2dd..42aa01c65d 100644 --- a/centreon/packages/ui/src/Graph/SingleBar/SingleBar.cypress.spec.tsx +++ b/centreon/packages/ui/src/Graph/SingleBar/SingleBar.cypress.spec.tsx @@ -1,10 +1,10 @@ -import dataLastWeek from '../LineChart/mockedData/lastWeek.json'; import { criticalThresholds, rangedThresholds, successThresholds, warningThresholds } from '../common/testUtils'; +import dataLastWeek from '../mockedData/lastWeek.json'; import SingleBar from './SingleBar'; import { SingleBarProps } from './models'; diff --git a/centreon/packages/ui/src/Graph/SingleBar/SingleBar.stories.tsx b/centreon/packages/ui/src/Graph/SingleBar/SingleBar.stories.tsx index 9b2f30683a..f594be3210 100644 --- a/centreon/packages/ui/src/Graph/SingleBar/SingleBar.stories.tsx +++ b/centreon/packages/ui/src/Graph/SingleBar/SingleBar.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import dataLastWeek from '../LineChart/mockedData/lastWeek.json'; +import dataLastWeek from '../mockedData/lastWeek.json'; import { SingleBar } from '.'; @@ -17,6 +17,12 @@ const Template = (props): JSX.Element => (
); +const SmallTemplate = (props): JSX.Element => ( +
+ +
+); + export const success: Story = { args: { data: dataLastWeek, @@ -202,3 +208,25 @@ export const Small: Story = { }, render: Template }; + +export const smallDisplay: Story = { + args: { + data: dataLastWeek, + thresholds: { + critical: [ + { + label: 'Critical', + value: 0.6 + } + ], + enabled: true, + warning: [ + { + label: 'Warning', + value: 0.5 + } + ] + } + }, + render: SmallTemplate +}; diff --git a/centreon/packages/ui/src/Graph/SingleBar/SingleBar.tsx b/centreon/packages/ui/src/Graph/SingleBar/SingleBar.tsx index 4fe5fc9270..b5d0637aab 100644 --- a/centreon/packages/ui/src/Graph/SingleBar/SingleBar.tsx +++ b/centreon/packages/ui/src/Graph/SingleBar/SingleBar.tsx @@ -1,7 +1,7 @@ import { ParentSize } from '../..'; -import { SingleBarProps } from './models'; import ResponsiveSingleBar from './ResponsiveSingleBar'; +import { SingleBarProps } from './models'; const SingleBar = ({ data, ...props }: SingleBarProps): JSX.Element | null => { if (!data) { diff --git a/centreon/packages/ui/src/Graph/SingleBar/ThresholdLine.tsx b/centreon/packages/ui/src/Graph/SingleBar/ThresholdLine.tsx index 50a1f684ea..a3c7f3b901 100644 --- a/centreon/packages/ui/src/Graph/SingleBar/ThresholdLine.tsx +++ b/centreon/packages/ui/src/Graph/SingleBar/ThresholdLine.tsx @@ -18,7 +18,9 @@ const lineMargins = { }; interface Props { + barHeight: number; hideTooltip: () => void; + isSmall: boolean; label: string; showTooltip: (args) => void; size: 'small' | 'medium'; @@ -34,7 +36,9 @@ export const ThresholdLine = ({ thresholdType, showTooltip, hideTooltip, - size + size, + barHeight, + isSmall }: Props): JSX.Element => { const theme = useTheme(); @@ -42,17 +46,9 @@ export const ThresholdLine = ({ const lineMargin = lineMargins[size]; - const thresholdLineHeight = barHeights[size] + 2 * lineMargin; - - const isSmall = equals(size, 'small'); - - const bottom = barHeights[size] + margin * 2; - - const onMouseEnter = (left) => (): void => + const onMouseEnter = (): void => showTooltip({ - tooltipData: label, - tooltipLeft: left, - tooltipTop: bottom + tooltipData: label }); const lineColor = equals(thresholdType, 'warning') @@ -70,13 +66,13 @@ export const ThresholdLine = ({ x2={scaledValue} y1={ isSmall - ? groupMargin - lineMargin + ? groupMargin - lineMargin + 6 : groupMargin + lineMargin + margins.top } y2={ isSmall - ? thresholdLineHeight + groupMargin - lineMargin - : thresholdLineHeight + groupMargin + lineMargin + margins.top + ? barHeight + groupMargin - lineMargin + margins.top - 2 + : barHeight + groupMargin + lineMargin + 2 * margins.top } /> diff --git a/centreon/packages/ui/src/Graph/SingleBar/Thresholds.tsx b/centreon/packages/ui/src/Graph/SingleBar/Thresholds.tsx index 662ac13067..2f09e2af2c 100644 --- a/centreon/packages/ui/src/Graph/SingleBar/Thresholds.tsx +++ b/centreon/packages/ui/src/Graph/SingleBar/Thresholds.tsx @@ -5,7 +5,9 @@ import { ThresholdLine } from './ThresholdLine'; export const groupMargin = 25; interface Props { + barHeight: number; hideTooltip: () => void; + isSmall: boolean; showTooltip: (args) => void; size: 'small' | 'medium'; thresholds: ThresholdsModel; @@ -17,12 +19,16 @@ const Thresholds = ({ thresholds, showTooltip, hideTooltip, - size + size, + barHeight, + isSmall }: Props): JSX.Element => ( <> {thresholds.warning.map(({ value, label }) => ( ( diff --git a/centreon/packages/ui/src/Graph/Text/Text.stories.tsx b/centreon/packages/ui/src/Graph/Text/Text.stories.tsx index c8b4842464..8902d94d76 100644 --- a/centreon/packages/ui/src/Graph/Text/Text.stories.tsx +++ b/centreon/packages/ui/src/Graph/Text/Text.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import dataLastWeek from '../LineChart/mockedData/lastWeek.json'; +import dataLastWeek from '../mockedData/lastWeek.json'; import { Text } from '.'; @@ -17,6 +17,12 @@ const Template = (props): JSX.Element => (
); +const SmallTemplate = (props): JSX.Element => ( +
+ +
+); + export const success: Story = { args: { data: dataLastWeek, @@ -121,3 +127,29 @@ export const rawValue: Story = { }, render: Template }; + +export const smallDisplay: Story = { + args: { + data: dataLastWeek, + labels: { + critical: 'Critical', + warning: 'Warning' + }, + thresholds: { + critical: [ + { + label: 'Critical', + value: 1.5 + } + ], + enabled: true, + warning: [ + { + label: 'Warning', + value: 0.5 + } + ] + } + }, + render: SmallTemplate +}; diff --git a/centreon/packages/ui/src/Graph/Text/Text.styles.ts b/centreon/packages/ui/src/Graph/Text/Text.styles.ts index c7e539747b..a262239332 100644 --- a/centreon/packages/ui/src/Graph/Text/Text.styles.ts +++ b/centreon/packages/ui/src/Graph/Text/Text.styles.ts @@ -9,7 +9,6 @@ export const useTextStyles = makeStyles()((theme) => ({ display: 'flex', flexDirection: 'column', gap: theme.spacing(1), - height: '100%', justifyContent: 'center' }, threshold: { diff --git a/centreon/packages/ui/src/Graph/Text/Text.tsx b/centreon/packages/ui/src/Graph/Text/Text.tsx index 3ddb0ce1a5..0b3ac06f81 100644 --- a/centreon/packages/ui/src/Graph/Text/Text.tsx +++ b/centreon/packages/ui/src/Graph/Text/Text.tsx @@ -1,6 +1,6 @@ import { isNil } from 'ramda'; -import { Typography, useTheme } from '@mui/material'; +import { useTheme } from '@mui/material'; import FluidTypography from '../../Typography/FluidTypography'; import { LineChartData, Thresholds } from '../common/models'; @@ -64,15 +64,19 @@ export const Text = ({ return (
- - - {formatMetricValueWithUnit({ + - + }) || '' + } + variant="h2" + /> {thresholds.enabled && (
extends Pick, 'treeLink'> { links: Array>>; diff --git a/centreon/packages/ui/src/Graph/Tree/StandaloneTree.tsx b/centreon/packages/ui/src/Graph/Tree/StandaloneTree.tsx index 729494096a..740479e193 100644 --- a/centreon/packages/ui/src/Graph/Tree/StandaloneTree.tsx +++ b/centreon/packages/ui/src/Graph/Tree/StandaloneTree.tsx @@ -2,8 +2,8 @@ import { useState } from 'react'; import { ParentSize } from '../..'; -import { BaseProp, TreeProps } from './models'; import { Tree } from './Tree'; +import { BaseProp, TreeProps } from './models'; export const StandaloneTree = ({ tree, diff --git a/centreon/packages/ui/src/Graph/Tree/Tree.cypress.spec.tsx b/centreon/packages/ui/src/Graph/Tree/Tree.cypress.spec.tsx index a0233cd68c..79ce45ac39 100644 --- a/centreon/packages/ui/src/Graph/Tree/Tree.cypress.spec.tsx +++ b/centreon/packages/ui/src/Graph/Tree/Tree.cypress.spec.tsx @@ -1,12 +1,12 @@ import { equals } from 'ramda'; +import { ComplexContent, SimpleContent } from './stories/contents'; import { ComplexData, - complexData, SimpleData, + complexData, simpleData } from './stories/datas'; -import { ComplexContent, SimpleContent } from './stories/contents'; import { Node, StandaloneTree, TreeProps } from '.'; @@ -35,6 +35,8 @@ const initializeStandaloneTree = ({ treeLink, children = SimpleContent }: InitializeProps): void => { + cy.adjustViewport(); + cy.mount({ Component: (
diff --git a/centreon/packages/ui/src/Graph/Tree/Tree.stories.tsx b/centreon/packages/ui/src/Graph/Tree/Tree.stories.tsx index 18c86daa9e..fb373cf383 100644 --- a/centreon/packages/ui/src/Graph/Tree/Tree.stories.tsx +++ b/centreon/packages/ui/src/Graph/Tree/Tree.stories.tsx @@ -5,14 +5,14 @@ import { equals, has } from 'ramda'; import { Zoom } from '../../components'; +import { ComplexContent, SimpleContent } from './stories/contents'; import { ComplexData, + SimpleData, complexData, moreComplexData, - SimpleData, simpleData } from './stories/datas'; -import { ComplexContent, SimpleContent } from './stories/contents'; import { StandaloneTree, Tree, TreeProps } from '.'; diff --git a/centreon/packages/ui/src/Graph/Tree/Tree.tsx b/centreon/packages/ui/src/Graph/Tree/Tree.tsx index 115e4e9604..f7d2d4b813 100644 --- a/centreon/packages/ui/src/Graph/Tree/Tree.tsx +++ b/centreon/packages/ui/src/Graph/Tree/Tree.tsx @@ -1,16 +1,16 @@ import { useCallback, useMemo } from 'react'; import { Group } from '@visx/group'; -import { hierarchy, Tree as VisxTree } from '@visx/hierarchy'; +import { Tree as VisxTree, hierarchy } from '@visx/hierarchy'; import { isNil } from 'ramda'; import { useDeepCompare } from '../../utils'; +import DescendantNodes from './DescendantNodes'; +import Links from './Links'; import { nodeMargins } from './constants'; import { BaseProp, Node, TreeProps } from './models'; import { updateNodeFromTree } from './utils'; -import Links from './Links'; -import DescendantNodes from './DescendantNodes'; export const Tree = ({ containerHeight, diff --git a/centreon/packages/ui/src/Graph/Tree/stories/contents.tsx b/centreon/packages/ui/src/Graph/Tree/stories/contents.tsx index bcaaa6816b..f2a8265689 100644 --- a/centreon/packages/ui/src/Graph/Tree/stories/contents.tsx +++ b/centreon/packages/ui/src/Graph/Tree/stories/contents.tsx @@ -1,7 +1,7 @@ -import { always, cond, equals, has, T } from 'ramda'; +import { T, always, cond, equals, has } from 'ramda'; -import { Avatar, Paper, Typography, useTheme } from '@mui/material'; import SpaIcon from '@mui/icons-material/Spa'; +import { Avatar, Paper, Typography, useTheme } from '@mui/material'; import { ChildrenProps } from '..'; diff --git a/centreon/packages/ui/src/Graph/common/Axes/AxisStyles.ts b/centreon/packages/ui/src/Graph/common/Axes/AxisStyles.ts new file mode 100644 index 0000000000..1fa2f4d966 --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/Axes/AxisStyles.ts @@ -0,0 +1,11 @@ +import { makeStyles } from 'tss-react/mui'; + +export const useYAxisStyles = makeStyles()((theme) => ({ + axisInput: { + maxHeight: theme.spacing(3), + minHeight: theme.spacing(3) + }, + unitContainer: { + marginTop: '2px' + } +})); diff --git a/centreon/packages/ui/src/Graph/common/Axes/UnitLabel.tsx b/centreon/packages/ui/src/Graph/common/Axes/UnitLabel.tsx new file mode 100644 index 0000000000..d7eff32e79 --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/Axes/UnitLabel.tsx @@ -0,0 +1,51 @@ +import SelectField from '../../../InputField/Select'; +import { commonTickLabelProps } from '../utils'; + +import { useYAxisStyles } from './AxisStyles'; + +interface UnitLabelProps { + onUnitChange?: (newUnit: string) => void; + unit: string; + units: Array; + x: number; + y?: number; +} + +const UnitLabel = ({ + x, + y = 16, + unit, + onUnitChange, + units +}: UnitLabelProps): JSX.Element => { + const { classes } = useYAxisStyles(); + + return onUnitChange ? ( + +
+ ({ + id: unitOption, + name: unitOption + }))} + selectedOptionId={unit} + size="small" + onChange={(e) => onUnitChange(e.target.value)} + /> +
+
+ ) : ( + + {unit} + + ); +}; + +export default UnitLabel; diff --git a/centreon/packages/ui/src/Graph/common/Axes/index.tsx b/centreon/packages/ui/src/Graph/common/Axes/index.tsx new file mode 100644 index 0000000000..228c89359c --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/Axes/index.tsx @@ -0,0 +1,133 @@ +import { Axis } from '@visx/visx'; +import { ScaleLinear } from 'd3-scale'; +import { equals, isNil } from 'ramda'; + +import { useLocaleDateTimeFormat } from '@centreon/ui'; + +import { margin } from '../../Chart/common'; +import { getXAxisTickFormat } from '../../Chart/helpers'; +import { getUnits } from '../timeSeries'; + +import UnitLabel from './UnitLabel'; +import { Data } from './models'; +import useAxisY from './useAxisY'; + +interface Props { + allUnits: Array; + data: Data; + height: number; + leftScale: ScaleLinear; + orientation: 'horizontal' | 'vertical'; + rightScale: ScaleLinear; + width: number; + xScale: ScaleLinear; +} + +const Axes = ({ + height, + width, + data, + rightScale, + leftScale, + xScale, + orientation, + allUnits +}: Props): JSX.Element => { + const { format } = useLocaleDateTimeFormat(); + const { lines, showBorder, yAxisTickLabelRotation } = data; + const isHorizontal = equals(orientation, 'horizontal'); + + const { axisLeft, axisRight } = useAxisY({ + data, + graphHeight: height, + graphWidth: width, + isHorizontal + }); + + const [, secondUnit] = getUnits(lines); + + const xTickCount = Math.min(Math.ceil(width / 82), 12); + + const [start, end] = xScale.domain(); + + const tickFormat = + data?.axisX?.xAxisTickFormat ?? getXAxisTickFormat({ end, start }); + + const formatAxisTick = (tick): string => + format({ date: new Date(tick), formatString: tickFormat }); + + const displayAxisRight = !isNil(secondUnit); + + const AxisBottom = isHorizontal ? Axis.AxisBottom : Axis.AxisLeft; + const AxisLeft = isHorizontal ? Axis.AxisLeft : Axis.AxisTop; + const AxisRight = isHorizontal ? Axis.AxisRight : Axis.AxisBottom; + + return ( + + ({ + ...axisLeft.tickLabelProps(), + dx: isHorizontal ? 16 : -4 + })} + top={isHorizontal ? height - margin.bottom : 0} + /> + + {axisLeft.displayUnit && ( + + )} + + ({ + ...axisLeft.tickLabelProps(), + angle: yAxisTickLabelRotation, + dx: isHorizontal ? -8 : 4, + dy: isHorizontal ? 4 : -6 + })} + tickLength={2} + /> + + {displayAxisRight && ( + ({ + ...axisRight.tickLabelProps(), + angle: yAxisTickLabelRotation, + dx: isHorizontal ? 4 : -4, + dy: 4 + })} + tickLength={2} + top={isHorizontal ? 0 : height - margin.bottom} + /> + )} + {axisRight.displayUnit && ( + + )} + + ); +}; + +export default Axes; diff --git a/centreon/packages/ui/src/Graph/common/Axes/models.ts b/centreon/packages/ui/src/Graph/common/Axes/models.ts new file mode 100644 index 0000000000..6454cf107e --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/Axes/models.ts @@ -0,0 +1,30 @@ +import { ChartAxis } from '../../Chart/models'; +import { Line, TimeValue } from '../timeSeries/models'; + +export interface LabelProps { + [x: string]: unknown; + textAnchor?: string; +} + +export interface Axis { + displayUnit?: boolean; + onUnitChange?: (newUnit: string) => void; + unit?: string; +} + +export interface AxisYRight extends Axis { + display?: boolean; +} + +export interface AxisX { + xAxisTickFormat?: string; +} +export interface Data + extends Omit { + axisX?: AxisX; + axisYLeft?: Axis; + axisYRight?: AxisYRight; + baseAxis: number; + lines: Array; + timeSeries: Array; +} diff --git a/centreon/packages/ui/src/Graph/common/Axes/useAxisY.ts b/centreon/packages/ui/src/Graph/common/Axes/useAxisY.ts new file mode 100644 index 0000000000..3dc6c61ad8 --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/Axes/useAxisY.ts @@ -0,0 +1,119 @@ +import { useMemo } from 'react'; + +import { Axis } from '@visx/visx'; +import { isNil } from 'ramda'; + +import { useTheme } from '@mui/material'; + +import { formatMetricValue, getUnits } from '../timeSeries'; +import { commonTickLabelProps } from '../utils'; + +import { Data, LabelProps } from './models'; + +interface AxisYData { + displayUnit: boolean; + numTicks?: number; + tickFormat: (value: unknown) => string; + tickLabelProps: Axis.TickLabelProps; + unit: string; +} + +interface AxisRightData extends AxisYData { + display: boolean; +} + +interface AxisY { + axisLeft: AxisYData; + axisRight: AxisRightData; +} + +interface Props { + data: Omit; + graphHeight?: number; + graphWidth?: number; + isHorizontal: boolean; +} + +const useAxisY = ({ + data, + graphHeight, + graphWidth, + isHorizontal +}: Props): AxisY => { + const theme = useTheme(); + + const { lines } = data; + const [firstUnit, secondUnit] = getUnits(lines); + + const numTicks = isHorizontal + ? graphHeight && Math.ceil(graphHeight / 30) + : graphWidth && Math.ceil(graphWidth / 60); + + const displayAxisRight = data?.axisYRight?.display || Boolean(secondUnit); + const displayUnitAxisRight = + data?.axisYRight?.displayUnit || Boolean(secondUnit); + const displayUnitAxisLeft = data?.axisYLeft?.displayUnit || true; + const leftUnit = useMemo( + () => data.axisYLeft?.unit ?? firstUnit, + [data.axisYLeft?.unit, firstUnit] + ); + const rightUnit = useMemo( + () => data.axisYRight?.unit ?? secondUnit, + [data.axisYRight?.unit, secondUnit] + ); + + const formatTick = + ({ unit }) => + (value): string => { + if (isNil(value)) { + return ''; + } + + return formatMetricValue({ base: data.baseAxis, unit, value }) as string; + }; + + const labelProps = ({ + textAnchor, + ...rest + }: LabelProps): Record => ({ + ...commonTickLabelProps, + textAnchor, + ...rest + }); + + const tickLabelPropsAxisLeft = (): Record => + labelProps({ + dx: theme.spacing(-1), + dy: theme.spacing(0.5), + textAnchor: 'end' + }); + + const tickLabelPropsAxisRight = (): Record => + labelProps({ + dx: theme.spacing(0.5), + dy: theme.spacing(0.5), + textAnchor: 'start' + }); + + return { + axisLeft: { + displayUnit: displayUnitAxisLeft, + numTicks, + tickFormat: formatTick({ + unit: leftUnit + }), + tickLabelProps: tickLabelPropsAxisLeft, + unit: leftUnit + }, + axisRight: { + display: displayAxisRight, + displayUnit: displayUnitAxisRight, + numTicks, + tickFormat: formatTick({ unit: rightUnit }), + tickLabelProps: tickLabelPropsAxisRight, + unit: rightUnit + } + }; +}; + +export default useAxisY; diff --git a/centreon/packages/ui/src/Graph/common/BaseChart/BaseChart.tsx b/centreon/packages/ui/src/Graph/common/BaseChart/BaseChart.tsx new file mode 100644 index 0000000000..70bcbe209d --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/BaseChart/BaseChart.tsx @@ -0,0 +1,137 @@ +import { + Dispatch, + MutableRefObject, + ReactNode, + SetStateAction, + useMemo +} from 'react'; + +import { equals, gt, isNil, lte, reduce } from 'ramda'; + +import { Stack } from '@mui/material'; + +import Legend from '../../Chart/Legend'; +import { legendWidth } from '../../Chart/Legend/Legend.styles'; +import { Line } from '../timeSeries/models'; + +import Header from './Header'; +import { LineChartHeader } from './Header/models'; +import { useBaseChartStyles } from './useBaseChartStyles'; + +interface Props { + base?: number; + children: JSX.Element; + graphWidth: number; + header?: LineChartHeader; + height: number | null; + isHorizontal?: boolean; + legend: { + displayLegend: boolean; + legendHeight?: number; + mode?: 'grid' | 'list'; + placement?: 'left' | 'right' | 'bottom'; + renderExtraComponent?: ReactNode; + }; + legendRef: MutableRefObject; + limitLegend?: number | false; + lines: Array; + setLines: + | Dispatch | null>> + | Dispatch>>; + title: string; +} + +const BaseChart = ({ + legend, + base = 1000, + height, + graphWidth, + lines, + limitLegend = false, + setLines, + children, + legendRef, + title, + header, + isHorizontal = true +}: Props): JSX.Element => { + const { classes, cx } = useBaseChartStyles(); + + const legendItemsWidth = useMemo( + () => reduce((acc) => acc + legendWidth * 8 + 24, 0, lines), + [lines] + ); + + const displayLegendInBottom = useMemo( + () => isNil(legend.placement) || equals(legend.placement, 'bottom'), + [legend.placement] + ); + + const shouldDisplayLegendInCompactMode = useMemo( + () => + lte(graphWidth, 808) && + gt(legendItemsWidth, graphWidth) && + displayLegendInBottom, + [graphWidth, displayLegendInBottom, legendItemsWidth] + ); + + return ( + <> +
+
+ + {legend.displayLegend && + (equals(legend?.placement, 'left') || + equals(legend?.placement, 'right')) && ( +
+ +
+ )} + {children} +
+
+ {legend.displayLegend && displayLegendInBottom && ( +
+ +
+ )} + + ); +}; + +export default BaseChart; diff --git a/centreon/packages/ui/src/Graph/common/BaseChart/ChartSvgWrapper.tsx b/centreon/packages/ui/src/Graph/common/BaseChart/ChartSvgWrapper.tsx new file mode 100644 index 0000000000..f8053cc655 --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/BaseChart/ChartSvgWrapper.tsx @@ -0,0 +1,89 @@ +import { MutableRefObject } from 'react'; + +import { Group } from '@visx/visx'; +import { equals } from 'ramda'; + +import { margin } from '../../Chart/common'; +import { ChartAxis } from '../../Chart/models'; +import Axes from '../Axes'; +import Grids from '../Grids'; +import { Line, TimeValue } from '../timeSeries/models'; + +import { extraMargin } from './useComputeBaseChartDimensions'; + +interface Props { + allUnits: Array; + axis?: ChartAxis; + base?: number; + children: JSX.Element; + displayedLines: Array; + graphHeight: number; + graphWidth: number; + gridLinesType?: string; + leftScale; + orientation?: 'horizontal' | 'vertical'; + rightScale; + showGridLines: boolean; + svgRef: MutableRefObject; + timeSeries: Array; + xScale; +} + +const ChartSvgWrapper = ({ + svgRef, + graphHeight, + leftScale, + rightScale, + xScale, + graphWidth, + showGridLines, + gridLinesType, + base = 1000, + displayedLines, + timeSeries, + axis, + children, + orientation = 'horizontal', + allUnits +}: Props): JSX.Element => { + const isHorizontal = equals(orientation, 'horizontal'); + + return ( + + + {showGridLines && ( + + )} + + {children} + + + ); +}; + +export default ChartSvgWrapper; diff --git a/centreon/packages/ui/src/Graph/common/BaseChart/Header/index.tsx b/centreon/packages/ui/src/Graph/common/BaseChart/Header/index.tsx new file mode 100644 index 0000000000..32a2a3b4a6 --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/BaseChart/Header/index.tsx @@ -0,0 +1,37 @@ +import Typography from '@mui/material/Typography'; + +import { useMemoComponent } from '@centreon/ui'; + +import { LineChartHeader } from './models'; +import { ussHeaderChartStyles } from './useHeaderStyles'; + +interface Props { + header?: LineChartHeader; + title: string; +} + +const Header = ({ title, header }: Props): JSX.Element => { + const { classes } = ussHeaderChartStyles(); + + const displayTitle = header?.displayTitle ?? true; + + return useMemoComponent({ + Component: ( +
+
+
+ {displayTitle && ( + + {title} + + )} +
+ {header?.extraComponent} +
+ ), + + memoProps: [title, header] + }); +}; + +export default Header; diff --git a/centreon/packages/ui/src/Graph/common/BaseChart/Header/models.ts b/centreon/packages/ui/src/Graph/common/BaseChart/Header/models.ts new file mode 100644 index 0000000000..5b74d1d2f4 --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/BaseChart/Header/models.ts @@ -0,0 +1,4 @@ +export interface LineChartHeader { + displayTitle?: boolean; + extraComponent?: ReactNode; +} diff --git a/centreon/packages/ui/src/Graph/common/BaseChart/Header/useHeaderStyles.ts b/centreon/packages/ui/src/Graph/common/BaseChart/Header/useHeaderStyles.ts new file mode 100644 index 0000000000..aa6f45bf5b --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/BaseChart/Header/useHeaderStyles.ts @@ -0,0 +1,9 @@ +import { makeStyles } from 'tss-react/mui'; + +export const ussHeaderChartStyles = makeStyles()({ + header: { + display: 'grid', + gridTemplateColumns: '0.4fr 1fr 0.4fr', + width: '100%' + } +}); diff --git a/centreon/packages/ui/src/Graph/common/BaseChart/useBaseChartStyles.ts b/centreon/packages/ui/src/Graph/common/BaseChart/useBaseChartStyles.ts new file mode 100644 index 0000000000..7fab91ee6c --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/BaseChart/useBaseChartStyles.ts @@ -0,0 +1,44 @@ +import { makeStyles } from 'tss-react/mui'; + +export const useBaseChartStyles = makeStyles()((theme) => ({ + container: { + '& .visx-axis-bottom': { + '& .visx-axis-tick': { + '& .visx-line': { + stroke: theme.palette.text.primary + }, + text: { + fill: theme.palette.text.primary + } + } + }, + '& .visx-axis-line': { + stroke: theme.palette.text.primary + }, + '& .visx-axis-right': { + '& .visx-axis-tick': { + '& .visx-line': { + stroke: theme.palette.text.primary + } + } + }, + '& .visx-columns': { + '& .visx-line': { + stroke: theme.palette.divider + } + }, + '& .visx-rows': { + '& .visx-line': { + stroke: theme.palette.divider + } + }, + fill: theme.palette.text.primary, + position: 'relative' + }, + legendContainer: { + maxWidth: '60%' + }, + legendContainerVerticalSide: { + marginRight: theme.spacing(6) + } +})); diff --git a/centreon/packages/ui/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts b/centreon/packages/ui/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts new file mode 100644 index 0000000000..bda73233db --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts @@ -0,0 +1,66 @@ +import { MutableRefObject, useRef } from 'react'; + +import { equals, isNil } from 'ramda'; + +import { margin } from '../../Chart/common'; + +export const extraMargin = 10; + +interface UseComputeBaseChartDimensionsProps { + hasSecondUnit?: boolean; + height: number | null; + legendDisplay?: boolean; + legendHeight?: number; + legendPlacement?: string; + width: number; +} + +interface UseComputeBaseChartDimensionsState { + graphHeight: number; + graphWidth: number; + legendRef: MutableRefObject; +} + +export const useComputeBaseChartDimensions = ({ + width, + height, + legendDisplay, + legendPlacement, + hasSecondUnit, + legendHeight +}: UseComputeBaseChartDimensionsProps): UseComputeBaseChartDimensionsState => { + const legendRef = useRef(null); + + const currentLegendHeight = + legendHeight ?? (legendRef.current?.getBoundingClientRect().height || 0); + + const legendBoundingHeight = + !equals(legendDisplay, false) && + (isNil(legendPlacement) || equals(legendPlacement, 'bottom')) + ? currentLegendHeight + : 0; + const legendBoundingWidth = + !equals(legendDisplay, false) && + (equals(legendPlacement, 'left') || equals(legendPlacement, 'right')) + ? legendRef.current?.getBoundingClientRect().width || 0 + : 0; + + const graphWidth = + width > 0 + ? width - + margin.left - + (hasSecondUnit ? margin.right : 8) - + extraMargin - + legendBoundingWidth + : 0; + const graphHeight = + (height || 0) > 0 + ? (height || 0) - margin.top - 5 - legendBoundingHeight + : 0; + + return { + graphHeight, + graphWidth, + legendRef + }; +}; diff --git a/centreon/packages/ui/src/Graph/common/Grids/index.tsx b/centreon/packages/ui/src/Graph/common/Grids/index.tsx new file mode 100644 index 0000000000..749c69049c --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/Grids/index.tsx @@ -0,0 +1,44 @@ +import { useMemo } from 'react'; + +import { Grid } from '@visx/visx'; +import { ScaleLinear } from 'd3-scale'; +import { includes } from 'ramda'; + +import { ChartAxis } from '../../Chart/models'; + +interface Props extends Pick { + height: number; + leftScale: ScaleLinear; + width: number; + xScale: ScaleLinear; +} + +const Grids = ({ + height, + width, + leftScale, + xScale, + gridLinesType +}: Props): JSX.Element => { + const displayRows = useMemo( + () => includes(gridLinesType, ['all', 'horizontal', undefined]), + [gridLinesType] + ); + const displayColumns = useMemo( + () => includes(gridLinesType, ['all', 'vertical', undefined]), + [gridLinesType] + ); + + return ( + + {displayRows && ( + + )} + {displayColumns && ( + + )} + + ); +}; + +export default Grids; diff --git a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/ThresholdLine.tsx b/centreon/packages/ui/src/Graph/common/Thresholds/ThresholdLine.tsx similarity index 75% rename from centreon/packages/ui/src/Graph/LineChart/BasicComponents/ThresholdLine.tsx rename to centreon/packages/ui/src/Graph/common/Thresholds/ThresholdLine.tsx index 7997730927..5ddbcb7f21 100644 --- a/centreon/packages/ui/src/Graph/LineChart/BasicComponents/ThresholdLine.tsx +++ b/centreon/packages/ui/src/Graph/common/Thresholds/ThresholdLine.tsx @@ -2,10 +2,11 @@ import { equals } from 'ramda'; import { useTheme } from '@mui/material'; -import { margin } from '../common'; +import { margin } from '../../Chart/common'; interface Props { hideTooltip: () => void; + isHorizontal: boolean; label: string; showTooltip: (args) => void; thresholdType: string; @@ -21,7 +22,8 @@ export const ThresholdLine = ({ thresholdType, showTooltip, hideTooltip, - width + width, + isHorizontal }: Props): JSX.Element => { const theme = useTheme(); @@ -38,6 +40,20 @@ export const ThresholdLine = ({ ? theme.palette.warning.main : theme.palette.error.main; + const coordinates = isHorizontal + ? { + x1: 0, + x2: width, + y1: scaledValue, + y2: scaledValue + } + : { + x1: scaledValue, + x2: scaledValue, + y1: 0, + y2: width + }; + return ( <> ); diff --git a/centreon/packages/ui/src/Graph/common/Thresholds/Thresholds.tsx b/centreon/packages/ui/src/Graph/common/Thresholds/Thresholds.tsx new file mode 100644 index 0000000000..aef66a78df --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/Thresholds/Thresholds.tsx @@ -0,0 +1,76 @@ +import { ScaleLinear } from 'd3-scale'; +import { equals } from 'ramda'; + +import { Thresholds as ThresholdsModel } from '../models'; +import { getUnits, getYScale } from '../timeSeries'; +import { Line } from '../timeSeries/models'; + +import { ThresholdLine } from './ThresholdLine'; + +interface Props { + displayedLines: Array; + hideTooltip: () => void; + isHorizontal?: boolean; + showTooltip: (props) => void; + thresholdUnit?: string; + thresholds: ThresholdsModel; + width: number; + yScalesPerUnit: Record>; +} + +const Thresholds = ({ + thresholds, + width, + displayedLines, + thresholdUnit, + showTooltip, + hideTooltip, + yScalesPerUnit, + isHorizontal = true +}: Props): JSX.Element => { + const [firstUnit, secondUnit] = getUnits(displayedLines as Array); + + const shouldUseRightScale = + thresholdUnit && equals(thresholdUnit, secondUnit); + + const yScale = shouldUseRightScale + ? yScalesPerUnit[secondUnit] + : getYScale({ + invert: null, + unit: firstUnit, + yScalesPerUnit + }); + + return ( + <> + {thresholds.warning.map(({ value, label }) => ( + + ))} + {thresholds.critical.map(({ value, label }) => ( + + ))} + + ); +}; + +export default Thresholds; diff --git a/centreon/packages/ui/src/Graph/common/timeSeries/index.test.ts b/centreon/packages/ui/src/Graph/common/timeSeries/index.test.ts index dcb776d848..1655699782 100644 --- a/centreon/packages/ui/src/Graph/common/timeSeries/index.test.ts +++ b/centreon/packages/ui/src/Graph/common/timeSeries/index.test.ts @@ -1,7 +1,23 @@ +import { + formatMetricValue, + formatMetricValueWithUnit, + getDates, + getInvertedStackedLines, + getLineData, + getLineForMetric, + getMetricValuesForLines, + getMetricValuesForUnit, + getMetrics, + getNotInvertedStackedLines, + getSortedStackedLines, + getStackedMetricValues, + getTimeSeries, + getTimeSeriesForLines, + getUnits, + hasUnitStackedLines +} from '.'; import { LineChartData } from '../models'; -import * as timeSeries from '.'; - type TestCase = [number | null, string, 1000 | 1024, string | null]; describe('timeSeries', () => { @@ -114,7 +130,7 @@ describe('timeSeries', () => { describe('getTimeSeries', () => { it('returns the time series for the given graph data', () => { - expect(timeSeries.getTimeSeries(graphData)).toEqual([ + expect(getTimeSeries(graphData)).toEqual([ { 1: 0, 2: 0.5, @@ -142,7 +158,7 @@ describe('timeSeries', () => { } }; - expect(timeSeries.getTimeSeries(graphDataWithLowerLimit)).toEqual([ + expect(getTimeSeries(graphDataWithLowerLimit)).toEqual([ { 2: 0.5, 3: 6, @@ -163,7 +179,7 @@ describe('timeSeries', () => { describe('getLineData', () => { it('returns the line information for the given graph data', () => { - expect(timeSeries.getLineData(graphData)).toEqual([ + expect(getLineData(graphData)).toEqual([ { areaColor: 'transparent', average_value: 1, @@ -266,7 +282,7 @@ describe('timeSeries', () => { describe('getMetrics', () => { it('returns the metrics for the given time value', () => { expect( - timeSeries.getMetrics({ + getMetrics({ rta: 1, time: 0, timeTick: '2020-11-05T10:40:00Z' @@ -277,29 +293,29 @@ describe('timeSeries', () => { describe('getMetricValuesForUnit', () => { it('returns the values in the given time series corresponding to the given line unit', () => { - const series = timeSeries.getTimeSeries(graphData); - const lines = timeSeries.getLineData(graphData); + const series = getTimeSeries(graphData); + const lines = getLineData(graphData); const unit = 'ms'; expect( - timeSeries.getMetricValuesForUnit({ lines, timeSeries: series, unit }) + getMetricValuesForUnit({ lines, timeSeries: series, unit }) ).toEqual([0, 1, 0.5, 3, 6, 4, 12, 25]); }); }); describe('getUnits', () => { it('returns the units for the given lines', () => { - const lines = timeSeries.getLineData(graphData); + const lines = getLineData(graphData); - expect(timeSeries.getUnits(lines)).toEqual(['ms', '%']); + expect(getUnits(lines)).toEqual(['ms', '%']); }); }); describe('getDates', () => { it('teruns the dates for the given time series', () => { - const series = timeSeries.getTimeSeries(graphData); + const series = getTimeSeries(graphData); - expect(timeSeries.getDates(series)).toEqual([ + expect(getDates(series)).toEqual([ new Date('2020-11-05T10:35:00.000Z'), new Date('2020-11-05T10:40:00.000Z') ]); @@ -308,9 +324,9 @@ describe('timeSeries', () => { describe('getLineForMetric', () => { it('returns the line corresponding to the given metrics', () => { - const lines = timeSeries.getLineData(graphData); + const lines = getLineData(graphData); - expect(timeSeries.getLineForMetric({ lines, metric_id: 1 })).toEqual({ + expect(getLineForMetric({ lines, metric_id: 1 })).toEqual({ areaColor: 'transparent', average_value: 1, color: 'black', @@ -334,16 +350,16 @@ describe('timeSeries', () => { describe('getMetricValuesForLines', () => { it('returns the metric values for the given lines within the given time series', () => { - const lines = timeSeries.getLineData(graphData); - const series = timeSeries.getTimeSeries(graphData); + const lines = getLineData(graphData); + const series = getTimeSeries(graphData); - expect( - timeSeries.getMetricValuesForLines({ lines, timeSeries: series }) - ).toEqual([0, 1, 0.5, 3, 6, 4, 12, 25, 0, 1]); + expect(getMetricValuesForLines({ lines, timeSeries: series })).toEqual([ + 0, 1, 0.5, 3, 6, 4, 12, 25, 0, 1 + ]); }); }); - describe(timeSeries.formatMetricValue, () => { + describe(formatMetricValue, () => { const cases: Array = [ [218857269, '', 1000, '218.86m'], [218857269, '', 1024, '208.72 M'], @@ -356,7 +372,7 @@ describe('timeSeries', () => { it.each(cases)( 'formats the given value to a human readable form according to the given unit and base', (value, unit, base, formattedResult) => { - expect(timeSeries.formatMetricValue({ base, unit, value })).toEqual( + expect(formatMetricValue({ base, unit, value })).toEqual( formattedResult ); } @@ -365,9 +381,9 @@ describe('timeSeries', () => { describe('getSortedStackedLines', () => { it('returns stacked lines sorted by their own order for the given lines', () => { - const lines = timeSeries.getLineData(graphData); + const lines = getLineData(graphData); - expect(timeSeries.getSortedStackedLines(lines)).toEqual([ + expect(getSortedStackedLines(lines)).toEqual([ { areaColor: 'yellow', average_value: 1, @@ -412,12 +428,12 @@ describe('timeSeries', () => { describe('getStackedMetricValues', () => { it('returns stacked metrics values for the given lines and the given time series', () => { - const lines = timeSeries.getLineData(graphData); - const series = timeSeries.getTimeSeries(graphData); + const lines = getLineData(graphData); + const series = getTimeSeries(graphData); expect( - timeSeries.getStackedMetricValues({ - lines: timeSeries.getSortedStackedLines(lines), + getStackedMetricValues({ + lines: getSortedStackedLines(lines), timeSeries: series }) ).toEqual([18, 29]); @@ -426,12 +442,12 @@ describe('timeSeries', () => { describe('getTimeSeriesForLines', () => { it('returns the specific time series for the given lines and the fiven time series', () => { - const lines = timeSeries.getLineData(graphData); - const series = timeSeries.getTimeSeries(graphData); + const lines = getLineData(graphData); + const series = getTimeSeries(graphData); expect( - timeSeries.getTimeSeriesForLines({ - lines: timeSeries.getSortedStackedLines(lines), + getTimeSeriesForLines({ + lines: getSortedStackedLines(lines), timeSeries: series }) ).toEqual([ @@ -451,9 +467,9 @@ describe('timeSeries', () => { describe('getInvertedStackedLines', () => { it('returns inverted and stacked lines for the given lines', () => { - const lines = timeSeries.getLineData(graphData); + const lines = getLineData(graphData); - expect(timeSeries.getInvertedStackedLines(lines)).toEqual([ + expect(getInvertedStackedLines(lines)).toEqual([ { areaColor: 'yellow', average_value: 1, @@ -479,9 +495,9 @@ describe('timeSeries', () => { describe('getNotInvertedStackedLines', () => { it('returns not inverted and stacked lines for the given lines', () => { - const lines = timeSeries.getLineData(graphData); + const lines = getLineData(graphData); - expect(timeSeries.getNotInvertedStackedLines(lines)).toEqual([ + expect(getNotInvertedStackedLines(lines)).toEqual([ { areaColor: 'red', average_value: 1, @@ -507,15 +523,11 @@ describe('timeSeries', () => { describe('hasUnitStackedLines', () => { it('returns true if the given unit contains stacked lines following the given lines, false otherwise', () => { - const lines = timeSeries.getLineData(graphData); + const lines = getLineData(graphData); - expect(timeSeries.hasUnitStackedLines({ lines, unit: 'ms' })).toEqual( - true - ); + expect(hasUnitStackedLines({ lines, unit: 'ms' })).toEqual(true); - expect(timeSeries.hasUnitStackedLines({ lines, unit: '%' })).toEqual( - false - ); + expect(hasUnitStackedLines({ lines, unit: '%' })).toEqual(false); }); }); }); @@ -598,7 +610,7 @@ describe('Format value with unit', () => { 'formats the value with $unit', ({ value, unit, expectedResult }) => { expect( - timeSeries.formatMetricValueWithUnit({ + formatMetricValueWithUnit({ unit, value }) @@ -612,7 +624,7 @@ describe('Format value with unit', () => { 'formats the value with $unit', ({ value, unit, expectedResult }) => { expect( - timeSeries.formatMetricValueWithUnit({ + formatMetricValueWithUnit({ isRaw: true, unit, value diff --git a/centreon/packages/ui/src/Graph/common/timeSeries/index.test.ts-E b/centreon/packages/ui/src/Graph/common/timeSeries/index.test.ts-E new file mode 100644 index 0000000000..abbcfce596 --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/timeSeries/index.test.ts-E @@ -0,0 +1,622 @@ +import { LineChartData } from '../models'; + +type TestCase = [number | null, string, 1000 | 1024, string | null]; + +describe('timeSeries', () => { + const graphData: LineChartData = { + global: {}, + metrics: [ + { + average_value: 1, + data: [0, 1], + ds_data: { + ds_color_area: 'transparent', + ds_color_line: 'black', + ds_filled: false, + ds_invert: null, + ds_legend: 'Round-Trip-Time Average', + ds_order: null, + ds_stack: null, + ds_transparency: 80 + }, + legend: 'Round-Trip-Time Average (ms)', + maximum_value: 1.5, + metric: 'rta', + metric_id: 1, + minimum_value: 0.5, + unit: 'ms' + }, + { + average_value: 1, + data: [0.5, 3], + ds_data: { + ds_color_area: 'blue', + ds_color_line: 'blue', + ds_filled: true, + ds_invert: null, + ds_legend: 'Time', + ds_order: null, + ds_stack: null, + ds_transparency: 80 + }, + legend: 'Time (ms)', + maximum_value: 1.5, + metric: 'time', + metric_id: 2, + minimum_value: 0.5, + unit: 'ms' + }, + { + average_value: 1, + data: [6, 4], + ds_data: { + ds_color_area: 'red', + ds_color_line: 'red', + ds_filled: true, + ds_invert: null, + ds_legend: 'Average duration', + ds_order: '2', + ds_stack: '1', + ds_transparency: 80 + }, + legend: 'Average duration (ms)', + maximum_value: 1.5, + metric: 'avgDuration', + metric_id: 3, + minimum_value: 0.5, + unit: 'ms' + }, + { + average_value: 1, + data: [12, 25], + ds_data: { + ds_color_area: 'yellow', + ds_color_line: 'yellow', + ds_filled: true, + ds_invert: '1', + ds_legend: 'Duration', + ds_order: '1', + ds_stack: '1', + ds_transparency: 80 + }, + legend: 'Duration (ms)', + maximum_value: 1.5, + metric: 'duration', + metric_id: 4, + minimum_value: 0.5, + unit: 'ms' + }, + { + average_value: 1, + data: [0, 1], + ds_data: { + ds_color_area: 'yellow', + ds_color_line: 'yellow', + ds_filled: true, + ds_invert: null, + ds_legend: 'Packet Loss', + ds_order: null, + ds_stack: null, + ds_transparency: 80 + }, + legend: 'Packet Loss (%)', + maximum_value: 1.5, + metric: 'packet_loss', + metric_id: 5, + minimum_value: 0.5, + unit: '%' + } + ], + times: ['2020-11-05T10:35:00Z', '2020-11-05T10:40:00Z'] + }; + + describe('getTimeSeries', () => { + it('returns the time series for the given graph data', () => { + expect(getTimeSeries(graphData)).toEqual([ + { + 1: 0, + 2: 0.5, + 3: 6, + 4: 12, + 5: 0, + timeTick: '2020-11-05T10:35:00Z' + }, + { + 1: 1, + 2: 3, + 3: 4, + 4: 25, + 5: 1, + timeTick: '2020-11-05T10:40:00Z' + } + ]); + }); + + it('filters metric values below the given lower-limit value', () => { + const graphDataWithLowerLimit = { + ...graphData, + global: { + 'lower-limit': 0.4 + } + }; + + expect(getTimeSeries(graphDataWithLowerLimit)).toEqual([ + { + 2: 0.5, + 3: 6, + 4: 12, + timeTick: '2020-11-05T10:35:00Z' + }, + { + 1: 1, + 2: 3, + 3: 4, + 4: 25, + 5: 1, + timeTick: '2020-11-05T10:40:00Z' + } + ]); + }); + }); + + describe('getLineData', () => { + it('returns the line information for the given graph data', () => { + expect(getLineData(graphData)).toEqual([ + { + areaColor: 'transparent', + average_value: 1, + color: 'black', + display: true, + filled: false, + highlight: undefined, + invert: null, + legend: 'Round-Trip-Time Average', + lineColor: 'black', + maximum_value: 1.5, + metric: 'rta', + metric_id: 1, + minimum_value: 0.5, + name: 'Round-Trip-Time Average (ms)', + stackOrder: null, + transparency: 80, + unit: 'ms' + }, + { + areaColor: 'blue', + average_value: 1, + color: 'blue', + display: true, + filled: true, + highlight: undefined, + invert: null, + legend: 'Time', + lineColor: 'blue', + maximum_value: 1.5, + metric: 'time', + metric_id: 2, + minimum_value: 0.5, + name: 'Time (ms)', + stackOrder: null, + transparency: 80, + unit: 'ms' + }, + { + areaColor: 'red', + average_value: 1, + color: 'red', + display: true, + filled: true, + highlight: undefined, + invert: null, + legend: 'Average duration', + lineColor: 'red', + maximum_value: 1.5, + metric: 'avgDuration', + metric_id: 3, + minimum_value: 0.5, + name: 'Average duration (ms)', + stackOrder: 2, + transparency: 80, + unit: 'ms' + }, + { + areaColor: 'yellow', + average_value: 1, + color: 'yellow', + display: true, + filled: true, + highlight: undefined, + invert: '1', + legend: 'Duration', + lineColor: 'yellow', + maximum_value: 1.5, + metric: 'duration', + metric_id: 4, + minimum_value: 0.5, + name: 'Duration (ms)', + stackOrder: 1, + transparency: 80, + unit: 'ms' + }, + { + areaColor: 'yellow', + average_value: 1, + color: 'yellow', + display: true, + filled: true, + highlight: undefined, + invert: null, + legend: 'Packet Loss', + lineColor: 'yellow', + maximum_value: 1.5, + metric: 'packet_loss', + metric_id: 5, + minimum_value: 0.5, + name: 'Packet Loss (%)', + stackOrder: null, + transparency: 80, + unit: '%' + } + ]); + }); + }); + + describe('getMetrics', () => { + it('returns the metrics for the given time value', () => { + expect( + getMetrics({ + rta: 1, + time: 0, + timeTick: '2020-11-05T10:40:00Z' + }) + ).toEqual(['rta', 'time']); + }); + }); + + describe('getMetricValuesForUnit', () => { + it('returns the values in the given time series corresponding to the given line unit', () => { + const series = getTimeSeries(graphData); + const lines = getLineData(graphData); + const unit = 'ms'; + + expect( + getMetricValuesForUnit({ lines, timeSeries: series, unit }) + ).toEqual([0, 1, 0.5, 3, 6, 4, 12, 25]); + }); + }); + + describe('getUnits', () => { + it('returns the units for the given lines', () => { + const lines = getLineData(graphData); + + expect(getUnits(lines)).toEqual(['ms', '%']); + }); + }); + + describe('getDates', () => { + it('teruns the dates for the given time series', () => { + const series = getTimeSeries(graphData); + + expect(getDates(series)).toEqual([ + new Date('2020-11-05T10:35:00.000Z'), + new Date('2020-11-05T10:40:00.000Z') + ]); + }); + }); + + describe('getLineForMetric', () => { + it('returns the line corresponding to the given metrics', () => { + const lines = getLineData(graphData); + + expect(getLineForMetric({ lines, metric_id: 1 })).toEqual({ + areaColor: 'transparent', + average_value: 1, + color: 'black', + display: true, + filled: false, + highlight: undefined, + invert: null, + legend: 'Round-Trip-Time Average', + lineColor: 'black', + maximum_value: 1.5, + metric: 'rta', + metric_id: 1, + minimum_value: 0.5, + name: 'Round-Trip-Time Average (ms)', + stackOrder: null, + transparency: 80, + unit: 'ms' + }); + }); + }); + + describe('getMetricValuesForLines', () => { + it('returns the metric values for the given lines within the given time series', () => { + const lines = getLineData(graphData); + const series = getTimeSeries(graphData); + + expect( + getMetricValuesForLines({ lines, timeSeries: series }) + ).toEqual([0, 1, 0.5, 3, 6, 4, 12, 25, 0, 1]); + }); + }); + + describe(formatMetricValue, () => { + const cases: Array = [ + [218857269, '', 1000, '218.86m'], + [218857269, '', 1024, '208.72 M'], + [0.12232323445, '', 1000, '0.12'], + [1024, 'B', 1000, '1 KB'], + [1024, 'B', 1024, '1 KB'], + [null, 'B', 1024, null] + ]; + + it.each(cases)( + 'formats the given value to a human readable form according to the given unit and base', + (value, unit, base, formattedResult) => { + expect(formatMetricValue({ base, unit, value })).toEqual( + formattedResult + ); + } + ); + }); + + describe('getSortedStackedLines', () => { + it('returns stacked lines sorted by their own order for the given lines', () => { + const lines = getLineData(graphData); + + expect(getSortedStackedLines(lines)).toEqual([ + { + areaColor: 'yellow', + average_value: 1, + color: 'yellow', + display: true, + filled: true, + highlight: undefined, + invert: '1', + legend: 'Duration', + lineColor: 'yellow', + maximum_value: 1.5, + metric: 'duration', + metric_id: 4, + minimum_value: 0.5, + name: 'Duration (ms)', + stackOrder: 1, + transparency: 80, + unit: 'ms' + }, + { + areaColor: 'red', + average_value: 1, + color: 'red', + display: true, + filled: true, + highlight: undefined, + invert: null, + legend: 'Average duration', + lineColor: 'red', + maximum_value: 1.5, + metric: 'avgDuration', + metric_id: 3, + minimum_value: 0.5, + name: 'Average duration (ms)', + stackOrder: 2, + transparency: 80, + unit: 'ms' + } + ]); + }); + }); + + describe('getStackedMetricValues', () => { + it('returns stacked metrics values for the given lines and the given time series', () => { + const lines = getLineData(graphData); + const series = getTimeSeries(graphData); + + expect( + getStackedMetricValues({ + lines: getSortedStackedLines(lines), + timeSeries: series + }) + ).toEqual([18, 29]); + }); + }); + + describe('getTimeSeriesForLines', () => { + it('returns the specific time series for the given lines and the fiven time series', () => { + const lines = getLineData(graphData); + const series = getTimeSeries(graphData); + + expect( + getTimeSeriesForLines({ + lines: getSortedStackedLines(lines), + timeSeries: series + }) + ).toEqual([ + { + 3: 6, + 4: 12, + timeTick: '2020-11-05T10:35:00Z' + }, + { + 3: 4, + 4: 25, + timeTick: '2020-11-05T10:40:00Z' + } + ]); + }); + }); + + describe('getInvertedStackedLines', () => { + it('returns inverted and stacked lines for the given lines', () => { + const lines = getLineData(graphData); + + expect(getInvertedStackedLines(lines)).toEqual([ + { + areaColor: 'yellow', + average_value: 1, + color: 'yellow', + display: true, + filled: true, + highlight: undefined, + invert: '1', + legend: 'Duration', + lineColor: 'yellow', + maximum_value: 1.5, + metric: 'duration', + metric_id: 4, + minimum_value: 0.5, + name: 'Duration (ms)', + stackOrder: 1, + transparency: 80, + unit: 'ms' + } + ]); + }); + }); + + describe('getNotInvertedStackedLines', () => { + it('returns not inverted and stacked lines for the given lines', () => { + const lines = getLineData(graphData); + + expect(getNotInvertedStackedLines(lines)).toEqual([ + { + areaColor: 'red', + average_value: 1, + color: 'red', + display: true, + filled: true, + highlight: undefined, + invert: null, + legend: 'Average duration', + lineColor: 'red', + maximum_value: 1.5, + metric: 'avgDuration', + metric_id: 3, + minimum_value: 0.5, + name: 'Average duration (ms)', + stackOrder: 2, + transparency: 80, + unit: 'ms' + } + ]); + }); + }); + + describe('hasUnitStackedLines', () => { + it('returns true if the given unit contains stacked lines following the given lines, false otherwise', () => { + const lines = getLineData(graphData); + + expect(hasUnitStackedLines({ lines, unit: 'ms' })).toEqual( + true + ); + + expect(hasUnitStackedLines({ lines, unit: '%' })).toEqual( + false + ); + }); + }); +}); + +describe('Format value with unit', () => { + const units = [ + 'B', + 'bytes', + 'bytespersecond', + 'B/s', + 'B/sec', + 'o', + 'octets', + 'b/s', + 'b', + 'ms', + '%', + '' + ]; + + const getExpectedResult = (unit): string => { + if (unit === '') { + return '324.23m'; + } + + return `309.21 M${unit}`; + }; + + const humanReadableTestCases = units.map((unit) => { + if (unit === '%') { + return { + expectedResult: '45.56%', + unit, + value: 45.55678 + }; + } + + if (unit === 'ms') { + return { + expectedResult: '34.23 seconds', + unit, + value: 34232 + }; + } + + return { + expectedResult: getExpectedResult(unit), + unit, + value: 324234232.34233 + }; + }); + + const rawTestCases = units.map((unit) => { + if (unit === '%') { + return { + expectedResult: '45.55678%', + unit, + value: 45.55678 + }; + } + + if (unit === 'ms') { + return { + expectedResult: '34232 ms', + unit, + value: 34232 + }; + } + + return { + expectedResult: + unit === '' ? '324234232.34233 ' : `324234232.34233 ${unit}`, + unit, + value: 324234232.34233 + }; + }); + + describe('Format the value as human readable', () => { + it.each(humanReadableTestCases)( + 'formats the value with $unit', + ({ value, unit, expectedResult }) => { + expect( + formatMetricValueWithUnit({ + unit, + value + }) + ).toEqual(expectedResult); + } + ); + }); + + describe('Format the value as raw', () => { + it.each(rawTestCases)( + 'formats the value with $unit', + ({ value, unit, expectedResult }) => { + expect( + timeSeries.formatMetricValueWithUnit({ + isRaw: true, + unit, + value + }) + ).toEqual(expectedResult); + } + ); + }); +}); diff --git a/centreon/packages/ui/src/Graph/common/timeSeries/index.ts b/centreon/packages/ui/src/Graph/common/timeSeries/index.ts index b84898b19b..bce05602f6 100644 --- a/centreon/packages/ui/src/Graph/common/timeSeries/index.ts +++ b/centreon/packages/ui/src/Graph/common/timeSeries/index.ts @@ -1,53 +1,51 @@ -import numeral from 'numeral'; import { Scale } from '@visx/visx'; import { bisector } from 'd3-array'; import { ScaleLinear, ScaleTime } from 'd3-scale'; +import numeral from 'numeral'; import { - map, - pipe, - reduce, - filter, - addIndex, - isNil, path, - reject, + T, + add, + addIndex, + always, + any, + cond, equals, + filter, + find, + flatten, + head, + identity, + includes, + isEmpty, + isNil, + isNotNil, keys, + last, + lt, + map, + negate, + pipe, prop, - flatten, propEq, - uniq, - find, + reduce, + reject, sortBy, - add, - isEmpty, - any, - not, - min, - max, - lt, - identity, - head, - last, - cond, - always, - T, - includes, - split + split, + uniq } from 'ramda'; -import { margin } from '../../LineChart/common'; +import { margin } from '../../Chart/common'; import { LineChartData } from '../models'; import { - Metric, - TimeValue, - Line, AxeScale, - Xscale, FormatMetricValueProps, - YScales, - TimeValueProps + Line, + Metric, + TimeValue, + TimeValueProps, + Xscale } from './models'; interface TimeTickWithMetrics { @@ -119,12 +117,14 @@ const toLine = ({ average_value, minimum_value, maximum_value, - metric_id + metric_id, + displayAs }: Metric): Line => ({ areaColor: ds_data.ds_color_area, average_value, color: ds_data.ds_color_line, display: true, + displayAs, filled: ds_data.ds_filled, highlight: undefined, invert: ds_data.ds_invert, @@ -135,9 +135,10 @@ const toLine = ({ metric_id, minimum_value, name: legend, - stackOrder: equals(ds_data.ds_stack, '1') - ? parseInt(ds_data.ds_order || '0', 10) - : null, + stackOrder: + equals(ds_data.ds_stack, '1') || equals(ds_data.ds_stack, true) + ? Number.parseInt(ds_data.ds_order || '0', 10) + : null, transparency: ds_data.ds_transparency, unit }); @@ -219,6 +220,7 @@ export const getLinesForMetrics = ({ filter(({ metric_id }) => metricIds.includes(metric_id), lines); interface LinesTimeSeries { + invert?: boolean | string | null; lines: Array; timeSeries: Array; } @@ -268,17 +270,13 @@ const getSortedStackedLines = (lines: Array): Array => const getInvertedStackedLines = (lines: Array): Array => pipe( - reject(({ invert }: Line): boolean => isNil(invert)) as ( - lines - ) => Array, + filter(({ invert }: Line): boolean => invert) as (lines) => Array, getSortedStackedLines )(lines); const getNotInvertedStackedLines = (lines: Array): Array => pipe( - filter(({ invert }: Line): boolean => isNil(invert)) as ( - lines - ) => Array, + reject(({ invert }: Line): boolean => invert) as (lines) => Array, getSortedStackedLines )(lines); @@ -292,7 +290,8 @@ const hasUnitStackedLines = ({ lines, unit }: HasStackedLines): boolean => const getTimeSeriesForLines = ({ lines, - timeSeries + timeSeries, + invert }: LinesTimeSeries): Array => { const metrics = map(prop('metric_id'), lines); @@ -301,7 +300,10 @@ const getTimeSeriesForLines = ({ ...reduce( (acc, metric_id): Omit => ({ ...acc, - [metric_id]: metricsValue[metric_id] + [metric_id]: + invert && metricsValue[metric_id] + ? negate(metricsValue[metric_id]) + : metricsValue[metric_id] }), {}, metrics @@ -313,39 +315,39 @@ const getTimeSeriesForLines = ({ }; interface GetYScaleProps { - hasMoreThanTwoUnits: boolean; invert: string | null; - leftScale: ScaleLinear; - rightScale: ScaleLinear; - secondUnit: string; + scale?: 'linear' | 'logarithmic'; + scaleLogarithmicBase?: number; unit: string; + yScalesPerUnit: Record>; } const getYScale = ({ - hasMoreThanTwoUnits, unit, - secondUnit, - leftScale, - rightScale, - invert + invert, + yScalesPerUnit, + scale = 'linear', + scaleLogarithmicBase }: GetYScaleProps): ScaleLinear => { - const isLeftScale = hasMoreThanTwoUnits || unit !== secondUnit; - const scale = isLeftScale ? leftScale : rightScale; + const yScale = yScalesPerUnit[unit]; return invert - ? Scale.scaleLinear({ - domain: scale.domain().reverse(), - nice: true, - range: scale.range().reverse() + ? getScaleType(scale)({ + base: scaleLogarithmicBase, + domain: yScale.domain().reverse(), + range: yScale.range().reverse() }) - : scale; + : yScale; }; const getScaleType = ( - scale: 'linear' | 'logarithimc' + scale: 'linear' | 'logarithmic' ): typeof Scale.scaleLinear | typeof Scale.scaleLog => equals(scale, 'logarithmic') ? Scale.scaleLog : Scale.scaleLinear; +const hasOnlyZeroesHasValue = (graphValues: Array): boolean => + graphValues.every((value) => equals(value, 0) || equals(value, null)); + const getScale = ({ graphValues, height, @@ -353,23 +355,29 @@ const getScale = ({ thresholds, isCenteredZero, scale, - scaleLogarithmicBase + scaleLogarithmicBase, + isHorizontal, + invert, + hasDisplayAsBar }): ScaleLinear => { const isLogScale = equals(scale, 'logarithmic'); const minValue = Math.min( - getMin(graphValues), + hasDisplayAsBar && 0, + invert ? negate(getMax(graphValues)) : getMin(graphValues), getMin(stackedValues), Math.min(...thresholds) ); const maxValue = Math.max( getMax(graphValues), getMax(stackedValues), + hasOnlyZeroesHasValue(graphValues) ? 1 : 0, Math.max(...thresholds) ); const scaleType = getScaleType(scale); const upperRangeValue = minValue === maxValue && maxValue === 0 ? height : 0; + const range = [height, upperRangeValue]; if (isCenteredZero) { const greatestValue = Math.max(Math.abs(maxValue), Math.abs(minValue)); @@ -377,65 +385,16 @@ const getScale = ({ return scaleType({ base: scaleLogarithmicBase || 2, domain: [-greatestValue, greatestValue], - range: [height, upperRangeValue] + range: isHorizontal ? range : range.reverse() }); } + const domain = [isLogScale ? 0.001 : minValue, maxValue]; + return scaleType({ base: scaleLogarithmicBase || 2, - domain: [isLogScale ? 0.001 : minValue, maxValue], - range: [height, upperRangeValue] - }); -}; - -const getLeftScale = ({ - dataLines, - dataTimeSeries, - valueGraphHeight, - thresholds, - thresholdUnit, - isCenteredZero, - scale, - scaleLogarithmicBase -}: AxeScale): ScaleLinear => { - const [firstUnit, , thirdUnit] = getUnits(dataLines); - - const shouldApplyThresholds = - equals(thresholdUnit, firstUnit) || - equals(thresholdUnit, thirdUnit) || - !thresholdUnit; - - const graphValues = isNil(thirdUnit) - ? getMetricValuesForUnit({ - lines: dataLines, - timeSeries: dataTimeSeries, - unit: firstUnit - }) - : getMetricValuesForLines({ - lines: dataLines, - timeSeries: dataTimeSeries - }); - - const firstUnitHasStackedLines = - isNil(thirdUnit) && not(isNil(firstUnit)) - ? hasUnitStackedLines({ lines: dataLines, unit: firstUnit }) - : false; - - const stackedValues = firstUnitHasStackedLines - ? getStackedMetricValues({ - lines: getSortedStackedLines(dataLines), - timeSeries: dataTimeSeries - }) - : [0]; - - return getScale({ - graphValues, - height: valueGraphHeight, - isCenteredZero, - scale, - scaleLogarithmicBase, - stackedValues, - thresholds: shouldApplyThresholds ? thresholds : [] + domain, + range: isHorizontal ? range : range.reverse() }); }; @@ -449,7 +408,18 @@ const getXScale = ({ }); }; -const getRightScale = ({ +export const getXScaleBand = ({ + dataTime, + valueWidth +}: Xscale): ReturnType> => { + return Scale.scaleBand({ + domain: dataTime.map(getTime), + padding: 0.2, + range: [0, valueWidth] + }); +}; + +const getYScaleUnit = ({ dataLines, dataTimeSeries, valueGraphHeight, @@ -457,33 +427,50 @@ const getRightScale = ({ thresholdUnit, isCenteredZero, scale, - scaleLogarithmicBase -}: AxeScale): ScaleLinear => { - const [, secondUnit] = getUnits(dataLines); + scaleLogarithmicBase, + isHorizontal = true, + unit, + invert +}: AxeScale & { invert?: boolean | string | null; unit: string }): ScaleLinear< + number, + number +> => { + const [firstUnit] = getUnits(dataLines); + const shouldApplyThresholds = + equals(unit, thresholdUnit) || (!thresholdUnit && equals(firstUnit, unit)); const graphValues = getMetricValuesForUnit({ lines: dataLines, timeSeries: dataTimeSeries, - unit: secondUnit + unit }); - const shouldApplyThresholds = equals(thresholdUnit, secondUnit); - - const secondUnitHasStackedLines = isNil(secondUnit) - ? false - : hasUnitStackedLines({ lines: dataLines, unit: secondUnit }); + const hasStackedLines = hasUnitStackedLines({ + lines: dataLines, + unit + }); - const stackedValues = secondUnitHasStackedLines + const stackedValues = hasStackedLines ? getStackedMetricValues({ - lines: getSortedStackedLines(dataLines), + lines: getSortedStackedLines(dataLines).filter( + ({ unit: stackedUnit }) => equals(unit, stackedUnit) + ), timeSeries: dataTimeSeries }) : [0]; return getScale({ graphValues, + hasDisplayAsBar: dataLines.some( + ({ displayAs, unit: lineUnit, stackOrder }) => + equals(unit, lineUnit) && + equals(displayAs, 'bar') && + isNotNil(stackOrder) + ), height: valueGraphHeight, + invert, isCenteredZero, + isHorizontal, scale, scaleLogarithmicBase, stackedValues, @@ -491,6 +478,43 @@ const getRightScale = ({ }); }; +const getYScalePerUnit = ({ + dataLines, + dataTimeSeries, + valueGraphHeight, + thresholds, + thresholdUnit, + isCenteredZero, + scale, + scaleLogarithmicBase, + isHorizontal = true +}: AxeScale): Record> => { + const units = getUnits(dataLines); + + const scalePerUnit = units.reduce((acc, unit) => { + return { + ...acc, + [unit]: getYScaleUnit({ + dataLines, + dataTimeSeries, + invert: dataLines.some( + ({ unit: lineUnit, invert }) => equals(lineUnit, unit) && invert + ), + isCenteredZero, + isHorizontal, + scale, + scaleLogarithmicBase, + thresholdUnit, + thresholds, + unit, + valueGraphHeight + }) + }; + }, {}); + + return scalePerUnit; +}; + const formatTime = (value: number): string => { if (value < 1000) { return `${numeral(value).format('0.[00]a')} ms`; @@ -584,7 +608,7 @@ const formatMetricValueWithUnit = ({ } if (equals('%', unit)) { - return `${numeral(Math.abs(value)).format('0.[00]')}%`; + return `${numeral(value).format('0.[00]')}%`; } const formattedMetricValue = formatMetricValue({ base, unit, value }); @@ -594,29 +618,6 @@ const formatMetricValueWithUnit = ({ : `${formattedMetricValue} ${unit}`; }; -const getStackedYScale = ({ - leftScale, - rightScale -}: YScales): ScaleLinear => { - const minDomain = min( - getMin(leftScale.domain()), - getMin(rightScale.domain()) - ); - const maxDomain = max( - getMax(leftScale.domain()), - getMax(rightScale.domain()) - ); - - const minRange = min(getMin(leftScale.range()), getMin(rightScale.range())); - const maxRange = max(getMax(leftScale.range()), getMax(rightScale.range())); - - return Scale.scaleLinear({ - domain: [minDomain, maxDomain], - nice: true, - range: [maxRange, minRange] - }); -}; - const bisectDate = bisector(identity).center; const getTimeValue = ({ @@ -685,13 +686,12 @@ export { hasUnitStackedLines, getYScale, getScale, - getLeftScale, getXScale, - getRightScale, formatMetricValue, - getStackedYScale, getTimeValue, bisectDate, getMetricWithLatestData, - formatMetricValueWithUnit + formatMetricValueWithUnit, + getYScaleUnit, + getYScalePerUnit }; diff --git a/centreon/packages/ui/src/Graph/common/timeSeries/models.ts b/centreon/packages/ui/src/Graph/common/timeSeries/models.ts index 0f8cb9802c..d35fa62cac 100644 --- a/centreon/packages/ui/src/Graph/common/timeSeries/models.ts +++ b/centreon/packages/ui/src/Graph/common/timeSeries/models.ts @@ -1,6 +1,6 @@ import { ScaleLinear, ScaleTime } from 'd3-scale'; -import { LineChartAxis } from '../../LineChart/models'; +import { ChartAxis } from '../../Chart/models'; interface DsData { ds_color_area: string; @@ -19,6 +19,7 @@ export interface Metric { critical_high_threshold: number | null; critical_low_threshold: number | null; data: Array; + displayAs?: 'line' | 'bar'; ds_data?: DsData; legend: string; maximum_value: number | null; @@ -41,6 +42,7 @@ export interface Line { average_value: number | null; color: string; display: boolean; + displayAs?: 'line' | 'bar'; filled: boolean; highlight?: boolean; invert: string | null; @@ -70,12 +72,10 @@ export interface Xscale { valueWidth: number; } export interface AxeScale - extends Pick< - LineChartAxis, - 'isCenteredZero' | 'scale' | 'scaleLogarithmicBase' - > { + extends Pick { dataLines: Array; dataTimeSeries: Array; + isHorizontal?: boolean; thresholdUnit?: string; thresholds: Array; valueGraphHeight: number; diff --git a/centreon/packages/ui/src/Graph/common/useTooltipStyles.ts b/centreon/packages/ui/src/Graph/common/useTooltipStyles.ts new file mode 100644 index 0000000000..02c6895c4c --- /dev/null +++ b/centreon/packages/ui/src/Graph/common/useTooltipStyles.ts @@ -0,0 +1,18 @@ +import { makeStyles } from 'tss-react/mui'; + +export const useTooltipStyles = makeStyles()((theme) => ({ + tooltip: { + backgroundColor: theme.palette.background.paper, + borderRadius: theme.shape.borderRadius, + boxShadow: theme.shadows[3], + color: theme.palette.text.primary, + fontSize: theme.typography.caption.fontSize, + fontWeight: theme.typography.caption.fontWeight, + maxWidth: 'none', + padding: theme.spacing(0.5, 1) + }, + tooltipChildren: { height: '100%', width: '100%' }, + tooltipDisablePadding: { + padding: theme.spacing(0) + } +})); diff --git a/centreon/packages/ui/src/Graph/common/utils.ts b/centreon/packages/ui/src/Graph/common/utils.ts index 1e3924bd1c..336d0648c8 100644 --- a/centreon/packages/ui/src/Graph/common/utils.ts +++ b/centreon/packages/ui/src/Graph/common/utils.ts @@ -1,3 +1,4 @@ +import numeral from 'numeral'; import { T, always, @@ -12,9 +13,8 @@ import { lte, pluck } from 'ramda'; -import numeral from 'numeral'; -import { darken, getLuminance, lighten, Theme } from '@mui/material'; +import { Theme, darken, getLuminance, lighten } from '@mui/material'; import { Thresholds } from './models'; @@ -172,3 +172,9 @@ export const getStrokeDashArray = ({ export const getPointRadius = (lineWidth?: number): number => Math.max(Math.ceil((lineWidth ?? 2) * 1.2), 2); + +export const commonTickLabelProps = { + fontFamily: 'Roboto, sans-serif', + fontSize: 10, + textAnchor: 'middle' +}; diff --git a/centreon/packages/ui/src/Graph/index.ts b/centreon/packages/ui/src/Graph/index.ts index ef8feaaf59..e32038eb7a 100644 --- a/centreon/packages/ui/src/Graph/index.ts +++ b/centreon/packages/ui/src/Graph/index.ts @@ -1,4 +1,7 @@ -export { default as LineChart } from './LineChart'; +export { default as LineChart } from './Chart'; +export { default as ThresholdLines } from './Chart/BasicComponents/Lines/Threshold'; +export { default as useLineChartData } from './Chart/useChartData'; +export { default as BarChart } from './BarChart/BarChart'; export { Gauge } from './Gauge'; export { SingleBar } from './SingleBar'; export { Text as GraphText } from './Text'; @@ -7,3 +10,8 @@ export { HeatMap } from './HeatMap'; export { BarStack } from './BarStack'; export { PieChart } from './PieChart'; export * from './Tree'; +export type { LineChartData } from './common/models'; +export * from './common/timeSeries'; +export type { Metric } from './common/timeSeries/models'; +export * from './Chart/models'; +export * from './PieChart/models'; diff --git a/centreon/packages/ui/src/Graph/mockedData/annotationData.json b/centreon/packages/ui/src/Graph/mockedData/annotationData.json new file mode 100644 index 0000000000..eb8ddd1d2e --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/annotationData.json @@ -0,0 +1,324 @@ +{ + "result": [ + { + "id": 78662735, + "type": "comment", + "date": "2023-06-07T20:07:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 85.149% (memory used)", + "contact": "nouha", + "status": { + "code": 0, + "name": "OK", + "severity_code": 5 + }, + "tries": 1 + }, + { + "id": 78662642, + "type": "comment", + "date": "2023-06-07T19:57:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 84.908% (memory used)", + "contact": "nouha", + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 3 + }, + { + "id": 78662621, + "type": "comment", + "date": "2023-06-07T19:56:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 82.956% (memory used)", + "contact": "nouha", + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 2 + }, + { + "id": 78662612, + "type": "downtime", + "date": "2023-06-07T19:55:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 84.341% (memory used)", + "contact": "nouha", + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 1 + }, + { + "id": 78662414, + "type": "downtime", + "date": "2023-06-07T19:45:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 85.217% (memory used)", + "contact": null, + "status": { + "code": 0, + "name": "OK", + "severity_code": 5 + }, + "tries": 1 + }, + { + "id": 78661672, + "type": "downtime", + "date": "2023-06-07T19:05:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 84.467% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 3 + }, + { + "id": 78661660, + "type": "acknowledgement", + "date": "2023-06-07T19:04:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 83.731% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 2 + }, + { + "id": 78661625, + "type": "acknowledgement", + "date": "2023-06-07T19:03:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 84.825% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 1 + }, + { + "id": 78659281, + "type": "acknowledgement", + "date": "2023-06-07T17:18:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 86.132% (memory used)", + "contact": null, + "status": { + "code": 0, + "name": "OK", + "severity_code": 5 + }, + "tries": 1 + }, + { + "id": 78658829, + "type": "acknowledgement", + "date": "2023-06-07T16:58:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 82.638% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 3 + }, + { + "id": 78658821, + "type": "event", + "date": "2023-06-07T16:57:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 83.353% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 2 + }, + { + "id": 78658804, + "type": "event", + "date": "2023-06-07T16:56:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 84.231% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 1 + }, + { + "id": 78658665, + "type": "event", + "date": "2023-06-07T16:51:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 85.792% (memory used)", + "contact": null, + "status": { + "code": 0, + "name": "OK", + "severity_code": 5 + }, + "tries": 1 + }, + { + "id": 78650736, + "type": "event", + "date": "2023-06-07T11:06:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 81.780% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 3 + }, + { + "id": 78650731, + "type": "event", + "date": "2023-06-07T11:05:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 82.828% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 2 + }, + { + "id": 78650689, + "type": "event", + "date": "2023-06-07T11:04:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 84.561% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 1 + }, + { + "id": 78650260, + "type": "event", + "date": "2023-06-07T10:44:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 85.529% (memory used)", + "contact": null, + "status": { + "code": 0, + "name": "OK", + "severity_code": 5 + }, + "tries": 1 + }, + { + "id": 78650158, + "type": "event", + "date": "2023-06-07T10:39:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 84.905% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 3 + }, + { + "id": 78650096, + "type": "event", + "date": "2023-06-07T10:38:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 84.210% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 2 + }, + { + "id": 78650057, + "type": "event", + "date": "2023-06-07T10:37:28+02:00", + "start_date": null, + "end_date": null, + "content": "Shared pool hit ratio = 83.771% (memory used)", + "contact": null, + "status": { + "code": 1, + "name": "WARNING", + "severity_code": 2 + }, + "tries": 1 + } + ], + "meta": { + "page": 1, + "limit": 20, + "search": { + "$and": [ + { + "date": { + "$gt": "2023-06-06T19:27:15.554Z" + } + }, + { + "date": { + "$lt": "2023-06-07T19:27:15.554Z" + } + } + ] + }, + "sort_by": {}, + "total": 44 + } +} diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/curvesWithSameColor.json b/centreon/packages/ui/src/Graph/mockedData/curvesWithSameColor.json similarity index 99% rename from centreon/packages/ui/src/Graph/LineChart/mockedData/curvesWithSameColor.json rename to centreon/packages/ui/src/Graph/mockedData/curvesWithSameColor.json index 3ac76c0d0a..ed0bc2aa69 100644 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/curvesWithSameColor.json +++ b/centreon/packages/ui/src/Graph/mockedData/curvesWithSameColor.json @@ -249,4 +249,4 @@ "2024-05-10T10:15:00+02:00", "2024-05-10T10:20:00+02:00" ] -} \ No newline at end of file +} diff --git a/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodFirstPeriod.json b/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodFirstPeriod.json new file mode 100644 index 0000000000..10e217423c --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodFirstPeriod.json @@ -0,0 +1,368 @@ +{ + "global": { + "title": "anomaly-nbr-connect graph on fw-brasilia", + "start": "2023-06-14T21:02:27+02:00", + "end": "2023-06-15T00:02:58+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 1, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 152032, + "metric_id": 15165, + "metric": "connection", + "metric_legend": "connection", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#993366" + }, + "legend": "connection", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 22.203333333, 27.576666667, 27.406666667, 22.22, 25.78, 15.846666667, + 15.39, 22.373333333, 20.813333333, 23.983333333, 28.186666667, 26.61, + 26, 22.813333333, 18.016666667, 13.813333333, 16.186666667, + 17.796666667, 21.983333333, 14.236666667, 23.153333333, 17.236666667, + 15, 20.576666667, 22.796666667, 27.78, 28.203333333, 27.203333333, + 14.253333333, 13.39, 21.17, 19.813333333, 22.186666667, 14.236666667, + 22.356666667, 15.44, 14.593333333 + ], + "prints": [ + ["Last:14.59"], + ["Min:13.39"], + ["Max:28.20"], + ["Average:20.77"] + ], + "last_value": 14.59, + "minimum_value": 13.39, + "maximum_value": 28.2, + "average_value": 20.77 + }, + { + "index_id": 152032, + "metric_id": 16196, + "metric": "connection_fit", + "metric_legend": "connection_fit", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#9933ff" + }, + "legend": "connection_fit", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 19.3527, 19.1427, 18.964566667, 18.93, 18.93, 18.93, 18.93, 18.93, + 18.969833333, 19.139333333, 19.3473, 19.493566667, 19.3527, 19.1427, + 18.964566667, 18.93, 18.93, 18.93, 18.93, 18.93, 18.969833333, + 19.139333333, 19.3473, 19.493566667, 19.3527, 19.1427, 18.964566667, + 18.93, 18.93, 18.93, 18.93, 18.93, 18.969833333, 19.139333333, 19.3473, + 19.493566667, 19.3527 + ], + "prints": [ + ["Last:19.35"], + ["Min:18.93"], + ["Max:19.49"], + ["Average:19.10"] + ], + "last_value": 19.35, + "minimum_value": 18.93, + "maximum_value": 19.49, + "average_value": 19.1 + }, + { + "index_id": 152032, + "metric_id": 16197, + "metric": "connection_lower_margin", + "metric_legend": "connection_lower_margin", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#00ff99" + }, + "legend": "connection_lower_margin", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, + -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, + -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, + -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, + -17.88 + ], + "prints": [ + ["Last:-17.88"], + ["Min:-17.88"], + ["Max:-17.88"], + ["Average:-17.88"] + ], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + }, + { + "index_id": 152032, + "metric_id": 16198, + "metric": "connection_upper_margin", + "metric_legend": "connection_upper_margin", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#9900ff" + }, + "legend": "connection_upper_margin", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, + 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, + 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, + 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15 + ], + "prints": [ + ["Last:10.15"], + ["Min:10.15"], + ["Max:10.15"], + ["Average:10.15"] + ], + "last_value": 10.15, + "minimum_value": 10.15, + "maximum_value": 10.15, + "average_value": 10.15 + }, + { + "index_id": 152032, + "metric_id": 15177, + "metric": "connection_lower_thresholds", + "metric_legend": "connection_lower_thresholds", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 50, + "host_id": null, + "service_id": null, + "name": "Anomaly Lower Threshold", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": ".*_lower_thresholds", + "ds_color_line": "#D728C9", + "ds_color_line_mode": "0", + "ds_color_area": "#FFFFFF", + "ds_color_area_warn": "#F8C706", + "ds_color_area_crit": "#F91E05", + "ds_filled": null, + "ds_max": null, + "ds_min": null, + "ds_minmax_int": null, + "ds_average": null, + "ds_last": null, + "ds_total": null, + "ds_tickness": 2, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": "Lower Threshold", + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "Lower Threshold", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + -34.2873, -34.4973, -34.667466667, -34.7, -34.7, -34.7, -34.7, -34.7, + -34.668133333, -34.4927, -34.2827, -34.1444, -34.2873, -34.4973, + -34.667466667, -34.7, -34.7, -34.7, -34.7, -34.7, -34.668133333, + -34.4927, -34.2827, -34.1444, -34.2873, -34.4973, -34.667466667, -34.7, + -34.7, -34.7, -34.7, -34.7, -34.668133333, -34.4927, -34.2827, -34.1444, + -34.2873 + ], + "prints": [], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + }, + { + "index_id": 152032, + "metric_id": 15178, + "metric": "connection_upper_thresholds", + "metric_legend": "connection_upper_thresholds", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 51, + "host_id": null, + "service_id": null, + "name": "Anomaly Upper Threshold", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": ".*_upper_thresholds", + "ds_color_line": "#D728C9", + "ds_color_line_mode": "0", + "ds_color_area": "#FFFFFF", + "ds_color_area_warn": "#F8C706", + "ds_color_area_crit": "#F91E05", + "ds_filled": null, + "ds_max": null, + "ds_min": null, + "ds_minmax_int": null, + "ds_average": null, + "ds_last": null, + "ds_total": null, + "ds_tickness": 2, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": "Upper Threshold", + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "Upper Threshold", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + 49.810666667, 49.6027, 49.424566667, 49.39, 49.39, 49.39, 49.39, 49.39, + 49.421866667, 49.5973, 49.8073, 49.9456, 49.810666667, 49.6027, + 49.424566667, 49.39, 49.39, 49.39, 49.39, 49.39, 49.421866667, 49.5973, + 49.8073, 49.9456, 49.810666667, 49.6027, 49.424566667, 49.39, 49.39, + 49.39, 49.39, 49.39, 49.421866667, 49.5973, 49.8073, 49.9456, + 49.810666667 + ], + "prints": [], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2023-06-14T21:05:00+02:00", + "2023-06-14T21:10:00+02:00", + "2023-06-14T21:15:00+02:00", + "2023-06-14T21:20:00+02:00", + "2023-06-14T21:25:00+02:00", + "2023-06-14T21:30:00+02:00", + "2023-06-14T21:35:00+02:00", + "2023-06-14T21:40:00+02:00", + "2023-06-14T21:45:00+02:00", + "2023-06-14T21:50:00+02:00", + "2023-06-14T21:55:00+02:00", + "2023-06-14T22:00:00+02:00", + "2023-06-14T22:05:00+02:00", + "2023-06-14T22:10:00+02:00", + "2023-06-14T22:15:00+02:00", + "2023-06-14T22:20:00+02:00", + "2023-06-14T22:25:00+02:00", + "2023-06-14T22:30:00+02:00", + "2023-06-14T22:35:00+02:00", + "2023-06-14T22:40:00+02:00", + "2023-06-14T22:45:00+02:00", + "2023-06-14T22:50:00+02:00", + "2023-06-14T22:55:00+02:00", + "2023-06-14T23:00:00+02:00", + "2023-06-14T23:05:00+02:00", + "2023-06-14T23:10:00+02:00", + "2023-06-14T23:15:00+02:00", + "2023-06-14T23:20:00+02:00", + "2023-06-14T23:25:00+02:00", + "2023-06-14T23:30:00+02:00", + "2023-06-14T23:35:00+02:00", + "2023-06-14T23:40:00+02:00", + "2023-06-14T23:45:00+02:00", + "2023-06-14T23:50:00+02:00", + "2023-06-14T23:55:00+02:00", + "2023-06-15T00:00:00+02:00", + "2023-06-15T00:05:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodSecondPeriod.json b/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodSecondPeriod.json new file mode 100644 index 0000000000..02bfbdc10d --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodSecondPeriod.json @@ -0,0 +1,372 @@ +{ + "global": { + "title": "anomaly-nbr-connect graph on fw-brasilia", + "start": "2023-06-15T12:02:17+02:00", + "end": "2023-06-15T15:00:01+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 1, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 152032, + "metric_id": 15165, + "metric": "connection", + "metric_legend": "connection", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#993366" + }, + "legend": "connection", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 90.506666667, 124.84, 131.21333333, 175.1, 155.07333333, 116.39333333, + 101.31333333, 141.41333333, 156.46, 131.38, 162.25333333, 182.70666667, + 181.82, 124.62, 96.646666667, 96.413333333, 124.22, 146.96666667, + 140.75333333, 106.12, 144.83333333, 152.43333333, 97.293333333, 96.44, + 142.32, 142.33333333, 103.74, 118.54, 145.55333333, 122.16666667, + 109.15333333, 134.74666667, 117.19333333, 122.83333333, 152.28, + 170.50666667, 93.506666667 + ], + "prints": [ + ["Last:93.51"], + ["Min:90.51"], + ["Max:182.71"], + ["Average:131.14"] + ], + "last_value": 93.51, + "minimum_value": 90.51, + "maximum_value": 182.71, + "average_value": 131.14 + }, + { + "index_id": 152032, + "metric_id": 16196, + "metric": "connection_fit", + "metric_legend": "connection_fit", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#9933ff" + }, + "legend": "connection_fit", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 131.36, 131.36, 131.35613333, 131.3342, 131.3042, 131.2974, + 131.38933333, 131.49126667, 131.57226667, 131.52453333, 131.4426, + 131.36806667, 131.36, 131.36, 131.35613333, 131.3342, 131.3042, + 131.2974, 131.38933333, 131.49126667, 131.57226667, 131.52453333, + 131.4426, 131.36806667, 131.36, 131.36, 131.35613333, 131.3342, + 131.3042, 131.2974, 131.38933333, 131.49126667, 131.59546667, + 131.67353333, 131.7416, 131.79193333, 131.8 + ], + "prints": [ + ["Last:131.80"], + ["Min:131.30"], + ["Max:131.80"], + ["Average:131.44"] + ], + "last_value": 131.8, + "minimum_value": 131.3, + "maximum_value": 131.8, + "average_value": 131.44 + }, + { + "index_id": 152032, + "metric_id": 16197, + "metric": "connection_lower_margin", + "metric_legend": "connection_lower_margin", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#00ff99" + }, + "legend": "connection_lower_margin", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, + -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, + -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, + -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, -92.84, + -92.84 + ], + "prints": [ + ["Last:-92.84"], + ["Min:-92.84"], + ["Max:-92.84"], + ["Average:-92.84"] + ], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + }, + { + "index_id": 152032, + "metric_id": 16198, + "metric": "connection_upper_margin", + "metric_legend": "connection_upper_margin", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#9900ff" + }, + "legend": "connection_upper_margin", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, + 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, + 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, + 80.19, 80.19, 80.19, 80.19, 80.19, 80.19, 80.19 + ], + "prints": [ + ["Last:80.19"], + ["Min:80.19"], + ["Max:80.19"], + ["Average:80.19"] + ], + "last_value": 80.19, + "minimum_value": 80.19, + "maximum_value": 80.19, + "average_value": 80.19 + }, + { + "index_id": 152032, + "metric_id": 15177, + "metric": "connection_lower_thresholds", + "metric_legend": "connection_lower_thresholds", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 50, + "host_id": null, + "service_id": null, + "name": "Anomaly Lower Threshold", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": ".*_lower_thresholds", + "ds_color_line": "#D728C9", + "ds_color_line_mode": "0", + "ds_color_area": "#FFFFFF", + "ds_color_area_warn": "#F8C706", + "ds_color_area_crit": "#F91E05", + "ds_filled": null, + "ds_max": null, + "ds_min": null, + "ds_minmax_int": null, + "ds_average": null, + "ds_last": null, + "ds_total": null, + "ds_tickness": 2, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": "Lower Threshold", + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "Lower Threshold", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + -147.17, -147.17, -147.17386667, -147.1958, -147.22386667, + -147.22453333, -147.13873333, -147.02873333, -146.94966667, + -147.00546667, -147.08546667, -147.15386667, -147.17, -147.17, + -147.17386667, -147.1958, -147.22386667, -147.22453333, -147.13873333, + -147.02873333, -146.94966667, -147.00546667, -147.08546667, + -147.15386667, -147.17, -147.17, -147.17386667, -147.1958, + -147.22386667, -147.22453333, -147.13873333, -147.02873333, + -146.92453333, -146.8484, -146.78646667, -146.72806667, -146.72 + ], + "prints": [], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + }, + { + "index_id": 152032, + "metric_id": 15178, + "metric": "connection_upper_thresholds", + "metric_legend": "connection_upper_thresholds", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 51, + "host_id": null, + "service_id": null, + "name": "Anomaly Upper Threshold", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": ".*_upper_thresholds", + "ds_color_line": "#D728C9", + "ds_color_line_mode": "0", + "ds_color_area": "#FFFFFF", + "ds_color_area_warn": "#F8C706", + "ds_color_area_crit": "#F91E05", + "ds_filled": null, + "ds_max": null, + "ds_min": null, + "ds_minmax_int": null, + "ds_average": null, + "ds_last": null, + "ds_total": null, + "ds_tickness": 2, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": "Upper Threshold", + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "Upper Threshold", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + 371.92, 371.92, 371.91613333, 371.8942, 371.8642, 371.8574, + 371.95126667, 372.06126667, 372.14033333, 372.08453333, 372.0026, + 371.92806667, 371.92, 371.92, 371.91613333, 371.8942, 371.8642, + 371.8574, 371.95126667, 372.06126667, 372.14033333, 372.08453333, + 372.0026, 371.92806667, 371.92, 371.92, 371.91613333, 371.8942, + 371.8642, 371.8574, 371.95126667, 372.06126667, 372.16353333, + 372.23353333, 372.3016, 372.35386667, 372.37 + ], + "prints": [], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2023-06-15T12:05:00+02:00", + "2023-06-15T12:10:00+02:00", + "2023-06-15T12:15:00+02:00", + "2023-06-15T12:20:00+02:00", + "2023-06-15T12:25:00+02:00", + "2023-06-15T12:30:00+02:00", + "2023-06-15T12:35:00+02:00", + "2023-06-15T12:40:00+02:00", + "2023-06-15T12:45:00+02:00", + "2023-06-15T12:50:00+02:00", + "2023-06-15T12:55:00+02:00", + "2023-06-15T13:00:00+02:00", + "2023-06-15T13:05:00+02:00", + "2023-06-15T13:10:00+02:00", + "2023-06-15T13:15:00+02:00", + "2023-06-15T13:20:00+02:00", + "2023-06-15T13:25:00+02:00", + "2023-06-15T13:30:00+02:00", + "2023-06-15T13:35:00+02:00", + "2023-06-15T13:40:00+02:00", + "2023-06-15T13:45:00+02:00", + "2023-06-15T13:50:00+02:00", + "2023-06-15T13:55:00+02:00", + "2023-06-15T14:00:00+02:00", + "2023-06-15T14:05:00+02:00", + "2023-06-15T14:10:00+02:00", + "2023-06-15T14:15:00+02:00", + "2023-06-15T14:20:00+02:00", + "2023-06-15T14:25:00+02:00", + "2023-06-15T14:30:00+02:00", + "2023-06-15T14:35:00+02:00", + "2023-06-15T14:40:00+02:00", + "2023-06-15T14:45:00+02:00", + "2023-06-15T14:50:00+02:00", + "2023-06-15T14:55:00+02:00", + "2023-06-15T15:00:00+02:00", + "2023-06-15T15:05:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodThirdPeriod.json b/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodThirdPeriod.json new file mode 100644 index 0000000000..ab82c2207d --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/exclusionPeriodThirdPeriod.json @@ -0,0 +1,367 @@ +{ + "global": { + "title": "anomaly-nbr-connect graph on fw-brasilia", + "start": "2023-06-15T06:00:41+02:00", + "end": "2023-06-15T08:58:26+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 1, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 152032, + "metric_id": 15165, + "metric": "connection", + "metric_legend": "connection", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#993366" + }, + "legend": "connection", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 11, 18.933333333, 25.76, 15.1, 15.173333333, 21.553333333, 27.76, 24.24, + 15.86, 17.966666667, 24.553333333, 16.48, 24.313333333, 22.24, + 22.586666667, 27.76, 18.686666667, 19.966666667, 23.38, 13.686666667, + 23.693333333, 23.033333333, 25.173333333, 22.826666667, 19.62, 11.86, + 17.14, 18.206666667, 19.586666667, 26.346666667, 28.793333333, + 18.686666667, 11.24, 16.346666667, 15.62, 83.226666667 + ], + "prints": [ + ["Last:83.23"], + ["Min:11.00"], + ["Max:83.23"], + ["Average:21.90"] + ], + "last_value": 83.23, + "minimum_value": 11, + "maximum_value": 83.23, + "average_value": 21.9 + }, + { + "index_id": 152032, + "metric_id": 16196, + "metric": "connection_fit", + "metric_legend": "connection_fit", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#9933ff" + }, + "legend": "connection_fit", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 19.97, 19.97, 19.97, 19.977933333, 19.987933333, 20.005866667, + 20.065533333, 20.1276, 20.179666667, 20.150333333, 20.108266667, + 20.0762, 20.07, 20.07, 20.07, 20.077933333, 20.087933333, 20.105866667, + 20.165533333, 20.2276, 20.24, 20.041666667, 19.783733333, 19.571333333, + 19.53, 19.53, 19.537933333, 19.547933333, 19.557933333, 19.567933333, + 19.5938, 19.631733333, 19.8304, 20.7368, 21.808866667, 27.519866667 + ], + "prints": [ + ["Last:27.52"], + ["Min:19.53"], + ["Max:27.52"], + ["Average:20.21"] + ], + "last_value": 27.52, + "minimum_value": 19.53, + "maximum_value": 27.52, + "average_value": 20.21 + }, + { + "index_id": 152032, + "metric_id": 16197, + "metric": "connection_lower_margin", + "metric_legend": "connection_lower_margin", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#00ff99" + }, + "legend": "connection_lower_margin", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, + -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, + -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, + -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -17.88, -21.9736 + ], + "prints": [ + ["Last:-21.97"], + ["Min:-21.97"], + ["Max:-17.88"], + ["Average:-17.99"] + ], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + }, + { + "index_id": 152032, + "metric_id": 16198, + "metric": "connection_upper_margin", + "metric_legend": "connection_upper_margin", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#9900ff" + }, + "legend": "connection_upper_margin", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, + 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, + 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, 10.15, + 10.15, 10.15, 10.15, 10.15, 10.15, 13.9818 + ], + "prints": [ + ["Last:13.98"], + ["Min:10.15"], + ["Max:13.98"], + ["Average:10.26"] + ], + "last_value": 13.98, + "minimum_value": 10.15, + "maximum_value": 13.98, + "average_value": 10.26 + }, + { + "index_id": 152032, + "metric_id": 15177, + "metric": "connection_lower_thresholds", + "metric_legend": "connection_lower_thresholds", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 50, + "host_id": null, + "service_id": null, + "name": "Anomaly Lower Threshold", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": ".*_lower_thresholds", + "ds_color_line": "#D728C9", + "ds_color_line_mode": "0", + "ds_color_area": "#FFFFFF", + "ds_color_area_warn": "#F8C706", + "ds_color_area_crit": "#F91E05", + "ds_filled": null, + "ds_max": null, + "ds_min": null, + "ds_minmax_int": null, + "ds_average": null, + "ds_last": null, + "ds_total": null, + "ds_tickness": 2, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": "Lower Threshold", + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "Lower Threshold", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + -33.67, -33.67, -33.67, -33.662066667, -33.652066667, -33.6262, + -33.5724, -33.504466667, -33.458266667, -33.481733333, -33.529666667, + -33.5638, -33.57, -33.57, -33.57, -33.562066667, -33.552066667, + -33.5262, -33.4724, -33.404466667, -33.39, -33.596266667, -33.848333333, + -34.058666667, -34.1, -34.1, -34.1, -34.092066667, -34.082066667, + -34.064133333, -34.0362, -34.0062, -33.801666667, -32.901133333, + -31.831133333, -38.408866667 + ], + "prints": [], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + }, + { + "index_id": 152032, + "metric_id": 15178, + "metric": "connection_upper_thresholds", + "metric_legend": "connection_upper_thresholds", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 51, + "host_id": null, + "service_id": null, + "name": "Anomaly Upper Threshold", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": ".*_upper_thresholds", + "ds_color_line": "#D728C9", + "ds_color_line_mode": "0", + "ds_color_area": "#FFFFFF", + "ds_color_area_warn": "#F8C706", + "ds_color_area_crit": "#F91E05", + "ds_filled": null, + "ds_max": null, + "ds_min": null, + "ds_minmax_int": null, + "ds_average": null, + "ds_last": null, + "ds_total": null, + "ds_tickness": 2, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": "Upper Threshold", + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "Upper Threshold", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + 50.42, 50.42, 50.427933333, 50.437933333, 50.447933333, 50.465866667, + 50.525533333, 50.5876, 50.631733333, 50.608266667, 50.568266667, + 50.528266667, 50.52, 50.52, 50.527933333, 50.537933333, 50.547933333, + 50.565866667, 50.625533333, 50.6876, 50.7, 50.501666667, 50.243733333, + 50.031333333, 49.99, 49.99, 49.99, 49.997933333, 50.007933333, + 50.025866667, 50.0538, 50.0838, 50.288333333, 51.188866667, 52.2668, + 69.4594 + ], + "prints": [], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2023-06-15T06:05:00+02:00", + "2023-06-15T06:10:00+02:00", + "2023-06-15T06:15:00+02:00", + "2023-06-15T06:20:00+02:00", + "2023-06-15T06:25:00+02:00", + "2023-06-15T06:30:00+02:00", + "2023-06-15T06:35:00+02:00", + "2023-06-15T06:40:00+02:00", + "2023-06-15T06:45:00+02:00", + "2023-06-15T06:50:00+02:00", + "2023-06-15T06:55:00+02:00", + "2023-06-15T07:00:00+02:00", + "2023-06-15T07:05:00+02:00", + "2023-06-15T07:10:00+02:00", + "2023-06-15T07:15:00+02:00", + "2023-06-15T07:20:00+02:00", + "2023-06-15T07:25:00+02:00", + "2023-06-15T07:30:00+02:00", + "2023-06-15T07:35:00+02:00", + "2023-06-15T07:40:00+02:00", + "2023-06-15T07:45:00+02:00", + "2023-06-15T07:50:00+02:00", + "2023-06-15T07:55:00+02:00", + "2023-06-15T08:00:00+02:00", + "2023-06-15T08:05:00+02:00", + "2023-06-15T08:10:00+02:00", + "2023-06-15T08:15:00+02:00", + "2023-06-15T08:20:00+02:00", + "2023-06-15T08:25:00+02:00", + "2023-06-15T08:30:00+02:00", + "2023-06-15T08:35:00+02:00", + "2023-06-15T08:40:00+02:00", + "2023-06-15T08:45:00+02:00", + "2023-06-15T08:50:00+02:00", + "2023-06-15T08:55:00+02:00", + "2023-06-15T09:00:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/lastDay.json b/centreon/packages/ui/src/Graph/mockedData/lastDay.json new file mode 100644 index 0000000000..2859c9fac3 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/lastDay.json @@ -0,0 +1,1292 @@ +{ + "global": { + "title": "oracle-buffer-hit-ratio graph on srv-oracle-users", + "start": "2023-06-18T17:04:46+02:00", + "end": "2023-06-19T17:04:46+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 0, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 5614, + "metric_id": 13536, + "metric": "connTime", + "metric_legend": "connTime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#6699cc" + }, + "legend": "connTime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.53123333333, + 0.56452, + 0.5341, + 0.51537666667, + 0.25730333333, + 0.48611333333, + 0.41435666667, + 0.42371, + 0.55438333333, + 0.60211, + 0.72619, + 0.67167333333, + 0.63883333333, + 0.52027666667, + 0.67368666667, + 0.83443333333, + 0.86102333333, + 0.76291666667, + 0.39081666667, + 0.22492333333, + 0.64388333333, + 0.81007666667, + 0.61811333333, + 0.58901, + 0.58737333333, + 0.60651333333, + 0.74783333333, + 0.92823, + 0.89503333333, + 0.82551333333, + 0.75017333333, + 0.33549666667, + 0.40213666667, + 0.60645666667, + 0.55312666667, + 0.31503666667, + 0.078203333333, + 0.44113, + 0.35953666667, + 0.41073333333, + 0.8358, + 0.86683333333, + 0.68390666667, + 0.28047333333, + 0.0607, + 0.49994666667, + 0.75459666667, + 0.51677333333, + 0.63137, + 0.74141666667, + 0.60566666667, + 0.32040666667, + 0.15528666667, + 0.43645333333, + 0.65261666667, + 0.46921666667, + 0.60091666667, + 0.47360333333, + 0.10643, + 0.29183, + 0.35995, + 0.40254333333, + 0.58827666667, + 0.45241333333, + 0.24455333333, + 0.18674, + 0.13640333333, + 0.34897666667, + 0.55044, + 0.52277666667, + 0.69064333333, + 0.56236333333, + 0.39762, + 0.65475666667, + 0.58477, + 0.49433, + 0.28894333333, + 0.49294333333, + 0.64683, + 0.35607666667, + 0.55465, + 0.45637333333, + 0.54171666667, + 0.42502666667, + 0.30588, + 0.32094, + 0.22269333333, + 0.44262, + 0.62073333333, + 0.60227666667, + 0.32498333333, + 0.25148, + 0.47383333333, + 0.30778333333, + 0.26413666667, + 0.58817, + 0.42611, + 0.44147, + 0.70327, + 0.61590333333, + 0.67324333333, + 0.71732333333, + 0.38394, + 0.23022, + 0.32007333333, + 0.37968, + 0.32084666667, + 0.54738333333, + 0.85402666667, + 0.72061666667, + 0.69251666667, + 0.87611666667, + 0.83591333333, + 0.36148, + 0.45470333333, + 0.68843, + 0.52516, + 0.50904666667, + 0.51209333333, + 0.6553, + 0.85674333333, + 0.51166, + 0.4353, + 0.76875333333, + 0.78365666667, + 0.71250666667, + 0.81178666667, + 0.67356666667, + 0.48919333333, + 0.55755, + 0.50259333333, + 0.28751333333, + 0.56895666667, + 0.46348666667, + 0.065866666667, + 0.56505666667, + 0.90545333333, + 0.80578666667, + 0.5926, + 0.60521333333, + 0.80492333333, + 0.46766666667, + 0.45899, + 0.67702333333, + 0.35113666667, + 0.47643666667, + 0.71041666667, + 0.55792, + 0.73992, + 0.76518, + 0.35002333333, + 0.26003, + 0.55407333333, + 0.76546333333, + 0.37679, + 0.067946666667, + 0.34679, + 0.26, + 0.66257333333, + 0.40848, + 0.53458333333, + 0.51552, + 0.61109, + 0.85858333333, + 0.68362, + 0.27503333333, + 0.2019, + 0.13221333333, + 0.79457, + 0.69949666667, + 0.35275333333, + 0.81529, + 0.078553333333, + 0.03339, + 0.39325333333, + 0.40176333333, + 0.14054333333, + 0.32028666667, + 0.33053666667, + 0.89415666667, + 0.35837666667, + 0.85846, + 0.44418, + 0.29612333333, + 0.84746333333, + 0.69179, + 0.15608666667, + 0.46017333333, + 0.52039333333, + 0.04379, + 0.20713333333, + 0.69767, + 0.073123333333, + 0.72342666667, + 0.16706, + 0.56104666667, + 0.7642, + 0.84448, + 0.12149, + 0.84398666667, + 0.17495, + 0.73171, + 0.31948666667, + 0.86547, + 0.51050333333, + 0.73184, + 0.24332, + 0.64512333333, + 0.87497666667, + 0.64631666667, + 0.93808666667, + 0.40630666667, + 0.58898666667, + 0.079853333333, + 0.52536666667, + 0.24560333333, + 0.08881, + 0.59968333333, + 0.76672666667, + 0.12605, + 0.57891, + 0.3994, + 0.93223, + 0.91706, + 0.73287333333, + 0.35697666667, + 0.76189, + 0.53946666667, + 0.80423333333, + 0.89725, + 0.11539666667, + 0.29745333333, + 0.77966666667, + 0.71089333333, + 0.26618666667, + 0.66581333333, + 0.72693, + 0.2858, + 0.21299, + 0.19799666667, + 0.73068666667, + 0.48692, + 0.5738, + 0.060393333333, + 0.36694333333, + 0.29905, + 0.70373, + 0.59026666667, + 0.95010333333, + 0.96899666667, + 0.18778333333, + 0.44893666667, + 0.54063333333, + 0.30962666667, + 0.67226, + 0.8979, + 0.61484, + 0.75435333333, + 0.21677, + 0.25687, + 0.73120666667, + 0.20676666667, + 0.32435333333, + 0.44787666667, + 0.89004333333, + 0.48926333333, + 0.36620666667, + 0.53720333333, + 0.77175333333, + 0.81031333333, + 0.68735, + 0.29566333333, + 0.64441333333, + 0.53196, + 0.57447666667, + 0.050853333333, + 0.28769333333, + 0.17988666667, + 0.10621333333, + 0.49249333333, + 0.81975, + 0.48222, + 0.25617333333, + 0.75395, + 0.36961, + 0.53932333333, + 0.65789666667, + 0.32339333333, + null + ], + "prints": [["Last:0.32"], ["Min:0.03"], ["Max:0.97"], ["Average:0.51"]], + "last_value": 0.32, + "minimum_value": 0.03, + "maximum_value": 0.97, + "average_value": 0.51 + }, + { + "index_id": 5614, + "metric_id": 13534, + "metric": "hitratio", + "metric_legend": "hitratio", + "unit": "%", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#cc9999" + }, + "legend": "hitratio", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 80.192446667, + 80.324963333, + 80.31374, + 80.043863333, + 78.97382, + 78.01196, + 77.85379, + 77.311446667, + 77.518806667, + 77.363833333, + 76.410303333, + 75.385206667, + 75.470793333, + 75.444866667, + 74.902366667, + 74.787096667, + 73.424696667, + 72.984073333, + 73.127803333, + 72.06457, + 71.092996667, + 70.652853333, + 72.838793333, + 74.3249, + 74.690726667, + 75.462586667, + 74.87943, + 75.429203333, + 76.836436667, + 77.9801, + 78.159586667, + 77.133953333, + 76.139193333, + 76.100923333, + 75.977446667, + 75.897756667, + 75.158033333, + 73.702993333, + 72.387816667, + 71.130253333, + 70.39241, + 71.103633333, + 71.842186667, + 72.052586667, + 71.766026667, + 71.548363333, + 71.128753333, + 72.8407, + 74.584996667, + 73.229936667, + 71.78108, + 71.673396667, + 71.184396667, + 70.4531, + 70.344756667, + 72.715336667, + 74.256866667, + 73.24873, + 73.652976667, + 75.191423333, + 75.63962, + 74.709446667, + 74.725396667, + 75.930556667, + 77.090426667, + 77.774146667, + 78.34251, + 79.083023333, + 79.19294, + 79.902196667, + 80.164726667, + 79.28103, + 78.529063333, + 77.409276667, + 75.7148, + 75.432493333, + 76.331206667, + 76.05935, + 76.290816667, + 76.174896667, + 74.520766667, + 74.641866667, + 75.632723333, + 75.710626667, + 74.692966667, + 73.84993, + 73.685023333, + 73.59346, + 73.485723333, + 74.233233333, + 76.036953333, + 77.343543333, + 77.40446, + 77.324593333, + 77.389233333, + 76.69522, + 75.906923333, + 75.531203333, + 75.230936667, + 74.892196667, + 75.257436667, + 76.047326667, + 76.83612, + 76.4245, + 74.62692, + 73.454276667, + 73.838346667, + 74.91667, + 75.654806667, + 75.07332, + 73.51074, + 72.497866667, + 72.15109, + 71.317343333, + 71.56787, + 72.18692, + 71.37498, + 70.426836667, + 70.611836667, + 71.692516667, + 72.545326667, + 71.79552, + 70.463443333, + 70.393413333, + 72.92507, + 75.238116667, + 74.41566, + 72.43751, + 70.750156667, + 70.50232, + 73.044236667, + 75.752553333, + 76.848816667, + 77.010526667, + 77.599906667, + 77.768733333, + 77.314866667, + 77.01545, + 77.704426667, + 78.521463333, + 79.173236667, + 79.92521, + 80.769776667, + 82.234066667, + 83.11997, + 82.61005, + 82.86877, + 83.577323333, + 84.011146667, + 84.565116667, + 84.8117, + 85.159493333, + 84.523926667, + 83.279573333, + 82.95924, + 83.57027, + 84.89847, + 83.853206667, + 84.676703333, + 86.10003, + 85.350266667, + 84.94219, + 85.116616667, + 84.75833, + 83.948586667, + 83.637406667, + 83.2102, + 82.458723333, + 82.4267, + 83.49822, + 83.83907, + 82.507316667, + 82.858513333, + 84.26815, + 83.920333333, + 84.255026667, + 82.74865, + 82.445566667, + 81.86038, + 80.631133333, + 81.62438, + 81.23579, + 80.95778, + 79.499446667, + 78.88417, + 78.406263333, + 76.631363333, + 75.627376667, + 75.485826667, + 73.82354, + 72.111716667, + 70.308843333, + 74.6297, + 75.690653333, + 74.810816667, + 75.50583, + 76.246803333, + 77.157083333, + 77.98975, + 77.812933333, + 77.722826667, + 79.01059, + 79.221413333, + 80.305683333, + 80.499336667, + 78.993733333, + 80.18652, + 81.94138, + 83.55718, + 82.897013333, + 82.29185, + 81.54342, + 82.708416667, + 83.576366667, + 83.04722, + 83.864086667, + 83.699626667, + 82.20913, + 81.32802, + 79.87446, + 79.22439, + 77.4626, + 78.31997, + 76.586803333, + 77.81823, + 77.163863333, + 77.913456667, + 79.026213333, + 77.37621, + 78.781353333, + 79.298723333, + 78.798236667, + 79.785363333, + 80.425, + 81.082246667, + 82.75068, + 83.45285, + 82.340293333, + 82.654883333, + 82.498793333, + 81.795116667, + 82.371406667, + 80.786006667, + 79.975043333, + 80.537633333, + 78.944543333, + 77.60028, + 76.822273333, + 75.409623333, + 74.17238, + 75.874883333, + 77.656453333, + 76.133693333, + 75.23148, + 76.698886667, + 76.538843333, + 77.68948, + 77.99752, + 79.06483, + 79.920213333, + 80.295163333, + 82.13812, + 81.25856, + 79.891413333, + 80.126633333, + 79.632393333, + 81.009086667, + 81.655146667, + 82.30286, + 83.57457, + 83.236493333, + 83.495466667, + 82.422156667, + 82.68833, + 83.218446667, + 84.335683333, + 85.520996667, + 85.508586667, + 85.91827, + 84.19682, + 86.29191, + 87.191866667, + 87.270053333, + 88.025836667, + 87.42611, + 86.863723333, + 86.564723333, + 87.268263333, + null + ], + "prints": [ + ["Last:87.27"], + ["Min:70.31"], + ["Max:88.03"], + ["Average:78.07"] + ], + "last_value": 87.27, + "minimum_value": 70.31, + "maximum_value": 88.03, + "average_value": 78.07 + }, + { + "index_id": 5614, + "metric_id": 13535, + "metric": "querytime", + "metric_legend": "querytime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#00ffcc" + }, + "legend": "querytime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.29714333333, + 0.69919666667, + 0.79321666667, + 0.71506, + 0.5782, + 0.48894666667, + 0.67059333333, + 0.54513333333, + 0.63351666667, + 0.83608666667, + 0.5301, + 0.27967333333, + 0.37714333333, + 0.59969333333, + 0.48521, + 0.59266333333, + 0.53817, + 0.1465, + 0.16135, + 0.3028, + 0.19724333333, + 0.17198333333, + 0.33685666667, + 0.24265333333, + 0.34326666667, + 0.76181, + 0.73900333333, + 0.67112333333, + 0.59812333333, + 0.52067666667, + 0.77137333333, + 0.47664333333, + 0.046403333333, + 0.24118333333, + 0.53058333333, + 0.57370333333, + 0.47472333333, + 0.19977, + 0.44531, + 0.80133, + 0.3802, + 0.034383333333, + 0.23191333333, + 0.32398666667, + 0.22054333333, + 0.35904666667, + 0.24970666667, + 0.29793666667, + 0.69748666667, + 0.54007333333, + 0.28856, + 0.18591333333, + 0.28871666667, + 0.43670333333, + 0.31626666667, + 0.3028, + 0.47199333333, + 0.56091666667, + 0.39671, + 0.44483, + 0.61814, + 0.61943, + 0.71691, + 0.4302, + 0.11944666667, + 0.42061, + 0.39272666667, + 0.19695, + 0.16065, + 0.34680666667, + 0.39646, + 0.48262, + 0.40757, + 0.14027, + 0.29311333333, + 0.57186, + 0.76852, + 0.8357, + 0.90495, + 0.50284, + 0.46309, + 0.73553666667, + 0.41647333333, + 0.47040333333, + 0.79052, + 0.53166333333, + 0.46984666667, + 0.69507333333, + 0.81015333333, + 0.68305, + 0.44918, + 0.42194333333, + 0.44094333333, + 0.22025666667, + 0.48985, + 0.86948, + 0.89493, + 0.60076, + 0.20515333333, + 0.56671333333, + 0.53818333333, + 0.18702666667, + 0.56491333333, + 0.91616666667, + 0.48051333333, + 0.35035666667, + 0.78203666667, + 0.88262, + 0.69741, + 0.67662, + 0.55486333333, + 0.28368666667, + 0.46458333333, + 0.84172, + 0.71890333333, + 0.63952333333, + 0.87039666667, + 0.54808, + 0.56612666667, + 0.63758666667, + 0.37719666667, + 0.68918666667, + 0.88794, + 0.90652666667, + 0.97649666667, + 0.78016, + 0.36409, + 0.34504333333, + 0.60541666667, + 0.58179, + 0.70434333333, + 0.53593666667, + 0.53723333333, + 0.50562666667, + 0.36219666667, + 0.36345666667, + 0.61732333333, + 0.77207666667, + 0.30536333333, + 0.22801666667, + 0.30937, + 0.32652666667, + 0.50535, + 0.60912, + 0.50587666667, + 0.27743666667, + 0.51364333333, + 0.50690666667, + 0.15515333333, + 0.39111333333, + 0.4863, + 0.52368, + 0.34827333333, + 0.2388, + 0.57008333333, + 0.60963666667, + 0.73512333333, + 0.7397, + 0.89249666667, + 0.71656666667, + 0.53072, + 0.66387333333, + 0.61843, + 0.30160333333, + 0.74331, + 0.17412666667, + 0.83096666667, + 0.17164666667, + 0.12400333333, + 0.30874333333, + 0.31753666667, + 0.54321666667, + 0.24991333333, + 0.29325, + 0.87885333333, + 0.14124333333, + 0.22927333333, + 0.87817666667, + 0.73802333333, + 0.94914, + 0.86089333333, + 0.49467, + 0.076276666667, + 0.33023333333, + 0.68270666667, + 0.78202, + 0.64673, + 0.4965, + 0.21815666667, + 0.073196666667, + 0.34646333333, + 0.23888666667, + 0.79677333333, + 0.91694333333, + 0.80389, + 0.16613333333, + 0.10015, + 0.77488, + 0.90486666667, + 0.07169, + 0.72866333333, + 0.65142333333, + 0.41378333333, + 0.92684, + 0.66168333333, + 0.47534, + 0.73346, + 0.42083, + 0.23695666667, + 0.22677, + 0.08573, + 0.55321, + 0.80721333333, + 0.43997, + 0.22795, + 0.34503666667, + 0.73733666667, + 0.90842333333, + 0.88768333333, + 0.08724, + 0.25737333333, + 0.25853333333, + 0.27085, + 0.39665, + 0.34975333333, + 0.17418333333, + 0.90513, + 0.89959666667, + 0.65670333333, + 0.92508, + 0.49195, + 0.63128, + 0.15663333333, + 0.059676666667, + 0.11686333333, + 0.16909, + 0.33827666667, + 0.77581, + 0.43058666667, + 0.097993333333, + 0.090543333333, + 0.44194333333, + 0.12752, + 0.34368333333, + 0.90045666667, + 0.85451333333, + 0.13603333333, + 0.87106666667, + 0.24542333333, + 0.65059, + 0.18116666667, + 0.77148333333, + 0.88124666667, + 0.86107, + 0.31515666667, + 0.91171666667, + 0.37591333333, + 0.34916, + 0.77019333333, + 0.62402666667, + 0.48065666667, + 0.22993333333, + 0.89142, + 0.085606666667, + 0.70465333333, + 0.50069666667, + 0.27494333333, + 0.88125, + 0.55443333333, + 0.38727, + 0.76749333333, + 0.83601, + 0.71435, + 0.53133666667, + 0.33418, + 0.44919, + 0.86442, + 0.19165, + 0.82827, + 0.32092, + 0.23609333333, + 0.45102333333, + 0.75873, + 0.23588666667, + 0.41906666667, + 0.357, + 0.32246333333, + 0.64624666667, + null + ], + "prints": [["Last:0.65"], ["Min:0.03"], ["Max:0.98"], ["Average:0.50"]], + "last_value": 0.65, + "minimum_value": 0.03, + "maximum_value": 0.98, + "average_value": 0.5 + } + ], + "times": [ + "2023-06-18T17:05:00+02:00", + "2023-06-18T17:10:00+02:00", + "2023-06-18T17:15:00+02:00", + "2023-06-18T17:20:00+02:00", + "2023-06-18T17:25:00+02:00", + "2023-06-18T17:30:00+02:00", + "2023-06-18T17:35:00+02:00", + "2023-06-18T17:40:00+02:00", + "2023-06-18T17:45:00+02:00", + "2023-06-18T17:50:00+02:00", + "2023-06-18T17:55:00+02:00", + "2023-06-18T18:00:00+02:00", + "2023-06-18T18:05:00+02:00", + "2023-06-18T18:10:00+02:00", + "2023-06-18T18:15:00+02:00", + "2023-06-18T18:20:00+02:00", + "2023-06-18T18:25:00+02:00", + "2023-06-18T18:30:00+02:00", + "2023-06-18T18:35:00+02:00", + "2023-06-18T18:40:00+02:00", + "2023-06-18T18:45:00+02:00", + "2023-06-18T18:50:00+02:00", + "2023-06-18T18:55:00+02:00", + "2023-06-18T19:00:00+02:00", + "2023-06-18T19:05:00+02:00", + "2023-06-18T19:10:00+02:00", + "2023-06-18T19:15:00+02:00", + "2023-06-18T19:20:00+02:00", + "2023-06-18T19:25:00+02:00", + "2023-06-18T19:30:00+02:00", + "2023-06-18T19:35:00+02:00", + "2023-06-18T19:40:00+02:00", + "2023-06-18T19:45:00+02:00", + "2023-06-18T19:50:00+02:00", + "2023-06-18T19:55:00+02:00", + "2023-06-18T20:00:00+02:00", + "2023-06-18T20:05:00+02:00", + "2023-06-18T20:10:00+02:00", + "2023-06-18T20:15:00+02:00", + "2023-06-18T20:20:00+02:00", + "2023-06-18T20:25:00+02:00", + "2023-06-18T20:30:00+02:00", + "2023-06-18T20:35:00+02:00", + "2023-06-18T20:40:00+02:00", + "2023-06-18T20:45:00+02:00", + "2023-06-18T20:50:00+02:00", + "2023-06-18T20:55:00+02:00", + "2023-06-18T21:00:00+02:00", + "2023-06-18T21:05:00+02:00", + "2023-06-18T21:10:00+02:00", + "2023-06-18T21:15:00+02:00", + "2023-06-18T21:20:00+02:00", + "2023-06-18T21:25:00+02:00", + "2023-06-18T21:30:00+02:00", + "2023-06-18T21:35:00+02:00", + "2023-06-18T21:40:00+02:00", + "2023-06-18T21:45:00+02:00", + "2023-06-18T21:50:00+02:00", + "2023-06-18T21:55:00+02:00", + "2023-06-18T22:00:00+02:00", + "2023-06-18T22:05:00+02:00", + "2023-06-18T22:10:00+02:00", + "2023-06-18T22:15:00+02:00", + "2023-06-18T22:20:00+02:00", + "2023-06-18T22:25:00+02:00", + "2023-06-18T22:30:00+02:00", + "2023-06-18T22:35:00+02:00", + "2023-06-18T22:40:00+02:00", + "2023-06-18T22:45:00+02:00", + "2023-06-18T22:50:00+02:00", + "2023-06-18T22:55:00+02:00", + "2023-06-18T23:00:00+02:00", + "2023-06-18T23:05:00+02:00", + "2023-06-18T23:10:00+02:00", + "2023-06-18T23:15:00+02:00", + "2023-06-18T23:20:00+02:00", + "2023-06-18T23:25:00+02:00", + "2023-06-18T23:30:00+02:00", + "2023-06-18T23:35:00+02:00", + "2023-06-18T23:40:00+02:00", + "2023-06-18T23:45:00+02:00", + "2023-06-18T23:50:00+02:00", + "2023-06-18T23:55:00+02:00", + "2023-06-19T00:00:00+02:00", + "2023-06-19T00:05:00+02:00", + "2023-06-19T00:10:00+02:00", + "2023-06-19T00:15:00+02:00", + "2023-06-19T00:20:00+02:00", + "2023-06-19T00:25:00+02:00", + "2023-06-19T00:30:00+02:00", + "2023-06-19T00:35:00+02:00", + "2023-06-19T00:40:00+02:00", + "2023-06-19T00:45:00+02:00", + "2023-06-19T00:50:00+02:00", + "2023-06-19T00:55:00+02:00", + "2023-06-19T01:00:00+02:00", + "2023-06-19T01:05:00+02:00", + "2023-06-19T01:10:00+02:00", + "2023-06-19T01:15:00+02:00", + "2023-06-19T01:20:00+02:00", + "2023-06-19T01:25:00+02:00", + "2023-06-19T01:30:00+02:00", + "2023-06-19T01:35:00+02:00", + "2023-06-19T01:40:00+02:00", + "2023-06-19T01:45:00+02:00", + "2023-06-19T01:50:00+02:00", + "2023-06-19T01:55:00+02:00", + "2023-06-19T02:00:00+02:00", + "2023-06-19T02:05:00+02:00", + "2023-06-19T02:10:00+02:00", + "2023-06-19T02:15:00+02:00", + "2023-06-19T02:20:00+02:00", + "2023-06-19T02:25:00+02:00", + "2023-06-19T02:30:00+02:00", + "2023-06-19T02:35:00+02:00", + "2023-06-19T02:40:00+02:00", + "2023-06-19T02:45:00+02:00", + "2023-06-19T02:50:00+02:00", + "2023-06-19T02:55:00+02:00", + "2023-06-19T03:00:00+02:00", + "2023-06-19T03:05:00+02:00", + "2023-06-19T03:10:00+02:00", + "2023-06-19T03:15:00+02:00", + "2023-06-19T03:20:00+02:00", + "2023-06-19T03:25:00+02:00", + "2023-06-19T03:30:00+02:00", + "2023-06-19T03:35:00+02:00", + "2023-06-19T03:40:00+02:00", + "2023-06-19T03:45:00+02:00", + "2023-06-19T03:50:00+02:00", + "2023-06-19T03:55:00+02:00", + "2023-06-19T04:00:00+02:00", + "2023-06-19T04:05:00+02:00", + "2023-06-19T04:10:00+02:00", + "2023-06-19T04:15:00+02:00", + "2023-06-19T04:20:00+02:00", + "2023-06-19T04:25:00+02:00", + "2023-06-19T04:30:00+02:00", + "2023-06-19T04:35:00+02:00", + "2023-06-19T04:40:00+02:00", + "2023-06-19T04:45:00+02:00", + "2023-06-19T04:50:00+02:00", + "2023-06-19T04:55:00+02:00", + "2023-06-19T05:00:00+02:00", + "2023-06-19T05:05:00+02:00", + "2023-06-19T05:10:00+02:00", + "2023-06-19T05:15:00+02:00", + "2023-06-19T05:20:00+02:00", + "2023-06-19T05:25:00+02:00", + "2023-06-19T05:30:00+02:00", + "2023-06-19T05:35:00+02:00", + "2023-06-19T05:40:00+02:00", + "2023-06-19T05:45:00+02:00", + "2023-06-19T05:50:00+02:00", + "2023-06-19T05:55:00+02:00", + "2023-06-19T06:00:00+02:00", + "2023-06-19T06:05:00+02:00", + "2023-06-19T06:10:00+02:00", + "2023-06-19T06:15:00+02:00", + "2023-06-19T06:20:00+02:00", + "2023-06-19T06:25:00+02:00", + "2023-06-19T06:30:00+02:00", + "2023-06-19T06:35:00+02:00", + "2023-06-19T06:40:00+02:00", + "2023-06-19T06:45:00+02:00", + "2023-06-19T06:50:00+02:00", + "2023-06-19T06:55:00+02:00", + "2023-06-19T07:00:00+02:00", + "2023-06-19T07:05:00+02:00", + "2023-06-19T07:10:00+02:00", + "2023-06-19T07:15:00+02:00", + "2023-06-19T07:20:00+02:00", + "2023-06-19T07:25:00+02:00", + "2023-06-19T07:30:00+02:00", + "2023-06-19T07:35:00+02:00", + "2023-06-19T07:40:00+02:00", + "2023-06-19T07:45:00+02:00", + "2023-06-19T07:50:00+02:00", + "2023-06-19T07:55:00+02:00", + "2023-06-19T08:00:00+02:00", + "2023-06-19T08:05:00+02:00", + "2023-06-19T08:10:00+02:00", + "2023-06-19T08:15:00+02:00", + "2023-06-19T08:20:00+02:00", + "2023-06-19T08:25:00+02:00", + "2023-06-19T08:30:00+02:00", + "2023-06-19T08:35:00+02:00", + "2023-06-19T08:40:00+02:00", + "2023-06-19T08:45:00+02:00", + "2023-06-19T08:50:00+02:00", + "2023-06-19T08:55:00+02:00", + "2023-06-19T09:00:00+02:00", + "2023-06-19T09:05:00+02:00", + "2023-06-19T09:10:00+02:00", + "2023-06-19T09:15:00+02:00", + "2023-06-19T09:20:00+02:00", + "2023-06-19T09:25:00+02:00", + "2023-06-19T09:30:00+02:00", + "2023-06-19T09:35:00+02:00", + "2023-06-19T09:40:00+02:00", + "2023-06-19T09:45:00+02:00", + "2023-06-19T09:50:00+02:00", + "2023-06-19T09:55:00+02:00", + "2023-06-19T10:00:00+02:00", + "2023-06-19T10:05:00+02:00", + "2023-06-19T10:10:00+02:00", + "2023-06-19T10:15:00+02:00", + "2023-06-19T10:20:00+02:00", + "2023-06-19T10:25:00+02:00", + "2023-06-19T10:30:00+02:00", + "2023-06-19T10:35:00+02:00", + "2023-06-19T10:40:00+02:00", + "2023-06-19T10:45:00+02:00", + "2023-06-19T10:50:00+02:00", + "2023-06-19T10:55:00+02:00", + "2023-06-19T11:00:00+02:00", + "2023-06-19T11:05:00+02:00", + "2023-06-19T11:10:00+02:00", + "2023-06-19T11:15:00+02:00", + "2023-06-19T11:20:00+02:00", + "2023-06-19T11:25:00+02:00", + "2023-06-19T11:30:00+02:00", + "2023-06-19T11:35:00+02:00", + "2023-06-19T11:40:00+02:00", + "2023-06-19T11:45:00+02:00", + "2023-06-19T11:50:00+02:00", + "2023-06-19T11:55:00+02:00", + "2023-06-19T12:00:00+02:00", + "2023-06-19T12:05:00+02:00", + "2023-06-19T12:10:00+02:00", + "2023-06-19T12:15:00+02:00", + "2023-06-19T12:20:00+02:00", + "2023-06-19T12:25:00+02:00", + "2023-06-19T12:30:00+02:00", + "2023-06-19T12:35:00+02:00", + "2023-06-19T12:40:00+02:00", + "2023-06-19T12:45:00+02:00", + "2023-06-19T12:50:00+02:00", + "2023-06-19T12:55:00+02:00", + "2023-06-19T13:00:00+02:00", + "2023-06-19T13:05:00+02:00", + "2023-06-19T13:10:00+02:00", + "2023-06-19T13:15:00+02:00", + "2023-06-19T13:20:00+02:00", + "2023-06-19T13:25:00+02:00", + "2023-06-19T13:30:00+02:00", + "2023-06-19T13:35:00+02:00", + "2023-06-19T13:40:00+02:00", + "2023-06-19T13:45:00+02:00", + "2023-06-19T13:50:00+02:00", + "2023-06-19T13:55:00+02:00", + "2023-06-19T14:00:00+02:00", + "2023-06-19T14:05:00+02:00", + "2023-06-19T14:10:00+02:00", + "2023-06-19T14:15:00+02:00", + "2023-06-19T14:20:00+02:00", + "2023-06-19T14:25:00+02:00", + "2023-06-19T14:30:00+02:00", + "2023-06-19T14:35:00+02:00", + "2023-06-19T14:40:00+02:00", + "2023-06-19T14:45:00+02:00", + "2023-06-19T14:50:00+02:00", + "2023-06-19T14:55:00+02:00", + "2023-06-19T15:00:00+02:00", + "2023-06-19T15:05:00+02:00", + "2023-06-19T15:10:00+02:00", + "2023-06-19T15:15:00+02:00", + "2023-06-19T15:20:00+02:00", + "2023-06-19T15:25:00+02:00", + "2023-06-19T15:30:00+02:00", + "2023-06-19T15:35:00+02:00", + "2023-06-19T15:40:00+02:00", + "2023-06-19T15:45:00+02:00", + "2023-06-19T15:50:00+02:00", + "2023-06-19T15:55:00+02:00", + "2023-06-19T16:00:00+02:00", + "2023-06-19T16:05:00+02:00", + "2023-06-19T16:10:00+02:00", + "2023-06-19T16:15:00+02:00", + "2023-06-19T16:20:00+02:00", + "2023-06-19T16:25:00+02:00", + "2023-06-19T16:30:00+02:00", + "2023-06-19T16:35:00+02:00", + "2023-06-19T16:40:00+02:00", + "2023-06-19T16:45:00+02:00", + "2023-06-19T16:50:00+02:00", + "2023-06-19T16:55:00+02:00", + "2023-06-19T17:00:00+02:00", + "2023-06-19T17:05:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/lastDayAreaStack.json b/centreon/packages/ui/src/Graph/mockedData/lastDayAreaStack.json new file mode 100644 index 0000000000..c519254969 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/lastDayAreaStack.json @@ -0,0 +1,3050 @@ +{ + "global": { + "title": "memory-stats graph on srv-oracle-crm", + "start": "2023-06-06T12:43:09+02:00", + "end": "2023-06-07T12:43:09+02:00", + "vertical-label": "Memory Usage", + "base": 1024, + "width": 550, + "height": 140, + "scaled": 1, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 5397, + "metric_id": 13071, + "metric": "mem_active", + "metric_legend": "mem_active", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 25, + "host_id": null, + "service_id": null, + "name": "Memory-stats-active", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": "mem_active", + "ds_color_line": "#E84017", + "ds_color_line_mode": "0", + "ds_color_area": "#E84017", + "ds_color_area_warn": "#E84017", + "ds_color_area_crit": "#E84017", + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "10", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": "1", + "default_tpl1": null, + "comment": null + }, + "legend": "mem_active", + "stack": "1", + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 1893820035, + 2052146925.1, + 2466085903, + 2466085903, + 2466085903, + 2466085903, + 2466085903, + 2285190216.1, + 1812246071, + 1812246071, + 2063947848.5, + 2146317828, + 641190915, + 641190915, + 641190915, + 2311348047.5, + 6240789467.9, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 976416823, + 3746504548, + 4136212707, + 4136212707, + 4136212707, + 4136212707, + 4136212707, + 4136212707, + 4136212707, + 4136212707, + 4136212707, + 4136212707, + 4136212707, + 4045334676.2, + 4032549554, + 4032549554, + 4032549554, + 4032549554, + 4032549554, + 4032549554, + 4032549554, + 4032549554, + 4032549554, + 4032549554, + 4032549554, + 2843304694.2, + 2675996482, + 3290636903.5, + 3377107229, + 3377107229, + 3377107229, + 3377107229, + 1008975090.3, + 675815816, + 675815816, + 675815816, + 675815816, + 675815816, + 675815816, + 675815816, + 675815816, + 5007167276.5, + 5616520904, + 5616520904, + 5616520904, + 5616520904, + 5616520904, + 5616520904, + 5616520904, + 5616520904, + 6020516585.6, + 3004905509.1, + 2717449076.5, + 4013696655, + 4013696655, + 4013696655, + 4013696655, + 4013696655, + 4013696655, + 4013696655, + 4013696655, + 4013696655, + 4013696655, + 3518667258.2, + 3477659444.3, + 4029339877, + 4029339877, + 4029339877, + 4029339877, + 4029339877, + 4029339877, + 4029339877, + 4029339877, + 4029339877, + 4029339877, + 4029339877, + 2669352098.8, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 1176218664, + 921214667.61, + 641245245, + 641245245, + 641245245, + 641245245, + 641245245, + 641245245, + 641245245, + 641245245, + 641245245, + 641245245, + 531967203.39, + 410376143, + 410376143, + 410376143, + 410376143, + 410376143, + 410376143, + 410376143, + 410376143, + 410376143, + 364244282.82, + 312223249, + 312223249, + 312223249, + 312223249, + 312223249, + 312223249, + 312223249, + 312223249, + 191874059.65, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 56161144, + 2507006790.8, + 5270726350, + 5270726350, + 5270726350, + 5270726350, + 5357995355.7, + 6141977364.6, + 1153868339, + 1153868339, + 1153868339, + 1435336547.7, + 5174842749, + 5174842749, + 4977220904.4, + 2351673540, + 2351673540, + 2351673540, + 2439970914.3, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3613064601, + 3633811544.1, + 3738396850.5, + 1465840195, + 1465840195, + 1465840195, + 1465840195, + 1465840195, + 1174502940.9, + 1130969788, + 1130969788, + 1130969788, + 1130969788, + 1130969788, + 1130969788, + 1130969788, + 1116663662, + 1114525965, + 1114525965, + 1114525965, + 1114525965, + 1114525965, + 1114525965, + 1114525965, + 1114525965, + 1114525965, + 496913723.64, + 404626837, + 404626837, + 404626837, + 404626837, + 404626837, + 404626837, + 404626837, + 5119506062, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5824028245, + 5908740341.6, + 5921398471, + 5921398471, + 5921398471, + 5921398471, + 5921398471, + 5921398471, + 5921398471, + 6245118232.5, + 6005456642, + 4040032635, + 2592658957, + 2592658957, + null + ], + "prints": [["Last:2592658957.00"], ["Average:2419187156.86"]], + "last_value": 2592658957, + "minimum_value": null, + "maximum_value": null, + "average_value": 2419187156.86 + }, + { + "index_id": 5397, + "metric_id": 13073, + "metric": "mem_apps", + "metric_legend": "mem_apps", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 26, + "host_id": null, + "service_id": null, + "name": "Memory-stats-apps", + "ds_order": 2, + "ds_hidecurve": null, + "ds_name": "mem_apps", + "ds_color_line": "#4BB846", + "ds_color_line_mode": "0", + "ds_color_area": "#4BB846", + "ds_color_area_warn": "#4BB846", + "ds_color_area_crit": "#4BB846", + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "10", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": "1", + "default_tpl1": null, + "comment": null + }, + "legend": "mem_apps", + "stack": "1", + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 2, + "data": [ + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 98553122, + 212008185.56, + 508631665, + 508631665, + 508631665, + 508631665, + 508631665, + 404436836.74, + 132023852, + 132023852, + 751679255.8, + 2023984324.9, + 1114786080, + 1114786080, + 1114786080, + 1545614683, + 2477236437.9, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 131631027, + 1689936947, + 1909166297, + 1909166297, + 1909166297, + 1909166297, + 1909166297, + 1909166297, + 1909166297, + 1909166297, + 1909166297, + 1909166297, + 1909166297, + 1590469817.4, + 1545634191, + 1545634191, + 1545634191, + 1545634191, + 1545634191, + 1545634191, + 1545634191, + 1545634191, + 1545634191, + 1545634191, + 1545634191, + 540868656.99, + 399513810, + 805884426.34, + 863054437, + 863054437, + 863054437, + 863054437, + 561082446.51, + 518599695, + 518599695, + 518599695, + 518599695, + 518599695, + 518599695, + 518599695, + 518599695, + 1357142860, + 1475112811, + 1475112811, + 1475112811, + 1475112811, + 1475112811, + 1475112811, + 1475112811, + 1475112811, + 1844808332.4, + 1834001095.6, + 2325101374.9, + 2897236369, + 2897236369, + 2897236369, + 2897236369, + 2897236369, + 2897236369, + 2897236369, + 2897236369, + 2897236369, + 2897236369, + 2780403570.1, + 2660846348.1, + 2670413196, + 2670413196, + 2670413196, + 2670413196, + 2670413196, + 2670413196, + 2670413196, + 2670413196, + 2670413196, + 2670413196, + 2670413196, + 1430911514, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 70060017, + 69927619.973, + 69782261, + 69782261, + 69782261, + 69782261, + 69782261, + 69782261, + 69782261, + 69782261, + 69782261, + 69782261, + 57749074.973, + 44360037, + 44360037, + 44360037, + 44360037, + 44360037, + 44360037, + 44360037, + 44360037, + 44360037, + 29247892.94, + 12206539, + 12206539, + 12206539, + 12206539, + 12206539, + 12206539, + 12206539, + 12206539, + 9103798.28, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 5604963, + 1292535222.4, + 2743754451, + 2743754451, + 2743754451, + 2743754451, + 2746719079.1, + 2664862881, + 1054057710, + 1054057710, + 1054057710, + 1077191458.5, + 1384539832, + 1384539832, + 1377460654.4, + 1283408724, + 1283408724, + 1283408724, + 1427368034.9, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3339970309, + 3341758517.8, + 3277555338.2, + 2108933138, + 2108933138, + 2108933138, + 2108933138, + 2108933138, + 1548430581.6, + 1464677326, + 1464677326, + 1464677326, + 1464677326, + 1464677326, + 1464677326, + 1464677326, + 300788359.3, + 126873916, + 126873916, + 126873916, + 126873916, + 126873916, + 126873916, + 126873916, + 126873916, + 126873916, + 84415687.93, + 78071355, + 78071355, + 78071355, + 78071355, + 78071355, + 78071355, + 78071355, + 1014630991.2, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 1154576684, + 2456071615.8, + 2650547870, + 2650547870, + 2650547870, + 2650547870, + 2650547870, + 2650547870, + 2650547870, + 2726291049, + 1847897022.8, + 477644310.52, + 158057658, + 158057658, + null + ], + "prints": [["Last:158057658.00"], ["Average:1062901083.13"]], + "last_value": 158057658, + "minimum_value": null, + "maximum_value": null, + "average_value": 1062901083.13 + }, + { + "index_id": 5397, + "metric_id": 13070, + "metric": "mem_mapped", + "metric_legend": "mem_mapped", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 27, + "host_id": null, + "service_id": null, + "name": "Memory-stats-mapped", + "ds_order": 3, + "ds_hidecurve": null, + "ds_name": "mem_mapped", + "ds_color_line": "#39C3C6", + "ds_color_line_mode": "0", + "ds_color_area": "#39C3C6", + "ds_color_area_warn": "#39C3C6", + "ds_color_area_crit": "#39C3C6", + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "10", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": "1", + "default_tpl1": null, + "comment": null + }, + "legend": "mem_mapped", + "stack": "1", + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 3, + "data": [ + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 26075867, + 30188011.807, + 40939041, + 40939041, + 40939041, + 40939041, + 40939041, + 40006741.287, + 37569283, + 37569283, + 44363448.583, + 50169994.46, + 18910194, + 18910194, + 18910194, + 44714711.123, + 103907909.91, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 4288797, + 134021342.32, + 152272689, + 152272689, + 152272689, + 152272689, + 152272689, + 152272689, + 152272689, + 152272689, + 152272689, + 152272689, + 152272689, + 96299329.143, + 88424750, + 88424750, + 88424750, + 88424750, + 88424750, + 88424750, + 88424750, + 88424750, + 88424750, + 88424750, + 88424750, + 50472420.157, + 45133119, + 95402405.987, + 102474511, + 102474511, + 102474511, + 102474511, + 59306851.707, + 53233835, + 53233835, + 53233835, + 53233835, + 53233835, + 53233835, + 53233835, + 53233835, + 139167265.92, + 151256760, + 151256760, + 151256760, + 151256760, + 151256760, + 151256760, + 151256760, + 151256760, + 167520608.11, + 87172020.61, + 105523104.02, + 169023088, + 169023088, + 169023088, + 169023088, + 169023088, + 169023088, + 169023088, + 169023088, + 169023088, + 169023088, + 125884231.76, + 92215363.55, + 107249346, + 107249346, + 107249346, + 107249346, + 107249346, + 107249346, + 107249346, + 107249346, + 107249346, + 107249346, + 107249346, + 71144807.53, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 31505559, + 29477861.9, + 27251649, + 27251649, + 27251649, + 27251649, + 27251649, + 27251649, + 27251649, + 27251649, + 27251649, + 27251649, + 18183509.593, + 8093608, + 8093608, + 8093608, + 8093608, + 8093608, + 8093608, + 8093608, + 8093608, + 8093608, + 4702974.42, + 879494, + 879494, + 879494, + 879494, + 879494, + 879494, + 879494, + 879494, + 486918.98, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 44228, + 68949003.82, + 146650134, + 146650134, + 146650134, + 146650134, + 147031336.99, + 152013277.07, + 150915692, + 150915692, + 150915692, + 151609863.87, + 160832433, + 160832433, + 155141940.43, + 79539682, + 79539682, + 79539682, + 81880551.23, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 112980671, + 115500915.72, + 146919039.18, + 119482341, + 119482341, + 119482341, + 119482341, + 119482341, + 90930015.45, + 86663576, + 86663576, + 86663576, + 86663576, + 86663576, + 86663576, + 86663576, + 52103843.03, + 46939745, + 46939745, + 46939745, + 46939745, + 46939745, + 46939745, + 46939745, + 46939745, + 46939745, + 30694571.69, + 28267132, + 28267132, + 28267132, + 28267132, + 28267132, + 28267132, + 28267132, + 150105765.22, + 168311538, + 168311538, + 168311538, + 168311538, + 168311538, + 168311538, + 168311538, + 168311538, + 168311538, + 168311538, + 168311538, + 168311538, + 169874079.75, + 170107563, + 170107563, + 170107563, + 170107563, + 170107563, + 170107563, + 170107563, + 170629573.67, + 120264551.1, + 56314383.81, + 48993877, + 48993877, + null + ], + "prints": [["Last:48993877.00"], ["Average:72908106.02"]], + "last_value": 48993877, + "minimum_value": null, + "maximum_value": null, + "average_value": 72908106.02 + }, + { + "index_id": 5397, + "metric_id": 13069, + "metric": "mem_pages_tables", + "metric_legend": "mem_pages_tables", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 28, + "host_id": null, + "service_id": null, + "name": "Memory-stats-page-tables", + "ds_order": 4, + "ds_hidecurve": null, + "ds_name": "mem_pages_tables", + "ds_color_line": "#E3DB1C", + "ds_color_line_mode": "0", + "ds_color_area": "#E3DB1C", + "ds_color_area_warn": "#E3DB1C", + "ds_color_area_crit": "#E3DB1C", + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "10", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": "1", + "default_tpl1": null, + "comment": null + }, + "legend": "mem_pages_tables", + "stack": "1", + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 4, + "data": [ + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 74549259, + 78623541.143, + 89275580, + 89275580, + 89275580, + 89275580, + 89275580, + 66932420.177, + 8517171, + 8517171, + 48204303.26, + 144020594.4, + 123251230, + 123251230, + 123251230, + 157464418.47, + 241700900.2, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 178924790, + 311516741.45, + 330170362, + 330170362, + 330170362, + 330170362, + 330170362, + 330170362, + 330170362, + 330170362, + 330170362, + 330170362, + 330170362, + 56983891.587, + 18550814, + 18550814, + 18550814, + 18550814, + 18550814, + 18550814, + 18550814, + 18550814, + 18550814, + 18550814, + 18550814, + 13753708.903, + 13078831, + 93841567.95, + 105203626, + 105203626, + 105203626, + 105203626, + 29710500.823, + 19089795, + 19089795, + 19089795, + 19089795, + 19089795, + 19089795, + 19089795, + 19089795, + 80470299.85, + 89105580, + 89105580, + 89105580, + 89105580, + 89105580, + 89105580, + 89105580, + 89105580, + 257340638.01, + 238801689.93, + 251976806.54, + 288584148, + 288584148, + 288584148, + 288584148, + 288584148, + 288584148, + 288584148, + 288584148, + 288584148, + 288584148, + 186830459.77, + 128637295.24, + 187399676, + 187399676, + 187399676, + 187399676, + 187399676, + 187399676, + 187399676, + 187399676, + 187399676, + 187399676, + 187399676, + 128653847.91, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 64156680, + 38517552.2, + 10368300, + 10368300, + 10368300, + 10368300, + 10368300, + 10368300, + 10368300, + 10368300, + 10368300, + 10368300, + 9097165.2267, + 7682804, + 7682804, + 7682804, + 7682804, + 7682804, + 7682804, + 7682804, + 7682804, + 7682804, + 4386945.92, + 670340, + 670340, + 670340, + 670340, + 670340, + 670340, + 670340, + 670340, + 573501.2, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 464300, + 105221194.23, + 223351309, + 223351309, + 223351309, + 223351309, + 231537164.72, + 337387099.68, + 298792029, + 298792029, + 298792029, + 298809162.27, + 299036790, + 299036790, + 296149074.19, + 257783707, + 257783707, + 257783707, + 262884434.38, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 330651241, + 331120621.73, + 315063592.89, + 18884007, + 18884007, + 18884007, + 18884007, + 18884007, + 3107364.36, + 749935, + 749935, + 749935, + 749935, + 749935, + 749935, + 749935, + 251633.8, + 177175, + 177175, + 177175, + 177175, + 177175, + 177175, + 177175, + 177175, + 177175, + 47990.44, + 28687, + 28687, + 28687, + 28687, + 28687, + 28687, + 28687, + 114925814.68, + 132094351, + 132094351, + 132094351, + 132094351, + 132094351, + 132094351, + 132094351, + 132094351, + 132094351, + 132094351, + 132094351, + 132094351, + 253196701.48, + 271292455, + 271292455, + 271292455, + 271292455, + 271292455, + 271292455, + 271292455, + 285387781.79, + 253248736.66, + 186446431.82, + 172196696, + 172196696, + null + ], + "prints": [["Last:172196696.00"], ["Average:118644866.56"]], + "last_value": 172196696, + "minimum_value": null, + "maximum_value": null, + "average_value": 118644866.56 + }, + { + "index_id": 5397, + "metric_id": 13072, + "metric": "mem_inactive", + "metric_legend": "mem_inactive", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 29, + "host_id": null, + "service_id": null, + "name": "Memory-stats-inactive", + "ds_order": 5, + "ds_hidecurve": null, + "ds_name": "mem_inactive", + "ds_color_line": "#91876E", + "ds_color_line_mode": "0", + "ds_color_area": "#91876E", + "ds_color_area_warn": "#91876E", + "ds_color_area_crit": "#91876E", + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "10", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": "1", + "default_tpl1": null, + "comment": null + }, + "legend": "mem_inactive", + "stack": "1", + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 5, + "data": [ + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 78174332, + 84397956.413, + 100669360, + 100669360, + 100669360, + 100669360, + 100669360, + 85037735.11, + 44169511, + 44169511, + 138186268.11, + 334429102.58, + 204856540, + 204856540, + 204856540, + 266905172.87, + 417538119.81, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 277947135, + 456831211.17, + 481997412, + 481997412, + 481997412, + 481997412, + 481997412, + 481997412, + 481997412, + 481997412, + 481997412, + 481997412, + 481997412, + 121519411.11, + 70805776, + 70805776, + 70805776, + 70805776, + 70805776, + 70805776, + 70805776, + 70805776, + 70805776, + 70805776, + 70805776, + 14874547.867, + 7005896, + 97493389.33, + 110223569, + 110223569, + 110223569, + 110223569, + 82766160.353, + 78903331, + 78903331, + 78903331, + 78903331, + 78903331, + 78903331, + 78903331, + 78903331, + 361860746.73, + 401668444, + 401668444, + 401668444, + 401668444, + 401668444, + 401668444, + 401668444, + 401668444, + 443765650.34, + 339668456.03, + 346882883.6, + 412521374, + 412521374, + 412521374, + 412521374, + 412521374, + 412521374, + 412521374, + 412521374, + 412521374, + 412521374, + 284942314.77, + 265374316.08, + 397672966, + 397672966, + 397672966, + 397672966, + 397672966, + 397672966, + 397672966, + 397672966, + 397672966, + 397672966, + 397672966, + 238462035.07, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 63664020, + 40019224.54, + 14059554, + 14059554, + 14059554, + 14059554, + 14059554, + 14059554, + 14059554, + 14059554, + 14059554, + 14059554, + 9025003.1667, + 3423179, + 3423179, + 3423179, + 3423179, + 3423179, + 3423179, + 3423179, + 3423179, + 3423179, + 2992653.83, + 2507168, + 2507168, + 2507168, + 2507168, + 2507168, + 2507168, + 2507168, + 2507168, + 2373775.89, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 2223355, + 208213620.2, + 440500515, + 440500515, + 440500515, + 440500515, + 442135076.11, + 435862503.86, + 64010186, + 64010186, + 64010186, + 85934393.62, + 377213152, + 377213152, + 356856826.5, + 86408502, + 86408502, + 86408502, + 103265039.74, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 327216184, + 336353686.99, + 457049389.5, + 447715491, + 447715491, + 447715491, + 447715491, + 447715491, + 359026791.42, + 345774457, + 345774457, + 345774457, + 345774457, + 345774457, + 345774457, + 345774457, + 128463407.08, + 95991641, + 95991641, + 95991641, + 95991641, + 95991641, + 95991641, + 95991641, + 95991641, + 95991641, + 86254514, + 84799541, + 84799541, + 84799541, + 84799541, + 84799541, + 84799541, + 84799541, + 117187388.57, + 122026952, + 122026952, + 122026952, + 122026952, + 122026952, + 122026952, + 122026952, + 122026952, + 122026952, + 122026952, + 122026952, + 122026952, + 196747423.13, + 207912551, + 207912551, + 207912551, + 207912551, + 207912551, + 207912551, + 207912551, + 326892127.45, + 316977681.63, + 105944222.97, + 51188466, + 51188466, + null + ], + "prints": [["Last:51188466.00"], ["Average:183852943.55"]], + "last_value": 51188466, + "minimum_value": null, + "maximum_value": null, + "average_value": 183852943.55 + }, + { + "index_id": 5397, + "metric_id": 13067, + "metric": "mem_buffer", + "metric_legend": "mem_buffer", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 30, + "host_id": null, + "service_id": null, + "name": "Memory-stats-buffer", + "ds_order": 6, + "ds_hidecurve": null, + "ds_name": "mem_buffer", + "ds_color_line": "#1209F5", + "ds_color_line_mode": "0", + "ds_color_area": "#1209F5", + "ds_color_area_warn": "#1209F5", + "ds_color_area_crit": "#1209F5", + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "10", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": "1", + "default_tpl1": null, + "comment": null + }, + "legend": "mem_buffer", + "stack": "1", + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 6, + "data": [ + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 37552729, + 191708687.1, + 594742939, + 594742939, + 594742939, + 594742939, + 594742939, + 540393727.81, + 398300007, + 398300007, + 480586455.45, + 625139901.46, + 440608844, + 440608844, + 440608844, + 467841282.06, + 537710601.72, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 521707935, + 696259169.45, + 720815807, + 720815807, + 720815807, + 720815807, + 720815807, + 720815807, + 720815807, + 720815807, + 720815807, + 720815807, + 720815807, + 113953070.44, + 28576944, + 28576944, + 28576944, + 28576944, + 28576944, + 28576944, + 28576944, + 28576944, + 28576944, + 28576944, + 28576944, + 16222688.197, + 14484637, + 236373711.35, + 267590045, + 267590045, + 267590045, + 267590045, + 195705498.99, + 185592464, + 185592464, + 185592464, + 185592464, + 185592464, + 185592464, + 185592464, + 185592464, + 650575197.22, + 715991019, + 715991019, + 715991019, + 715991019, + 715991019, + 715991019, + 715991019, + 715991019, + 838061375.8, + 281973265.07, + 328841897.77, + 681039689, + 681039689, + 681039689, + 681039689, + 681039689, + 681039689, + 681039689, + 681039689, + 681039689, + 681039689, + 445778518.09, + 419835812, + 674934492, + 674934492, + 674934492, + 674934492, + 674934492, + 674934492, + 674934492, + 674934492, + 674934492, + 674934492, + 674934492, + 424722024.73, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 150013232, + 145144937.14, + 139800026, + 139800026, + 139800026, + 139800026, + 139800026, + 139800026, + 139800026, + 139800026, + 139800026, + 139800026, + 137569339.95, + 135087309, + 135087309, + 135087309, + 135087309, + 135087309, + 135087309, + 135087309, + 135087309, + 135087309, + 122012400.62, + 107268355, + 107268355, + 107268355, + 107268355, + 107268355, + 107268355, + 107268355, + 107268355, + 98034856.26, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 87622613, + 404735924.31, + 762331786, + 762331786, + 762331786, + 762331786, + 766513542.81, + 809009098.93, + 635470168, + 635470168, + 635470168, + 638174903.11, + 674109241, + 674109241, + 647779351.33, + 297967960, + 297967960, + 297967960, + 312033490.01, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 498904103, + 513191502.42, + 659509551.15, + 81577554, + 81577554, + 81577554, + 81577554, + 81577554, + 45720144.69, + 40362141, + 40362141, + 40362141, + 40362141, + 40362141, + 40362141, + 40362141, + 19195506.45, + 16032676, + 16032676, + 16032676, + 16032676, + 16032676, + 16032676, + 16032676, + 16032676, + 16032676, + 5517032.98, + 3945730, + 3945730, + 3945730, + 3945730, + 3945730, + 3945730, + 3945730, + 462388009.63, + 530890879, + 530890879, + 530890879, + 530890879, + 530890879, + 530890879, + 530890879, + 530890879, + 530890879, + 530890879, + 530890879, + 530890879, + 617384949.64, + 630309351, + 630309351, + 630309351, + 630309351, + 630309351, + 630309351, + 630309351, + 638703189.57, + 584936985.36, + 354641768.23, + 175353479, + 175353479, + null + ], + "prints": [["Last:175353479.00"], ["Average:332234252.08"]], + "last_value": 175353479, + "minimum_value": null, + "maximum_value": null, + "average_value": 332234252.08 + }, + { + "index_id": 5397, + "metric_id": 13068, + "metric": "mem_cache", + "metric_legend": "mem_cache", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 31, + "host_id": null, + "service_id": null, + "name": "Memory-stats-cache", + "ds_order": 7, + "ds_hidecurve": null, + "ds_name": "mem_cache", + "ds_color_line": "#C738B3", + "ds_color_line_mode": "0", + "ds_color_area": "#C738B3", + "ds_color_area_warn": "#C738B3", + "ds_color_area_crit": "#C738B3", + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "10", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": "1", + "default_tpl1": null, + "comment": null + }, + "legend": "mem_cache", + "stack": "1", + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 7, + "data": [ + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2366932380, + 2525106295.6, + 2938645328, + 2938645328, + 2938645328, + 2938645328, + 2938645328, + 2351768818.4, + 817404932, + 817404932, + 1645987946.6, + 3207589652.9, + 1626643617, + 1626643617, + 1626643617, + 2160810351.6, + 3323027980.6, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 500774058, + 2333026907.7, + 2590796320, + 2590796320, + 2590796320, + 2590796320, + 2590796320, + 2590796320, + 2590796320, + 2590796320, + 2590796320, + 2590796320, + 2590796320, + 1910659820.6, + 1814975218, + 1814975218, + 1814975218, + 1814975218, + 1814975218, + 1814975218, + 1814975218, + 1814975218, + 1814975218, + 1814975218, + 1814975218, + 1222898572, + 1139602618, + 1443507739.1, + 1486262452, + 1486262452, + 1486262452, + 1486262452, + 1479102156.9, + 1478094815, + 1478094815, + 1478094815, + 1478094815, + 1478094815, + 1478094815, + 1478094815, + 1478094815, + 3660937859.7, + 3968029847, + 3968029847, + 3968029847, + 3968029847, + 3968029847, + 3968029847, + 3968029847, + 3968029847, + 4183448669.9, + 2332788260.5, + 2874868720.4, + 4456800060, + 4456800060, + 4456800060, + 4456800060, + 4456800060, + 4456800060, + 4456800060, + 4456800060, + 4456800060, + 4456800060, + 3221762121.1, + 2425597488.2, + 3040187834, + 3040187834, + 3040187834, + 3040187834, + 3040187834, + 3040187834, + 3040187834, + 3040187834, + 3040187834, + 3040187834, + 3040187834, + 2657943826.1, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 2238277328, + 1398491748, + 476489398, + 476489398, + 476489398, + 476489398, + 476489398, + 476489398, + 476489398, + 476489398, + 476489398, + 476489398, + 286775000.57, + 75684333, + 75684333, + 75684333, + 75684333, + 75684333, + 75684333, + 75684333, + 75684333, + 75684333, + 72587698.52, + 69095749, + 69095749, + 69095749, + 69095749, + 69095749, + 69095749, + 69095749, + 69095749, + 54257856.05, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 37525764, + 2408894455.5, + 5082991065, + 5082991065, + 5082991065, + 5082991065, + 5086825971.8, + 5115011610.7, + 4812577773, + 4812577773, + 4812577773, + 4824094075.7, + 4977096383, + 4977096383, + 4809771214.1, + 2586736827, + 2586736827, + 2586736827, + 2601799952.6, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2801924335, + 2949784835.2, + 4695957105.6, + 1796215918, + 1796215918, + 1796215918, + 1796215918, + 1796215918, + 1759041364.4, + 1753486546, + 1753486546, + 1753486546, + 1753486546, + 1753486546, + 1753486546, + 1753486546, + 1184101489.7, + 1099020964, + 1099020964, + 1099020964, + 1099020964, + 1099020964, + 1099020964, + 1099020964, + 1099020964, + 1099020964, + 985758279.22, + 968833970, + 968833970, + 968833970, + 968833970, + 968833970, + 968833970, + 968833970, + 3623849409.9, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4020575855, + 4886590537.3, + 5015995030, + 5015995030, + 5015995030, + 5015995030, + 5015995030, + 5015995030, + 5015995030, + 5048183774.8, + 4637944118.6, + 3658964974.6, + 3122834181, + 3122834181, + null + ], + "prints": [["Last:3122834181.00"], ["Average:2112555251.91"]], + "last_value": 3122834181, + "minimum_value": null, + "maximum_value": null, + "average_value": 2112555251.91 + }, + { + "index_id": 5397, + "metric_id": 13074, + "metric": "mem_unused", + "metric_legend": "mem_unused", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 32, + "host_id": null, + "service_id": null, + "name": "Memory-stats-unused", + "ds_order": 8, + "ds_hidecurve": null, + "ds_name": "mem_unused", + "ds_color_line": "#01FD0B", + "ds_color_line_mode": "0", + "ds_color_area": "#01FD0B", + "ds_color_area_warn": "#01FD0B", + "ds_color_area_crit": "#01FD0B", + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "10", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": "1", + "default_tpl1": null, + "comment": null + }, + "legend": "mem_unused", + "stack": "1", + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 8, + "data": [ + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12604211456, + 12005689577, + 10440879364, + 10440879364, + 10440879364, + 10440879364, + 10440879364, + 11406102684, + 13929638353, + 13929638353, + 12006913654, + 8648217781.3, + 13009621760, + 13009621760, + 13009621760, + 10225170513, + 3837957762, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 14588178615, + 7811772312.9, + 6858437586, + 6858437586, + 6858437586, + 6858437586, + 6858437586, + 6858437586, + 6858437586, + 6858437586, + 6858437586, + 6858437586, + 6858437586, + 9244649163.5, + 9580351933, + 9580351933, + 9580351933, + 9580351933, + 9580351933, + 9580351933, + 9580351933, + 9580351933, + 9580351933, + 9580351933, + 9580351933, + 12477473892, + 12885053787, + 11116729036, + 10867953311, + 10867953311, + 10867953311, + 10867953311, + 13763220474, + 14170539429, + 14170539429, + 14170539429, + 14170539429, + 14170539429, + 14170539429, + 14170539429, + 14170539429, + 5922547674.1, + 4762183815, + 4762183815, + 4762183815, + 4762183815, + 4762183815, + 4762183815, + 4762183815, + 4762183815, + 3424407319.8, + 9060558883.2, + 8229225316.2, + 4260967797, + 4260967797, + 4260967797, + 4260967797, + 4260967797, + 4260967797, + 4260967797, + 4260967797, + 4260967797, + 4260967797, + 6615600706.2, + 7709703112.6, + 6072671793, + 6072671793, + 6072671793, + 6072671793, + 6072671793, + 6072671793, + 6072671793, + 6072671793, + 6072671793, + 6072671793, + 6072671793, + 9558679025.8, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 13385973680, + 14537075569, + 15800872747, + 15800872747, + 15800872747, + 15800872747, + 15800872747, + 15800872747, + 15800872747, + 15800872747, + 15800872747, + 15800872747, + 16129502883, + 16495161767, + 16495161767, + 16495161767, + 16495161767, + 16495161767, + 16495161767, + 16495161767, + 16495161767, + 16495161767, + 16579694331, + 16675018286, + 16675018286, + 16675018286, + 16675018286, + 16675018286, + 16675018286, + 16675018286, + 16675018286, + 16823164414, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 16990222813, + 10184312969, + 2509563570, + 2509563570, + 2509563570, + 2509563570, + 2401111652.8, + 1523745344.1, + 9010177283, + 9010177283, + 9010177283, + 8668718775.2, + 4132198600, + 4132198600, + 4559489214.7, + 10236350238, + 10236350238, + 10236350238, + 9950666762.9, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 6155157736, + 5958347556.1, + 3889418312.9, + 11141220536, + 11141220536, + 11141220536, + 11141220536, + 11141220536, + 12199109977, + 12357185411, + 12357185411, + 12357185411, + 12357185411, + 12357185411, + 12357185411, + 12357185411, + 14378301279, + 14680307098, + 14680307098, + 14680307098, + 14680307098, + 14680307098, + 14680307098, + 14680307098, + 14680307098, + 14680307098, + 15490267380, + 15611295928, + 15611295928, + 15611295928, + 15611295928, + 15611295928, + 15611295928, + 15611295928, + 6577275738.8, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 5227364676, + 2691263531.3, + 2312305889, + 2312305889, + 2312305889, + 2312305889, + 2312305889, + 2312305889, + 2312305889, + 1738663451.3, + 3413143441.8, + 8299880453.1, + 10858585866, + 10858585866, + null + ], + "prints": [["Last:10858585866.00"], ["Average:10877585519.89"]], + "last_value": 10858585866, + "minimum_value": null, + "maximum_value": null, + "average_value": 10877585519.89 + } + ], + "times": [ + "2023-06-06T12:45:00+02:00", + "2023-06-06T12:50:00+02:00", + "2023-06-06T12:55:00+02:00", + "2023-06-06T13:00:00+02:00", + "2023-06-06T13:05:00+02:00", + "2023-06-06T13:10:00+02:00", + "2023-06-06T13:15:00+02:00", + "2023-06-06T13:20:00+02:00", + "2023-06-06T13:25:00+02:00", + "2023-06-06T13:30:00+02:00", + "2023-06-06T13:35:00+02:00", + "2023-06-06T13:40:00+02:00", + "2023-06-06T13:45:00+02:00", + "2023-06-06T13:50:00+02:00", + "2023-06-06T13:55:00+02:00", + "2023-06-06T14:00:00+02:00", + "2023-06-06T14:05:00+02:00", + "2023-06-06T14:10:00+02:00", + "2023-06-06T14:15:00+02:00", + "2023-06-06T14:20:00+02:00", + "2023-06-06T14:25:00+02:00", + "2023-06-06T14:30:00+02:00", + "2023-06-06T14:35:00+02:00", + "2023-06-06T14:40:00+02:00", + "2023-06-06T14:45:00+02:00", + "2023-06-06T14:50:00+02:00", + "2023-06-06T14:55:00+02:00", + "2023-06-06T15:00:00+02:00", + "2023-06-06T15:05:00+02:00", + "2023-06-06T15:10:00+02:00", + "2023-06-06T15:15:00+02:00", + "2023-06-06T15:20:00+02:00", + "2023-06-06T15:25:00+02:00", + "2023-06-06T15:30:00+02:00", + "2023-06-06T15:35:00+02:00", + "2023-06-06T15:40:00+02:00", + "2023-06-06T15:45:00+02:00", + "2023-06-06T15:50:00+02:00", + "2023-06-06T15:55:00+02:00", + "2023-06-06T16:00:00+02:00", + "2023-06-06T16:05:00+02:00", + "2023-06-06T16:10:00+02:00", + "2023-06-06T16:15:00+02:00", + "2023-06-06T16:20:00+02:00", + "2023-06-06T16:25:00+02:00", + "2023-06-06T16:30:00+02:00", + "2023-06-06T16:35:00+02:00", + "2023-06-06T16:40:00+02:00", + "2023-06-06T16:45:00+02:00", + "2023-06-06T16:50:00+02:00", + "2023-06-06T16:55:00+02:00", + "2023-06-06T17:00:00+02:00", + "2023-06-06T17:05:00+02:00", + "2023-06-06T17:10:00+02:00", + "2023-06-06T17:15:00+02:00", + "2023-06-06T17:20:00+02:00", + "2023-06-06T17:25:00+02:00", + "2023-06-06T17:30:00+02:00", + "2023-06-06T17:35:00+02:00", + "2023-06-06T17:40:00+02:00", + "2023-06-06T17:45:00+02:00", + "2023-06-06T17:50:00+02:00", + "2023-06-06T17:55:00+02:00", + "2023-06-06T18:00:00+02:00", + "2023-06-06T18:05:00+02:00", + "2023-06-06T18:10:00+02:00", + "2023-06-06T18:15:00+02:00", + "2023-06-06T18:20:00+02:00", + "2023-06-06T18:25:00+02:00", + "2023-06-06T18:30:00+02:00", + "2023-06-06T18:35:00+02:00", + "2023-06-06T18:40:00+02:00", + "2023-06-06T18:45:00+02:00", + "2023-06-06T18:50:00+02:00", + "2023-06-06T18:55:00+02:00", + "2023-06-06T19:00:00+02:00", + "2023-06-06T19:05:00+02:00", + "2023-06-06T19:10:00+02:00", + "2023-06-06T19:15:00+02:00", + "2023-06-06T19:20:00+02:00", + "2023-06-06T19:25:00+02:00", + "2023-06-06T19:30:00+02:00", + "2023-06-06T19:35:00+02:00", + "2023-06-06T19:40:00+02:00", + "2023-06-06T19:45:00+02:00", + "2023-06-06T19:50:00+02:00", + "2023-06-06T19:55:00+02:00", + "2023-06-06T20:00:00+02:00", + "2023-06-06T20:05:00+02:00", + "2023-06-06T20:10:00+02:00", + "2023-06-06T20:15:00+02:00", + "2023-06-06T20:20:00+02:00", + "2023-06-06T20:25:00+02:00", + "2023-06-06T20:30:00+02:00", + "2023-06-06T20:35:00+02:00", + "2023-06-06T20:40:00+02:00", + "2023-06-06T20:45:00+02:00", + "2023-06-06T20:50:00+02:00", + "2023-06-06T20:55:00+02:00", + "2023-06-06T21:00:00+02:00", + "2023-06-06T21:05:00+02:00", + "2023-06-06T21:10:00+02:00", + "2023-06-06T21:15:00+02:00", + "2023-06-06T21:20:00+02:00", + "2023-06-06T21:25:00+02:00", + "2023-06-06T21:30:00+02:00", + "2023-06-06T21:35:00+02:00", + "2023-06-06T21:40:00+02:00", + "2023-06-06T21:45:00+02:00", + "2023-06-06T21:50:00+02:00", + "2023-06-06T21:55:00+02:00", + "2023-06-06T22:00:00+02:00", + "2023-06-06T22:05:00+02:00", + "2023-06-06T22:10:00+02:00", + "2023-06-06T22:15:00+02:00", + "2023-06-06T22:20:00+02:00", + "2023-06-06T22:25:00+02:00", + "2023-06-06T22:30:00+02:00", + "2023-06-06T22:35:00+02:00", + "2023-06-06T22:40:00+02:00", + "2023-06-06T22:45:00+02:00", + "2023-06-06T22:50:00+02:00", + "2023-06-06T22:55:00+02:00", + "2023-06-06T23:00:00+02:00", + "2023-06-06T23:05:00+02:00", + "2023-06-06T23:10:00+02:00", + "2023-06-06T23:15:00+02:00", + "2023-06-06T23:20:00+02:00", + "2023-06-06T23:25:00+02:00", + "2023-06-06T23:30:00+02:00", + "2023-06-06T23:35:00+02:00", + "2023-06-06T23:40:00+02:00", + "2023-06-06T23:45:00+02:00", + "2023-06-06T23:50:00+02:00", + "2023-06-06T23:55:00+02:00", + "2023-06-07T00:00:00+02:00", + "2023-06-07T00:05:00+02:00", + "2023-06-07T00:10:00+02:00", + "2023-06-07T00:15:00+02:00", + "2023-06-07T00:20:00+02:00", + "2023-06-07T00:25:00+02:00", + "2023-06-07T00:30:00+02:00", + "2023-06-07T00:35:00+02:00", + "2023-06-07T00:40:00+02:00", + "2023-06-07T00:45:00+02:00", + "2023-06-07T00:50:00+02:00", + "2023-06-07T00:55:00+02:00", + "2023-06-07T01:00:00+02:00", + "2023-06-07T01:05:00+02:00", + "2023-06-07T01:10:00+02:00", + "2023-06-07T01:15:00+02:00", + "2023-06-07T01:20:00+02:00", + "2023-06-07T01:25:00+02:00", + "2023-06-07T01:30:00+02:00", + "2023-06-07T01:35:00+02:00", + "2023-06-07T01:40:00+02:00", + "2023-06-07T01:45:00+02:00", + "2023-06-07T01:50:00+02:00", + "2023-06-07T01:55:00+02:00", + "2023-06-07T02:00:00+02:00", + "2023-06-07T02:05:00+02:00", + "2023-06-07T02:10:00+02:00", + "2023-06-07T02:15:00+02:00", + "2023-06-07T02:20:00+02:00", + "2023-06-07T02:25:00+02:00", + "2023-06-07T02:30:00+02:00", + "2023-06-07T02:35:00+02:00", + "2023-06-07T02:40:00+02:00", + "2023-06-07T02:45:00+02:00", + "2023-06-07T02:50:00+02:00", + "2023-06-07T02:55:00+02:00", + "2023-06-07T03:00:00+02:00", + "2023-06-07T03:05:00+02:00", + "2023-06-07T03:10:00+02:00", + "2023-06-07T03:15:00+02:00", + "2023-06-07T03:20:00+02:00", + "2023-06-07T03:25:00+02:00", + "2023-06-07T03:30:00+02:00", + "2023-06-07T03:35:00+02:00", + "2023-06-07T03:40:00+02:00", + "2023-06-07T03:45:00+02:00", + "2023-06-07T03:50:00+02:00", + "2023-06-07T03:55:00+02:00", + "2023-06-07T04:00:00+02:00", + "2023-06-07T04:05:00+02:00", + "2023-06-07T04:10:00+02:00", + "2023-06-07T04:15:00+02:00", + "2023-06-07T04:20:00+02:00", + "2023-06-07T04:25:00+02:00", + "2023-06-07T04:30:00+02:00", + "2023-06-07T04:35:00+02:00", + "2023-06-07T04:40:00+02:00", + "2023-06-07T04:45:00+02:00", + "2023-06-07T04:50:00+02:00", + "2023-06-07T04:55:00+02:00", + "2023-06-07T05:00:00+02:00", + "2023-06-07T05:05:00+02:00", + "2023-06-07T05:10:00+02:00", + "2023-06-07T05:15:00+02:00", + "2023-06-07T05:20:00+02:00", + "2023-06-07T05:25:00+02:00", + "2023-06-07T05:30:00+02:00", + "2023-06-07T05:35:00+02:00", + "2023-06-07T05:40:00+02:00", + "2023-06-07T05:45:00+02:00", + "2023-06-07T05:50:00+02:00", + "2023-06-07T05:55:00+02:00", + "2023-06-07T06:00:00+02:00", + "2023-06-07T06:05:00+02:00", + "2023-06-07T06:10:00+02:00", + "2023-06-07T06:15:00+02:00", + "2023-06-07T06:20:00+02:00", + "2023-06-07T06:25:00+02:00", + "2023-06-07T06:30:00+02:00", + "2023-06-07T06:35:00+02:00", + "2023-06-07T06:40:00+02:00", + "2023-06-07T06:45:00+02:00", + "2023-06-07T06:50:00+02:00", + "2023-06-07T06:55:00+02:00", + "2023-06-07T07:00:00+02:00", + "2023-06-07T07:05:00+02:00", + "2023-06-07T07:10:00+02:00", + "2023-06-07T07:15:00+02:00", + "2023-06-07T07:20:00+02:00", + "2023-06-07T07:25:00+02:00", + "2023-06-07T07:30:00+02:00", + "2023-06-07T07:35:00+02:00", + "2023-06-07T07:40:00+02:00", + "2023-06-07T07:45:00+02:00", + "2023-06-07T07:50:00+02:00", + "2023-06-07T07:55:00+02:00", + "2023-06-07T08:00:00+02:00", + "2023-06-07T08:05:00+02:00", + "2023-06-07T08:10:00+02:00", + "2023-06-07T08:15:00+02:00", + "2023-06-07T08:20:00+02:00", + "2023-06-07T08:25:00+02:00", + "2023-06-07T08:30:00+02:00", + "2023-06-07T08:35:00+02:00", + "2023-06-07T08:40:00+02:00", + "2023-06-07T08:45:00+02:00", + "2023-06-07T08:50:00+02:00", + "2023-06-07T08:55:00+02:00", + "2023-06-07T09:00:00+02:00", + "2023-06-07T09:05:00+02:00", + "2023-06-07T09:10:00+02:00", + "2023-06-07T09:15:00+02:00", + "2023-06-07T09:20:00+02:00", + "2023-06-07T09:25:00+02:00", + "2023-06-07T09:30:00+02:00", + "2023-06-07T09:35:00+02:00", + "2023-06-07T09:40:00+02:00", + "2023-06-07T09:45:00+02:00", + "2023-06-07T09:50:00+02:00", + "2023-06-07T09:55:00+02:00", + "2023-06-07T10:00:00+02:00", + "2023-06-07T10:05:00+02:00", + "2023-06-07T10:10:00+02:00", + "2023-06-07T10:15:00+02:00", + "2023-06-07T10:20:00+02:00", + "2023-06-07T10:25:00+02:00", + "2023-06-07T10:30:00+02:00", + "2023-06-07T10:35:00+02:00", + "2023-06-07T10:40:00+02:00", + "2023-06-07T10:45:00+02:00", + "2023-06-07T10:50:00+02:00", + "2023-06-07T10:55:00+02:00", + "2023-06-07T11:00:00+02:00", + "2023-06-07T11:05:00+02:00", + "2023-06-07T11:10:00+02:00", + "2023-06-07T11:15:00+02:00", + "2023-06-07T11:20:00+02:00", + "2023-06-07T11:25:00+02:00", + "2023-06-07T11:30:00+02:00", + "2023-06-07T11:35:00+02:00", + "2023-06-07T11:40:00+02:00", + "2023-06-07T11:45:00+02:00", + "2023-06-07T11:50:00+02:00", + "2023-06-07T11:55:00+02:00", + "2023-06-07T12:00:00+02:00", + "2023-06-07T12:05:00+02:00", + "2023-06-07T12:10:00+02:00", + "2023-06-07T12:15:00+02:00", + "2023-06-07T12:20:00+02:00", + "2023-06-07T12:25:00+02:00", + "2023-06-07T12:30:00+02:00", + "2023-06-07T12:35:00+02:00", + "2023-06-07T12:40:00+02:00", + "2023-06-07T12:45:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/lastDayForward.json b/centreon/packages/ui/src/Graph/mockedData/lastDayForward.json new file mode 100644 index 0000000000..21531a5a45 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/lastDayForward.json @@ -0,0 +1,1305 @@ +{ + "global": { + "title": "oracle-shared-spool-ratio graph on srv-oracle-users", + "start": "2023-06-07T09:27:07+02:00", + "end": "2023-06-08T09:27:07+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 0, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 4811, + "metric_id": 11758, + "metric": "connTime", + "metric_legend": "connTime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#ff99cc" + }, + "legend": "connTime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.05376, + 0.338, + 0.63248, + 0.18326666667, + 0.36706666667, + 0.099166666667, + 0.31305, + 0.37373333333, + 0.43933333333, + 0.464, + 0.35258333333, + 0.28791666667, + 0.56913333333, + 0.76703333333, + 0.67518333333, + 0.90208333333, + 0.32488333333, + 0.47813333333, + 0.071966666667, + 0.3686, + 0.8341, + 0.77396666667, + 0.34295, + 0.51203333333, + 0.23581666667, + 0.14966666667, + 0.53633333333, + 0.66725, + 0.44083333333, + 0.40603333333, + 0.76311666667, + 0.76126666667, + 0.20203333333, + 0.50725, + 0.37375, + 0.7752, + 0.71796666667, + 0.65141666667, + 0.63618333333, + 0.46131666667, + 0.63278333333, + 0.77115, + 0.47151666667, + 0.63983333333, + 0.6915, + 0.55061666667, + 0.7759, + 0.79126666667, + 0.38161666667, + 0.42606666667, + 0.75068333333, + 0.40968333333, + 0.6918, + 0.44128333333, + 0.46593333333, + 0.20545, + 0.61953333333, + 0.72133333333, + 0.61795, + 0.7154, + 0.30433333333, + 0.38171666667, + 0.17726666667, + 0.19431666667, + 0.33643333333, + 0.73506666667, + 0.90695, + 0.83988333333, + 0.92438333333, + 0.54573333333, + 0.3909, + 0.82456666667, + 0.5597, + 0.66463333333, + 0.66005, + 0.52756666667, + 0.67001666667, + 0.4347, + 0.20076666667, + 0.199, + 0.45465, + 0.7167, + 0.4992, + 0.7525, + 0.68343333333, + 0.18691666667, + 0.10928333333, + 0.49846666667, + 0.20756666667, + 0.57808333333, + 0.5091, + 0.21378333333, + 0.33466666667, + 0.35905, + 0.7782, + 0.31376666667, + 0.30773333333, + 0.55781666667, + 0.61033333333, + 0.61753333333, + 0.78033333333, + 0.67196666667, + 0.83675, + 0.5666, + 0.31156666667, + 0.74395, + 0.58471666667, + 0.73915, + 0.411, + 0.25175, + 0.44345, + 0.85811666667, + 0.78576666667, + 0.54195, + 0.6819, + 0.77463333333, + 0.53966666667, + 0.081583333333, + 0.0105, + 0.66158333333, + 0.19941666667, + 0.3885, + 0.72716666667, + 0.34625, + 0.15866666667, + 0.80133333333, + 0.35021666667, + 0.40711666667, + 0.31185, + 0.50205, + 0.88026666667, + 0.57613333333, + 0.43963333333, + 0.32051666667, + 0.50523333333, + 0.6505, + 0.55111666667, + 0.5942, + 0.72986666667, + 0.95238333333, + 0.68285, + 0.46565, + 0.63016666667, + 0.45605, + 0.38395, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "prints": [["Last:0.38"], ["Min:0.01"], ["Max:0.95"], ["Average:0.51"]], + "last_value": 0.38, + "minimum_value": 0.01, + "maximum_value": 0.95, + "average_value": 0.51 + }, + { + "index_id": 4811, + "metric_id": 11757, + "metric": "querytime", + "metric_legend": "querytime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#6666ff" + }, + "legend": "querytime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.69412, + 0.29608, + 0.64332, + 0.78435, + 0.49911666667, + 0.26918333333, + 0.91718333333, + 0.5858, + 0.19691666667, + 0.44683333333, + 0.33975, + 0.23175, + 0.54105, + 0.58516666667, + 0.62908333333, + 0.21381666667, + 0.054433333333, + 0.41883333333, + 0.55065, + 0.74241666667, + 0.20685, + 0.73463333333, + 0.67131666667, + 0.27435, + 0.34288333333, + 0.7709, + 0.92633333333, + 0.6353, + 0.7674, + 0.79433333333, + 0.6929, + 0.36873333333, + 0.15238333333, + 0.45986666667, + 0.72241666667, + 0.71251666667, + 0.39875, + 0.70755, + 0.60123333333, + 0.83198333333, + 0.9789, + 0.57765, + 0.17835, + 0.5656, + 0.36398333333, + 0.46198333333, + 0.31618333333, + 0.3781, + 0.25323333333, + 0.1532, + 0.04195, + 0.23205, + 0.78596666667, + 0.43723333333, + 0.28218333333, + 0.72755, + 0.77603333333, + 0.68743333333, + 0.66741666667, + 0.34995, + 0.37335, + 0.69358333333, + 0.27455, + 0.28013333333, + 0.71015, + 0.50801666667, + 0.45211666667, + 0.76751666667, + 0.75243333333, + 0.2591, + 0.43015, + 0.36633333333, + 0.66898333333, + 0.79993333333, + 0.38278333333, + 0.43815, + 0.7089, + 0.57918333333, + 0.36856666667, + 0.65455, + 0.74285, + 0.91205, + 0.78031666667, + 0.71691666667, + 0.69246666667, + 0.5553, + 0.81631666667, + 0.82576666667, + 0.64196666667, + 0.35766666667, + 0.52513333333, + 0.59181666667, + 0.48015, + 0.17466666667, + 0.53273333333, + 0.78308333333, + 0.49533333333, + 0.71715, + 0.45326666667, + 0.34505, + 0.55813333333, + 0.58506666667, + 0.51556666667, + 0.25808333333, + 0.32178333333, + 0.87881666667, + 0.73263333333, + 0.29503333333, + 0.51955, + 0.80328333333, + 0.61133333333, + 0.88905, + 0.73008333333, + 0.46576666667, + 0.75335, + 0.64886666667, + 0.46566666667, + 0.23391666667, + 0.32333333333, + 0.06075, + 0.52183333333, + 0.75116666667, + 0.65341666667, + 0.41658333333, + 0.044, + 0.5455, + 0.66271666667, + 0.45943333333, + 0.34365, + 0.62895, + 0.69748333333, + 0.57913333333, + 0.42935, + 0.3825, + 0.5489, + 0.61453333333, + 0.52853333333, + 0.58836666667, + 0.70246666667, + 0.68868333333, + 0.69335, + 0.4246, + 0.40923333333, + 0.8041, + 0.6626, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "prints": [["Last:0.66"], ["Min:0.04"], ["Max:0.98"], ["Average:0.54"]], + "last_value": 0.66, + "minimum_value": 0.04, + "maximum_value": 0.98, + "average_value": 0.54 + }, + { + "index_id": 4811, + "metric_id": 11756, + "metric": "used", + "metric_legend": "used", + "unit": "%", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 8, + "host_id": null, + "service_id": null, + "name": "Used", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": "used", + "ds_color_line": "#2B28D7", + "ds_color_line_mode": "0", + "ds_color_area": "#050AF9", + "ds_color_area_warn": null, + "ds_color_area_crit": null, + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "used", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 1, + "data": [ + 81.5376, + 82.84972, + 83.50108, + 84.304366667, + 85.243566667, + 84.993333333, + 85.029616667, + 85.006383333, + 87.494416667, + 87.404, + 85.760416667, + 84.159166667, + 84.6812, + 84.468933333, + 84.2907, + 85.632833333, + 86.488066667, + 86.844516667, + 85.46465, + 84.358816667, + 82.004933333, + 82.207066667, + 81.247933333, + 79.504016667, + 79.532266667, + 79.924433333, + 79.03195, + 78.851233333, + 79.726933333, + 78.68965, + 78.418016667, + 78.223866667, + 76.752933333, + 75.281316667, + 73.84245, + 74.192566667, + 73.325533333, + 72.3546, + 71.02525, + 70.578283333, + 70.88545, + 73.86865, + 74.6044, + 74.356266667, + 74.481966667, + 74.988183333, + 74.891383333, + 74.5475, + 75.7053, + 76.809883333, + 77.069633333, + 76.012033333, + 75.40825, + 74.519, + 73.10165, + 73.826416667, + 73.605316667, + 72.003283333, + 71.210116667, + 70.476483333, + 73.647933333, + 76.360233333, + 78.137116667, + 78.928, + 78.254366667, + 78.312233333, + 78.939166667, + 79.256566667, + 78.5502, + 77.899116667, + 77.274816667, + 77.20985, + 77.566733333, + 77.3999, + 78.054983333, + 77.6581, + 78.215916667, + 78.121733333, + 78.28725, + 78.265633333, + 79.1123, + 79.665216667, + 81.06855, + 81.349333333, + 81.25085, + 82.1874, + 82.52145, + 83.712433333, + 85.337816667, + 84.673283333, + 83.360283333, + 83.58445, + 84.609016667, + 84.876033333, + 86.26595, + 86.732966667, + 87.697766667, + 88.536166667, + 87.30565, + 86.810316667, + 87.667166667, + 88.473583333, + 88.096516667, + 87.201566667, + 87.690583333, + 88.866416667, + 88.943983333, + 87.828033333, + 86.688216667, + 85.928366667, + 85.887183333, + 86.7506, + 86.304166667, + 85.379783333, + 85.705133333, + 84.564433333, + 82.771166667, + 81.506916667, + 82.213583333, + 82.514333333, + 83.525916667, + 83.594916667, + 84.6655, + 85.179166667, + 85.782583333, + 84.465416667, + 83.6318, + 84.248066667, + 86.10535, + 87.008783333, + 87.892233333, + 89.5511, + 91.161083333, + 92.036366667, + 91.702066667, + 90.579833333, + 90.5435, + 90.649233333, + 90.199233333, + 90.253016667, + 91.326716667, + 93.229816667, + 93.5479, + 93.26945, + 93.073233333, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "prints": [["Last:93.07"], ["Average:82.08"]], + "last_value": 93.07, + "minimum_value": null, + "maximum_value": null, + "average_value": 82.08 + } + ], + "times": [ + "2023-06-07T09:30:00+02:00", + "2023-06-07T09:35:00+02:00", + "2023-06-07T09:40:00+02:00", + "2023-06-07T09:45:00+02:00", + "2023-06-07T09:50:00+02:00", + "2023-06-07T09:55:00+02:00", + "2023-06-07T10:00:00+02:00", + "2023-06-07T10:05:00+02:00", + "2023-06-07T10:10:00+02:00", + "2023-06-07T10:15:00+02:00", + "2023-06-07T10:20:00+02:00", + "2023-06-07T10:25:00+02:00", + "2023-06-07T10:30:00+02:00", + "2023-06-07T10:35:00+02:00", + "2023-06-07T10:40:00+02:00", + "2023-06-07T10:45:00+02:00", + "2023-06-07T10:50:00+02:00", + "2023-06-07T10:55:00+02:00", + "2023-06-07T11:00:00+02:00", + "2023-06-07T11:05:00+02:00", + "2023-06-07T11:10:00+02:00", + "2023-06-07T11:15:00+02:00", + "2023-06-07T11:20:00+02:00", + "2023-06-07T11:25:00+02:00", + "2023-06-07T11:30:00+02:00", + "2023-06-07T11:35:00+02:00", + "2023-06-07T11:40:00+02:00", + "2023-06-07T11:45:00+02:00", + "2023-06-07T11:50:00+02:00", + "2023-06-07T11:55:00+02:00", + "2023-06-07T12:00:00+02:00", + "2023-06-07T12:05:00+02:00", + "2023-06-07T12:10:00+02:00", + "2023-06-07T12:15:00+02:00", + "2023-06-07T12:20:00+02:00", + "2023-06-07T12:25:00+02:00", + "2023-06-07T12:30:00+02:00", + "2023-06-07T12:35:00+02:00", + "2023-06-07T12:40:00+02:00", + "2023-06-07T12:45:00+02:00", + "2023-06-07T12:50:00+02:00", + "2023-06-07T12:55:00+02:00", + "2023-06-07T13:00:00+02:00", + "2023-06-07T13:05:00+02:00", + "2023-06-07T13:10:00+02:00", + "2023-06-07T13:15:00+02:00", + "2023-06-07T13:20:00+02:00", + "2023-06-07T13:25:00+02:00", + "2023-06-07T13:30:00+02:00", + "2023-06-07T13:35:00+02:00", + "2023-06-07T13:40:00+02:00", + "2023-06-07T13:45:00+02:00", + "2023-06-07T13:50:00+02:00", + "2023-06-07T13:55:00+02:00", + "2023-06-07T14:00:00+02:00", + "2023-06-07T14:05:00+02:00", + "2023-06-07T14:10:00+02:00", + "2023-06-07T14:15:00+02:00", + "2023-06-07T14:20:00+02:00", + "2023-06-07T14:25:00+02:00", + "2023-06-07T14:30:00+02:00", + "2023-06-07T14:35:00+02:00", + "2023-06-07T14:40:00+02:00", + "2023-06-07T14:45:00+02:00", + "2023-06-07T14:50:00+02:00", + "2023-06-07T14:55:00+02:00", + "2023-06-07T15:00:00+02:00", + "2023-06-07T15:05:00+02:00", + "2023-06-07T15:10:00+02:00", + "2023-06-07T15:15:00+02:00", + "2023-06-07T15:20:00+02:00", + "2023-06-07T15:25:00+02:00", + "2023-06-07T15:30:00+02:00", + "2023-06-07T15:35:00+02:00", + "2023-06-07T15:40:00+02:00", + "2023-06-07T15:45:00+02:00", + "2023-06-07T15:50:00+02:00", + "2023-06-07T15:55:00+02:00", + "2023-06-07T16:00:00+02:00", + "2023-06-07T16:05:00+02:00", + "2023-06-07T16:10:00+02:00", + "2023-06-07T16:15:00+02:00", + "2023-06-07T16:20:00+02:00", + "2023-06-07T16:25:00+02:00", + "2023-06-07T16:30:00+02:00", + "2023-06-07T16:35:00+02:00", + "2023-06-07T16:40:00+02:00", + "2023-06-07T16:45:00+02:00", + "2023-06-07T16:50:00+02:00", + "2023-06-07T16:55:00+02:00", + "2023-06-07T17:00:00+02:00", + "2023-06-07T17:05:00+02:00", + "2023-06-07T17:10:00+02:00", + "2023-06-07T17:15:00+02:00", + "2023-06-07T17:20:00+02:00", + "2023-06-07T17:25:00+02:00", + "2023-06-07T17:30:00+02:00", + "2023-06-07T17:35:00+02:00", + "2023-06-07T17:40:00+02:00", + "2023-06-07T17:45:00+02:00", + "2023-06-07T17:50:00+02:00", + "2023-06-07T17:55:00+02:00", + "2023-06-07T18:00:00+02:00", + "2023-06-07T18:05:00+02:00", + "2023-06-07T18:10:00+02:00", + "2023-06-07T18:15:00+02:00", + "2023-06-07T18:20:00+02:00", + "2023-06-07T18:25:00+02:00", + "2023-06-07T18:30:00+02:00", + "2023-06-07T18:35:00+02:00", + "2023-06-07T18:40:00+02:00", + "2023-06-07T18:45:00+02:00", + "2023-06-07T18:50:00+02:00", + "2023-06-07T18:55:00+02:00", + "2023-06-07T19:00:00+02:00", + "2023-06-07T19:05:00+02:00", + "2023-06-07T19:10:00+02:00", + "2023-06-07T19:15:00+02:00", + "2023-06-07T19:20:00+02:00", + "2023-06-07T19:25:00+02:00", + "2023-06-07T19:30:00+02:00", + "2023-06-07T19:35:00+02:00", + "2023-06-07T19:40:00+02:00", + "2023-06-07T19:45:00+02:00", + "2023-06-07T19:50:00+02:00", + "2023-06-07T19:55:00+02:00", + "2023-06-07T20:00:00+02:00", + "2023-06-07T20:05:00+02:00", + "2023-06-07T20:10:00+02:00", + "2023-06-07T20:15:00+02:00", + "2023-06-07T20:20:00+02:00", + "2023-06-07T20:25:00+02:00", + "2023-06-07T20:30:00+02:00", + "2023-06-07T20:35:00+02:00", + "2023-06-07T20:40:00+02:00", + "2023-06-07T20:45:00+02:00", + "2023-06-07T20:50:00+02:00", + "2023-06-07T20:55:00+02:00", + "2023-06-07T21:00:00+02:00", + "2023-06-07T21:05:00+02:00", + "2023-06-07T21:10:00+02:00", + "2023-06-07T21:15:00+02:00", + "2023-06-07T21:20:00+02:00", + "2023-06-07T21:25:00+02:00", + "2023-06-07T21:30:00+02:00", + "2023-06-07T21:35:00+02:00", + "2023-06-07T21:40:00+02:00", + "2023-06-07T21:45:00+02:00", + "2023-06-07T21:50:00+02:00", + "2023-06-07T21:55:00+02:00", + "2023-06-07T22:00:00+02:00", + "2023-06-07T22:05:00+02:00", + "2023-06-07T22:10:00+02:00", + "2023-06-07T22:15:00+02:00", + "2023-06-07T22:20:00+02:00", + "2023-06-07T22:25:00+02:00", + "2023-06-07T22:30:00+02:00", + "2023-06-07T22:35:00+02:00", + "2023-06-07T22:40:00+02:00", + "2023-06-07T22:45:00+02:00", + "2023-06-07T22:50:00+02:00", + "2023-06-07T22:55:00+02:00", + "2023-06-07T23:00:00+02:00", + "2023-06-07T23:05:00+02:00", + "2023-06-07T23:10:00+02:00", + "2023-06-07T23:15:00+02:00", + "2023-06-07T23:20:00+02:00", + "2023-06-07T23:25:00+02:00", + "2023-06-07T23:30:00+02:00", + "2023-06-07T23:35:00+02:00", + "2023-06-07T23:40:00+02:00", + "2023-06-07T23:45:00+02:00", + "2023-06-07T23:50:00+02:00", + "2023-06-07T23:55:00+02:00", + "2023-06-08T00:00:00+02:00", + "2023-06-08T00:05:00+02:00", + "2023-06-08T00:10:00+02:00", + "2023-06-08T00:15:00+02:00", + "2023-06-08T00:20:00+02:00", + "2023-06-08T00:25:00+02:00", + "2023-06-08T00:30:00+02:00", + "2023-06-08T00:35:00+02:00", + "2023-06-08T00:40:00+02:00", + "2023-06-08T00:45:00+02:00", + "2023-06-08T00:50:00+02:00", + "2023-06-08T00:55:00+02:00", + "2023-06-08T01:00:00+02:00", + "2023-06-08T01:05:00+02:00", + "2023-06-08T01:10:00+02:00", + "2023-06-08T01:15:00+02:00", + "2023-06-08T01:20:00+02:00", + "2023-06-08T01:25:00+02:00", + "2023-06-08T01:30:00+02:00", + "2023-06-08T01:35:00+02:00", + "2023-06-08T01:40:00+02:00", + "2023-06-08T01:45:00+02:00", + "2023-06-08T01:50:00+02:00", + "2023-06-08T01:55:00+02:00", + "2023-06-08T02:00:00+02:00", + "2023-06-08T02:05:00+02:00", + "2023-06-08T02:10:00+02:00", + "2023-06-08T02:15:00+02:00", + "2023-06-08T02:20:00+02:00", + "2023-06-08T02:25:00+02:00", + "2023-06-08T02:30:00+02:00", + "2023-06-08T02:35:00+02:00", + "2023-06-08T02:40:00+02:00", + "2023-06-08T02:45:00+02:00", + "2023-06-08T02:50:00+02:00", + "2023-06-08T02:55:00+02:00", + "2023-06-08T03:00:00+02:00", + "2023-06-08T03:05:00+02:00", + "2023-06-08T03:10:00+02:00", + "2023-06-08T03:15:00+02:00", + "2023-06-08T03:20:00+02:00", + "2023-06-08T03:25:00+02:00", + "2023-06-08T03:30:00+02:00", + "2023-06-08T03:35:00+02:00", + "2023-06-08T03:40:00+02:00", + "2023-06-08T03:45:00+02:00", + "2023-06-08T03:50:00+02:00", + "2023-06-08T03:55:00+02:00", + "2023-06-08T04:00:00+02:00", + "2023-06-08T04:05:00+02:00", + "2023-06-08T04:10:00+02:00", + "2023-06-08T04:15:00+02:00", + "2023-06-08T04:20:00+02:00", + "2023-06-08T04:25:00+02:00", + "2023-06-08T04:30:00+02:00", + "2023-06-08T04:35:00+02:00", + "2023-06-08T04:40:00+02:00", + "2023-06-08T04:45:00+02:00", + "2023-06-08T04:50:00+02:00", + "2023-06-08T04:55:00+02:00", + "2023-06-08T05:00:00+02:00", + "2023-06-08T05:05:00+02:00", + "2023-06-08T05:10:00+02:00", + "2023-06-08T05:15:00+02:00", + "2023-06-08T05:20:00+02:00", + "2023-06-08T05:25:00+02:00", + "2023-06-08T05:30:00+02:00", + "2023-06-08T05:35:00+02:00", + "2023-06-08T05:40:00+02:00", + "2023-06-08T05:45:00+02:00", + "2023-06-08T05:50:00+02:00", + "2023-06-08T05:55:00+02:00", + "2023-06-08T06:00:00+02:00", + "2023-06-08T06:05:00+02:00", + "2023-06-08T06:10:00+02:00", + "2023-06-08T06:15:00+02:00", + "2023-06-08T06:20:00+02:00", + "2023-06-08T06:25:00+02:00", + "2023-06-08T06:30:00+02:00", + "2023-06-08T06:35:00+02:00", + "2023-06-08T06:40:00+02:00", + "2023-06-08T06:45:00+02:00", + "2023-06-08T06:50:00+02:00", + "2023-06-08T06:55:00+02:00", + "2023-06-08T07:00:00+02:00", + "2023-06-08T07:05:00+02:00", + "2023-06-08T07:10:00+02:00", + "2023-06-08T07:15:00+02:00", + "2023-06-08T07:20:00+02:00", + "2023-06-08T07:25:00+02:00", + "2023-06-08T07:30:00+02:00", + "2023-06-08T07:35:00+02:00", + "2023-06-08T07:40:00+02:00", + "2023-06-08T07:45:00+02:00", + "2023-06-08T07:50:00+02:00", + "2023-06-08T07:55:00+02:00", + "2023-06-08T08:00:00+02:00", + "2023-06-08T08:05:00+02:00", + "2023-06-08T08:10:00+02:00", + "2023-06-08T08:15:00+02:00", + "2023-06-08T08:20:00+02:00", + "2023-06-08T08:25:00+02:00", + "2023-06-08T08:30:00+02:00", + "2023-06-08T08:35:00+02:00", + "2023-06-08T08:40:00+02:00", + "2023-06-08T08:45:00+02:00", + "2023-06-08T08:50:00+02:00", + "2023-06-08T08:55:00+02:00", + "2023-06-08T09:00:00+02:00", + "2023-06-08T09:05:00+02:00", + "2023-06-08T09:10:00+02:00", + "2023-06-08T09:15:00+02:00", + "2023-06-08T09:20:00+02:00", + "2023-06-08T09:25:00+02:00", + "2023-06-08T09:30:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/lastDayThreshold.json b/centreon/packages/ui/src/Graph/mockedData/lastDayThreshold.json new file mode 100644 index 0000000000..b51e14420f --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/lastDayThreshold.json @@ -0,0 +1,2320 @@ +{ + "global": { + "title": "anomaly-nbr-connect graph on fw-brasilia", + "start": "2023-06-14T17:31:46+02:00", + "end": "2023-06-15T17:31:46+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 1, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 152032, + "metric_id": 15165, + "metric": "connection", + "metric_legend": "connection", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#993366" + }, + "legend": "connection", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 120.88, + 119.98333333, + 161.63, + 136.94666667, + 152.69666667, + 52.246666667, + 16.236666667, + 14.796666667, + 20.576666667, + 24.39, + 26.593333333, + 24.61, + 24.796666667, + 13.846666667, + 25.34, + 28.203333333, + 17.643333333, + 25.356666667, + 17.643333333, + 24.56, + 19.033333333, + 20.983333333, + 18.813333333, + 25.17, + 13.456666667, + 25.136666667, + 29, + 14.66, + 24.543333333, + 21.626666667, + 14.423333333, + 18.576666667, + 20.796666667, + 25.78, + 20.626666667, + 15.813333333, + 18.186666667, + 25.373333333, + 14.253333333, + 21.356666667, + 18.423333333, + 21.78, + 22.203333333, + 27.576666667, + 27.406666667, + 22.22, + 25.78, + 15.846666667, + 15.39, + 22.373333333, + 20.813333333, + 23.983333333, + 28.186666667, + 26.61, + 26, + 22.813333333, + 18.016666667, + 13.813333333, + 16.186666667, + 17.796666667, + 21.983333333, + 14.236666667, + 23.153333333, + 17.236666667, + 15, + 20.576666667, + 22.796666667, + 27.78, + 28.203333333, + 27.203333333, + 14.253333333, + 13.39, + 21.17, + 19.813333333, + 22.186666667, + 14.236666667, + 22.356666667, + 15.44, + 14.593333333, + 12.61, + 24.746666667, + 24.813333333, + 17.626666667, + 12.813333333, + 16.78, + 20.39, + 21, + 17.813333333, + 20.983333333, + 25.186666667, + 17.236666667, + 21.373333333, + 19.813333333, + 21.39, + 14.033333333, + 10.406666667, + 22.746666667, + 21.22, + 23.983333333, + 13.846666667, + 16.576666667, + 20.39, + 13.033333333, + 24.543333333, + 22.423333333, + 24.186666667, + 27.39, + 16.05, + 23.356666667, + 18.033333333, + 20.78, + 18.016666667, + 18.593333333, + 26.17, + 21.626666667, + 16.016666667, + 14.203333333, + 17.186666667, + 25.966666667, + 24.813333333, + 27.983333333, + 24.22, + 12.643333333, + 21.95, + 21.016666667, + 19.203333333, + 20.593333333, + 21, + 22.593333333, + 19.016666667, + 17.203333333, + 11.423333333, + 18.763333333, + 21, + 19.406666667, + 13.446666667, + 16.76, + 25.14, + 27.793333333, + 24.826666667, + 20.033333333, + 22.173333333, + 25.38, + 18.066666667, + 18.38, + 16.62, + 12.033333333, + 12.586666667, + 13.793333333, + 11.62, + 11, + 18.933333333, + 25.76, + 15.1, + 15.173333333, + 21.553333333, + 27.76, + 24.24, + 15.86, + 17.966666667, + 24.553333333, + 16.48, + 24.313333333, + 22.24, + 22.586666667, + 27.76, + 18.686666667, + 19.966666667, + 23.38, + 13.686666667, + 23.693333333, + 23.033333333, + 25.173333333, + 22.826666667, + 19.62, + 11.86, + 17.14, + 18.206666667, + 19.586666667, + 26.346666667, + 28.793333333, + 18.686666667, + 11.24, + 16.346666667, + 15.62, + 83.226666667, + 127.96666667, + 104.84, + 108.50666667, + 148.44666667, + 161.2, + 132.94, + 119.67333333, + 139.44666667, + 161.86666667, + 169.49333333, + 133.61333333, + 133.35333333, + 137.84, + 137.44666667, + 153.29333333, + 147.60666667, + 168.1, + 150.2, + 128.70666667, + 133.62, + 113.96, + 131.78666667, + 99.693333333, + 148.62666667, + 94.873333333, + 88.126666667, + 101.25333333, + 126.34666667, + 160.09333333, + 165.65333333, + 137.51333333, + 152.64, + 159.82, + 116.34666667, + 150.28666667, + 148.14666667, + 90.506666667, + 124.84, + 131.21333333, + 175.1, + 155.07333333, + 116.39333333, + 101.31333333, + 141.41333333, + 156.46, + 131.38, + 162.25333333, + 182.70666667, + 181.82, + 124.62, + 96.646666667, + 96.413333333, + 124.22, + 146.96666667, + 140.75333333, + 106.12, + 144.83333333, + 152.43333333, + 97.293333333, + 96.44, + 142.32, + 142.33333333, + 103.74, + 118.54, + 145.55333333, + 122.16666667, + 109.15333333, + 134.74666667, + 117.19333333, + 122.83333333, + 152.28, + 170.50666667, + 93.506666667, + 122.23333333, + 95.353333333, + 114.72666667, + 164.26666667, + 130.64666667, + 121.90666667, + 110.93333333, + 119.96666667, + 119.16666667, + 104.02666667, + 121.52, + 109.9, + 125.09333333, + 130.84666667, + 116.08, + 174.16666667, + 151.1, + 144.02666667, + 162.48666667, + 145.42666667, + 131.92, + 169.31333333, + 87.253333333, + 115.05333333, + 145.20666667, + 96.966666667, + 104.28666667, + 111.42666667, + null, + null + ], + "prints": [ + ["Last:111.43"], + ["Min:10.41"], + ["Max:182.71"], + ["Average:61.78"] + ], + "last_value": 111.43, + "minimum_value": 10.41, + "maximum_value": 182.71, + "average_value": 61.78 + }, + { + "index_id": 152032, + "metric_id": 16196, + "metric": "connection_fit", + "metric_legend": "connection_fit", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#9933ff" + }, + "legend": "connection_fit", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 130.99763333, + 131.10763333, + 131.1778, + 131.08643333, + 130.95643333, + 125.59233333, + 98.3463, + 65.8563, + 37.923233333, + 29.0145, + 24.6645, + 21.015566667, + 20.31, + 20.31, + 20.270166667, + 20.060833333, + 19.810833333, + 19.5688, + 19.3527, + 19.1427, + 18.964566667, + 18.93, + 18.93, + 18.93, + 18.93, + 18.93, + 18.969833333, + 19.139333333, + 19.3473, + 19.493566667, + 19.3527, + 19.1427, + 18.964566667, + 18.93, + 18.93, + 18.93, + 18.93, + 18.93, + 18.969833333, + 19.139333333, + 19.3473, + 19.493566667, + 19.3527, + 19.1427, + 18.964566667, + 18.93, + 18.93, + 18.93, + 18.93, + 18.93, + 18.969833333, + 19.139333333, + 19.3473, + 19.493566667, + 19.3527, + 19.1427, + 18.964566667, + 18.93, + 18.93, + 18.93, + 18.93, + 18.93, + 18.969833333, + 19.139333333, + 19.3473, + 19.493566667, + 19.3527, + 19.1427, + 18.964566667, + 18.93, + 18.93, + 18.93, + 18.93, + 18.93, + 18.969833333, + 19.139333333, + 19.3473, + 19.493566667, + 19.3527, + 19.1427, + 18.964566667, + 18.93, + 18.93, + 18.93, + 18.93, + 18.93, + 18.969833333, + 19.155266667, + 19.375266667, + 19.523566667, + 19.3827, + 19.1727, + 18.994566667, + 18.96, + 18.96, + 18.96, + 18.96, + 18.96, + 19.0556, + 19.550033333, + 20.140033333, + 20.634433333, + 20.73, + 20.73, + 20.722033333, + 20.656266667, + 20.584233333, + 20.554066667, + 20.6695, + 20.8195, + 20.8978, + 20.663033333, + 20.345066667, + 20.0888, + 20.04, + 20.04, + 20.04, + 20.047966667, + 20.057966667, + 20.1078, + 20.295266667, + 20.523233333, + 20.673566667, + 20.5088, + 20.276766667, + 20.078633333, + 20.04, + 20.04, + 20.04, + 20.047966667, + 20.057966667, + 20.1078, + 20.295266667, + 20.523233333, + 20.673566667, + 20.5096, + 20.2696, + 20.069266667, + 20.03, + 20.03, + 20.03, + 20.045866667, + 20.057933333, + 20.091733333, + 20.234866667, + 20.396933333, + 20.509333333, + 20.371333333, + 20.171333333, + 20.003066667, + 19.97, + 19.97, + 19.97, + 19.977933333, + 19.987933333, + 20.005866667, + 20.065533333, + 20.1276, + 20.179666667, + 20.150333333, + 20.108266667, + 20.0762, + 20.07, + 20.07, + 20.07, + 20.077933333, + 20.087933333, + 20.105866667, + 20.165533333, + 20.2276, + 20.24, + 20.041666667, + 19.783733333, + 19.571333333, + 19.53, + 19.53, + 19.537933333, + 19.547933333, + 19.557933333, + 19.567933333, + 19.5938, + 19.631733333, + 19.8304, + 20.7368, + 21.808866667, + 27.519866667, + 45.074866667, + 81.596266667, + 107.08186667, + 115.47386667, + 119.99193333, + 123.8156, + 124.61126667, + 124.72126667, + 125.02846667, + 126.20293333, + 127.56486667, + 128.757, + 129.16253333, + 129.38253333, + 129.5658, + 129.5842, + 129.5542, + 129.5474, + 129.64126667, + 129.75126667, + 129.93666667, + 130.456, + 131.056, + 131.56126667, + 131.65, + 131.65, + 131.64613333, + 131.6242, + 131.59613333, + 131.59546667, + 131.68126667, + 131.79126667, + 131.85486667, + 131.7152, + 131.5352, + 131.3842, + 131.36, + 131.36, + 131.35613333, + 131.3342, + 131.3042, + 131.2974, + 131.38933333, + 131.49126667, + 131.57226667, + 131.52453333, + 131.4426, + 131.36806667, + 131.36, + 131.36, + 131.35613333, + 131.3342, + 131.3042, + 131.2974, + 131.38933333, + 131.49126667, + 131.57226667, + 131.52453333, + 131.4426, + 131.36806667, + 131.36, + 131.36, + 131.35613333, + 131.3342, + 131.3042, + 131.2974, + 131.38933333, + 131.49126667, + 131.59546667, + 131.67353333, + 131.7416, + 131.79193333, + 131.8, + 131.8, + 131.79613333, + 131.77613333, + 131.7542, + 131.74546667, + 131.83126667, + 131.94126667, + 132.02226667, + 131.9726, + 131.88453333, + 131.81613333, + 131.8, + 131.8, + 131.79613333, + 131.77613333, + 131.7542, + 131.74546667, + 131.83126667, + 131.94126667, + 132.02226667, + 131.9726, + 131.88453333, + 131.81613333, + 131.8, + 131.8, + 131.79613333, + 131.77613333, + 131.7542, + null, + null + ], + "prints": [ + ["Last:131.75"], + ["Min:18.93"], + ["Max:132.02"], + ["Average:61.08"] + ], + "last_value": 131.75, + "minimum_value": 18.93, + "maximum_value": 132.02, + "average_value": 61.08 + }, + { + "index_id": 152032, + "metric_id": 16197, + "metric": "connection_lower_margin", + "metric_legend": "connection_lower_margin", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#00ff99" + }, + "legend": "connection_lower_margin", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -88.792933333, + -67.8513, + -42.869266667, + -21.928366667, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -17.88, + -21.9736, + -36.769466667, + -67.8514, + -88.9438, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + -92.84, + null, + null + ], + "prints": [ + ["Last:-92.84"], + ["Min:-92.84"], + ["Max:-17.88"], + ["Average:-45.81"] + ], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + }, + { + "index_id": 152032, + "metric_id": 16198, + "metric": "connection_upper_margin", + "metric_legend": "connection_upper_margin", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#9900ff" + }, + "legend": "connection_upper_margin", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 76.405833333, + 56.8458, + 33.497833333, + 13.932, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 10.15, + 13.9818, + 27.801, + 56.8424, + 76.543866667, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + 80.19, + null, + null + ], + "prints": [ + ["Last:80.19"], + ["Min:10.15"], + ["Max:80.19"], + ["Average:36.24"] + ], + "last_value": 80.19, + "minimum_value": 10.15, + "maximum_value": 80.19, + "average_value": 36.24 + }, + { + "index_id": 152032, + "metric_id": 15177, + "metric": "connection_lower_thresholds", + "metric_legend": "connection_lower_thresholds", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 50, + "host_id": null, + "service_id": null, + "name": "Anomaly Lower Threshold", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": ".*_lower_thresholds", + "ds_color_line": "#D728C9", + "ds_color_line_mode": "0", + "ds_color_area": "#FFFFFF", + "ds_color_area_warn": "#F8C706", + "ds_color_area_crit": "#F91E05", + "ds_filled": null, + "ds_max": null, + "ds_min": null, + "ds_minmax_int": null, + "ds_average": null, + "ds_last": null, + "ds_total": null, + "ds_tickness": 2, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": "Lower Threshold", + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "Lower Threshold", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + -147.52236667, + -147.41236667, + -147.3422, + -147.43356667, + -147.56356667, + -140.79443333, + -105.2176, + -62.745566667, + -27.859833333, + -24.6255, + -28.9755, + -32.624433333, + -33.33, + -33.33, + -33.369833333, + -33.579166667, + -33.829166667, + -34.0712, + -34.2873, + -34.4973, + -34.667466667, + -34.7, + -34.7, + -34.7, + -34.7, + -34.7, + -34.668133333, + -34.4927, + -34.2827, + -34.1444, + -34.2873, + -34.4973, + -34.667466667, + -34.7, + -34.7, + -34.7, + -34.7, + -34.7, + -34.668133333, + -34.4927, + -34.2827, + -34.1444, + -34.2873, + -34.4973, + -34.667466667, + -34.7, + -34.7, + -34.7, + -34.7, + -34.7, + -34.668133333, + -34.4927, + -34.2827, + -34.1444, + -34.2873, + -34.4973, + -34.667466667, + -34.7, + -34.7, + -34.7, + -34.7, + -34.7, + -34.668133333, + -34.4927, + -34.2827, + -34.1444, + -34.2873, + -34.4973, + -34.667466667, + -34.7, + -34.7, + -34.7, + -34.7, + -34.7, + -34.668133333, + -34.4927, + -34.2827, + -34.1444, + -34.2873, + -34.4973, + -34.667466667, + -34.7, + -34.7, + -34.7, + -34.7, + -34.7, + -34.668133333, + -34.484733333, + -34.264733333, + -34.116433333, + -34.2573, + -34.4673, + -34.637466667, + -34.67, + -34.67, + -34.67, + -34.67, + -34.67, + -34.5744, + -34.079966667, + -33.497933333, + -33.005566667, + -32.91, + -32.91, + -32.917966667, + -32.975766667, + -33.045766667, + -33.0839, + -32.9705, + -32.8205, + -32.7422, + -32.976966667, + -33.286966667, + -33.549166667, + -33.6, + -33.6, + -33.6, + -33.592033333, + -33.582033333, + -33.5322, + -33.344733333, + -33.116766667, + -32.966433333, + -33.123233333, + -33.3612, + -33.561366667, + -33.6, + -33.6, + -33.6, + -33.592033333, + -33.582033333, + -33.5322, + -33.344733333, + -33.116766667, + -32.966433333, + -33.1304, + -33.3704, + -33.5628, + -33.6, + -33.6, + -33.6, + -33.592066667, + -33.582066667, + -33.548266667, + -33.405133333, + -33.235133333, + -33.1286, + -33.268666667, + -33.468666667, + -33.636933333, + -33.67, + -33.67, + -33.67, + -33.662066667, + -33.652066667, + -33.6262, + -33.5724, + -33.504466667, + -33.458266667, + -33.481733333, + -33.529666667, + -33.5638, + -33.57, + -33.57, + -33.57, + -33.562066667, + -33.552066667, + -33.5262, + -33.4724, + -33.404466667, + -33.39, + -33.596266667, + -33.848333333, + -34.058666667, + -34.1, + -34.1, + -34.1, + -34.092066667, + -34.082066667, + -34.064133333, + -34.0362, + -34.0062, + -33.801666667, + -32.901133333, + -31.831133333, + -38.408866667, + -65.231533333, + -121.966, + -159.74953333, + -163.04806667, + -158.53613333, + -154.7044, + -153.90873333, + -153.79873333, + -153.49346667, + -152.32513333, + -150.95513333, + -149.76493333, + -149.36553333, + -149.13746667, + -148.95613333, + -148.94386667, + -148.9658, + -148.97453333, + -148.88873333, + -148.77873333, + -148.5914, + -148.06593333, + -147.474, + -146.9668, + -146.87, + -146.87, + -146.87386667, + -146.8958, + -146.9258, + -146.9326, + -146.83873333, + -146.72873333, + -146.66513333, + -146.8048, + -146.9848, + -147.13773333, + -147.17, + -147.17, + -147.17386667, + -147.1958, + -147.22386667, + -147.22453333, + -147.13873333, + -147.02873333, + -146.94966667, + -147.00546667, + -147.08546667, + -147.15386667, + -147.17, + -147.17, + -147.17386667, + -147.1958, + -147.22386667, + -147.22453333, + -147.13873333, + -147.02873333, + -146.94966667, + -147.00546667, + -147.08546667, + -147.15386667, + -147.17, + -147.17, + -147.17386667, + -147.1958, + -147.22386667, + -147.22453333, + -147.13873333, + -147.02873333, + -146.92453333, + -146.8484, + -146.78646667, + -146.72806667, + -146.72, + -146.72, + -146.72386667, + -146.7458, + -146.77386667, + -146.77453333, + -146.68873333, + -146.57873333, + -146.49966667, + -146.55546667, + -146.63546667, + -146.70386667, + -146.72, + -146.72, + -146.72386667, + -146.7458, + -146.77386667, + -146.77453333, + -146.68873333, + -146.57873333, + -146.49966667, + -146.55546667, + -146.63546667, + -146.70386667, + -146.72, + -146.72, + -146.72386667, + -146.7458, + -146.77386667, + null, + null + ], + "prints": [], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + }, + { + "index_id": 152032, + "metric_id": 15178, + "metric": "connection_upper_thresholds", + "metric_legend": "connection_upper_thresholds", + "unit": "", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 51, + "host_id": null, + "service_id": null, + "name": "Anomaly Upper Threshold", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": ".*_upper_thresholds", + "ds_color_line": "#D728C9", + "ds_color_line_mode": "0", + "ds_color_area": "#FFFFFF", + "ds_color_area_warn": "#F8C706", + "ds_color_area_crit": "#F91E05", + "ds_filled": null, + "ds_max": null, + "ds_min": null, + "ds_minmax_int": null, + "ds_average": null, + "ds_last": null, + "ds_total": null, + "ds_tickness": 2, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": "Upper Threshold", + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "Upper Threshold", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_order": 1, + "data": [ + 371.55763333, + 371.66763333, + 371.7378, + 371.64643333, + 371.5244, + 354.80983333, + 268.86776667, + 166.34573333, + 79.7272, + 59.4745, + 55.1245, + 51.475566667, + 50.77, + 50.77, + 50.730166667, + 50.520833333, + 50.270833333, + 50.020833333, + 49.810666667, + 49.6027, + 49.424566667, + 49.39, + 49.39, + 49.39, + 49.39, + 49.39, + 49.421866667, + 49.5973, + 49.8073, + 49.9456, + 49.810666667, + 49.6027, + 49.424566667, + 49.39, + 49.39, + 49.39, + 49.39, + 49.39, + 49.421866667, + 49.5973, + 49.8073, + 49.9456, + 49.810666667, + 49.6027, + 49.424566667, + 49.39, + 49.39, + 49.39, + 49.39, + 49.39, + 49.421866667, + 49.5973, + 49.8073, + 49.9456, + 49.810666667, + 49.6027, + 49.424566667, + 49.39, + 49.39, + 49.39, + 49.39, + 49.39, + 49.421866667, + 49.5973, + 49.8073, + 49.9456, + 49.810666667, + 49.6027, + 49.424566667, + 49.39, + 49.39, + 49.39, + 49.39, + 49.39, + 49.421866667, + 49.5973, + 49.8073, + 49.9456, + 49.810666667, + 49.6027, + 49.424566667, + 49.39, + 49.39, + 49.39, + 49.39, + 49.39, + 49.429833333, + 49.6073, + 49.825266667, + 49.981533333, + 49.8427, + 49.6327, + 49.454566667, + 49.42, + 49.42, + 49.42, + 49.42, + 49.42, + 49.5156, + 50.010033333, + 50.600033333, + 51.094433333, + 51.19, + 51.19, + 51.174066667, + 51.114233333, + 51.044233333, + 51.0061, + 51.127466667, + 51.2795, + 51.349833333, + 51.113033333, + 50.803033333, + 50.540833333, + 50.49, + 50.49, + 50.497966667, + 50.507966667, + 50.517966667, + 50.559833333, + 50.753233333, + 50.983233333, + 51.133566667, + 50.9688, + 50.7288, + 50.528633333, + 50.49, + 50.49, + 50.497966667, + 50.507966667, + 50.517966667, + 50.559833333, + 50.753233333, + 50.983233333, + 51.133566667, + 50.9696, + 50.7296, + 50.529266667, + 50.49, + 50.49, + 50.49, + 50.497933333, + 50.507933333, + 50.549666667, + 50.686933333, + 50.854866667, + 50.9614, + 50.821333333, + 50.621333333, + 50.453066667, + 50.42, + 50.42, + 50.427933333, + 50.437933333, + 50.447933333, + 50.465866667, + 50.525533333, + 50.5876, + 50.631733333, + 50.608266667, + 50.568266667, + 50.528266667, + 50.52, + 50.52, + 50.527933333, + 50.537933333, + 50.547933333, + 50.565866667, + 50.625533333, + 50.6876, + 50.7, + 50.501666667, + 50.243733333, + 50.031333333, + 49.99, + 49.99, + 49.99, + 49.997933333, + 50.007933333, + 50.025866667, + 50.0538, + 50.0838, + 50.288333333, + 51.188866667, + 52.2668, + 69.4594, + 128.4818, + 252.1254, + 336.7196, + 356.03386667, + 360.55193333, + 364.3756, + 365.17126667, + 365.28126667, + 365.58846667, + 366.76293333, + 368.12486667, + 369.317, + 369.72253333, + 369.94446667, + 370.13386667, + 370.1442, + 370.1142, + 370.1074, + 370.20126667, + 370.31126667, + 370.49666667, + 371.016, + 371.616, + 372.12126667, + 372.21, + 372.21, + 372.20613333, + 372.1842, + 372.15613333, + 372.15546667, + 372.24126667, + 372.35126667, + 372.4168, + 372.28326667, + 372.0952, + 371.9442, + 371.92, + 371.92, + 371.91613333, + 371.8942, + 371.8642, + 371.8574, + 371.95126667, + 372.06126667, + 372.14033333, + 372.08453333, + 372.0026, + 371.92806667, + 371.92, + 371.92, + 371.91613333, + 371.8942, + 371.8642, + 371.8574, + 371.95126667, + 372.06126667, + 372.14033333, + 372.08453333, + 372.0026, + 371.92806667, + 371.92, + 371.92, + 371.91613333, + 371.8942, + 371.8642, + 371.8574, + 371.95126667, + 372.06126667, + 372.16353333, + 372.23353333, + 372.3016, + 372.35386667, + 372.37, + 372.37, + 372.3642, + 372.33613333, + 372.3142, + 372.30546667, + 372.39126667, + 372.50126667, + 372.58226667, + 372.5326, + 372.44453333, + 372.37806667, + 372.37, + 372.37, + 372.3642, + 372.33613333, + 372.3142, + 372.30546667, + 372.39126667, + 372.50126667, + 372.58226667, + 372.5326, + 372.44453333, + 372.37806667, + 372.37, + 372.37, + 372.3642, + 372.33613333, + 372.3142, + null, + null + ], + "prints": [], + "last_value": null, + "minimum_value": null, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2023-06-14T17:35:00+02:00", + "2023-06-14T17:40:00+02:00", + "2023-06-14T17:45:00+02:00", + "2023-06-14T17:50:00+02:00", + "2023-06-14T17:55:00+02:00", + "2023-06-14T18:00:00+02:00", + "2023-06-14T18:05:00+02:00", + "2023-06-14T18:10:00+02:00", + "2023-06-14T18:15:00+02:00", + "2023-06-14T18:20:00+02:00", + "2023-06-14T18:25:00+02:00", + "2023-06-14T18:30:00+02:00", + "2023-06-14T18:35:00+02:00", + "2023-06-14T18:40:00+02:00", + "2023-06-14T18:45:00+02:00", + "2023-06-14T18:50:00+02:00", + "2023-06-14T18:55:00+02:00", + "2023-06-14T19:00:00+02:00", + "2023-06-14T19:05:00+02:00", + "2023-06-14T19:10:00+02:00", + "2023-06-14T19:15:00+02:00", + "2023-06-14T19:20:00+02:00", + "2023-06-14T19:25:00+02:00", + "2023-06-14T19:30:00+02:00", + "2023-06-14T19:35:00+02:00", + "2023-06-14T19:40:00+02:00", + "2023-06-14T19:45:00+02:00", + "2023-06-14T19:50:00+02:00", + "2023-06-14T19:55:00+02:00", + "2023-06-14T20:00:00+02:00", + "2023-06-14T20:05:00+02:00", + "2023-06-14T20:10:00+02:00", + "2023-06-14T20:15:00+02:00", + "2023-06-14T20:20:00+02:00", + "2023-06-14T20:25:00+02:00", + "2023-06-14T20:30:00+02:00", + "2023-06-14T20:35:00+02:00", + "2023-06-14T20:40:00+02:00", + "2023-06-14T20:45:00+02:00", + "2023-06-14T20:50:00+02:00", + "2023-06-14T20:55:00+02:00", + "2023-06-14T21:00:00+02:00", + "2023-06-14T21:05:00+02:00", + "2023-06-14T21:10:00+02:00", + "2023-06-14T21:15:00+02:00", + "2023-06-14T21:20:00+02:00", + "2023-06-14T21:25:00+02:00", + "2023-06-14T21:30:00+02:00", + "2023-06-14T21:35:00+02:00", + "2023-06-14T21:40:00+02:00", + "2023-06-14T21:45:00+02:00", + "2023-06-14T21:50:00+02:00", + "2023-06-14T21:55:00+02:00", + "2023-06-14T22:00:00+02:00", + "2023-06-14T22:05:00+02:00", + "2023-06-14T22:10:00+02:00", + "2023-06-14T22:15:00+02:00", + "2023-06-14T22:20:00+02:00", + "2023-06-14T22:25:00+02:00", + "2023-06-14T22:30:00+02:00", + "2023-06-14T22:35:00+02:00", + "2023-06-14T22:40:00+02:00", + "2023-06-14T22:45:00+02:00", + "2023-06-14T22:50:00+02:00", + "2023-06-14T22:55:00+02:00", + "2023-06-14T23:00:00+02:00", + "2023-06-14T23:05:00+02:00", + "2023-06-14T23:10:00+02:00", + "2023-06-14T23:15:00+02:00", + "2023-06-14T23:20:00+02:00", + "2023-06-14T23:25:00+02:00", + "2023-06-14T23:30:00+02:00", + "2023-06-14T23:35:00+02:00", + "2023-06-14T23:40:00+02:00", + "2023-06-14T23:45:00+02:00", + "2023-06-14T23:50:00+02:00", + "2023-06-14T23:55:00+02:00", + "2023-06-15T00:00:00+02:00", + "2023-06-15T00:05:00+02:00", + "2023-06-15T00:10:00+02:00", + "2023-06-15T00:15:00+02:00", + "2023-06-15T00:20:00+02:00", + "2023-06-15T00:25:00+02:00", + "2023-06-15T00:30:00+02:00", + "2023-06-15T00:35:00+02:00", + "2023-06-15T00:40:00+02:00", + "2023-06-15T00:45:00+02:00", + "2023-06-15T00:50:00+02:00", + "2023-06-15T00:55:00+02:00", + "2023-06-15T01:00:00+02:00", + "2023-06-15T01:05:00+02:00", + "2023-06-15T01:10:00+02:00", + "2023-06-15T01:15:00+02:00", + "2023-06-15T01:20:00+02:00", + "2023-06-15T01:25:00+02:00", + "2023-06-15T01:30:00+02:00", + "2023-06-15T01:35:00+02:00", + "2023-06-15T01:40:00+02:00", + "2023-06-15T01:45:00+02:00", + "2023-06-15T01:50:00+02:00", + "2023-06-15T01:55:00+02:00", + "2023-06-15T02:00:00+02:00", + "2023-06-15T02:05:00+02:00", + "2023-06-15T02:10:00+02:00", + "2023-06-15T02:15:00+02:00", + "2023-06-15T02:20:00+02:00", + "2023-06-15T02:25:00+02:00", + "2023-06-15T02:30:00+02:00", + "2023-06-15T02:35:00+02:00", + "2023-06-15T02:40:00+02:00", + "2023-06-15T02:45:00+02:00", + "2023-06-15T02:50:00+02:00", + "2023-06-15T02:55:00+02:00", + "2023-06-15T03:00:00+02:00", + "2023-06-15T03:05:00+02:00", + "2023-06-15T03:10:00+02:00", + "2023-06-15T03:15:00+02:00", + "2023-06-15T03:20:00+02:00", + "2023-06-15T03:25:00+02:00", + "2023-06-15T03:30:00+02:00", + "2023-06-15T03:35:00+02:00", + "2023-06-15T03:40:00+02:00", + "2023-06-15T03:45:00+02:00", + "2023-06-15T03:50:00+02:00", + "2023-06-15T03:55:00+02:00", + "2023-06-15T04:00:00+02:00", + "2023-06-15T04:05:00+02:00", + "2023-06-15T04:10:00+02:00", + "2023-06-15T04:15:00+02:00", + "2023-06-15T04:20:00+02:00", + "2023-06-15T04:25:00+02:00", + "2023-06-15T04:30:00+02:00", + "2023-06-15T04:35:00+02:00", + "2023-06-15T04:40:00+02:00", + "2023-06-15T04:45:00+02:00", + "2023-06-15T04:50:00+02:00", + "2023-06-15T04:55:00+02:00", + "2023-06-15T05:00:00+02:00", + "2023-06-15T05:05:00+02:00", + "2023-06-15T05:10:00+02:00", + "2023-06-15T05:15:00+02:00", + "2023-06-15T05:20:00+02:00", + "2023-06-15T05:25:00+02:00", + "2023-06-15T05:30:00+02:00", + "2023-06-15T05:35:00+02:00", + "2023-06-15T05:40:00+02:00", + "2023-06-15T05:45:00+02:00", + "2023-06-15T05:50:00+02:00", + "2023-06-15T05:55:00+02:00", + "2023-06-15T06:00:00+02:00", + "2023-06-15T06:05:00+02:00", + "2023-06-15T06:10:00+02:00", + "2023-06-15T06:15:00+02:00", + "2023-06-15T06:20:00+02:00", + "2023-06-15T06:25:00+02:00", + "2023-06-15T06:30:00+02:00", + "2023-06-15T06:35:00+02:00", + "2023-06-15T06:40:00+02:00", + "2023-06-15T06:45:00+02:00", + "2023-06-15T06:50:00+02:00", + "2023-06-15T06:55:00+02:00", + "2023-06-15T07:00:00+02:00", + "2023-06-15T07:05:00+02:00", + "2023-06-15T07:10:00+02:00", + "2023-06-15T07:15:00+02:00", + "2023-06-15T07:20:00+02:00", + "2023-06-15T07:25:00+02:00", + "2023-06-15T07:30:00+02:00", + "2023-06-15T07:35:00+02:00", + "2023-06-15T07:40:00+02:00", + "2023-06-15T07:45:00+02:00", + "2023-06-15T07:50:00+02:00", + "2023-06-15T07:55:00+02:00", + "2023-06-15T08:00:00+02:00", + "2023-06-15T08:05:00+02:00", + "2023-06-15T08:10:00+02:00", + "2023-06-15T08:15:00+02:00", + "2023-06-15T08:20:00+02:00", + "2023-06-15T08:25:00+02:00", + "2023-06-15T08:30:00+02:00", + "2023-06-15T08:35:00+02:00", + "2023-06-15T08:40:00+02:00", + "2023-06-15T08:45:00+02:00", + "2023-06-15T08:50:00+02:00", + "2023-06-15T08:55:00+02:00", + "2023-06-15T09:00:00+02:00", + "2023-06-15T09:05:00+02:00", + "2023-06-15T09:10:00+02:00", + "2023-06-15T09:15:00+02:00", + "2023-06-15T09:20:00+02:00", + "2023-06-15T09:25:00+02:00", + "2023-06-15T09:30:00+02:00", + "2023-06-15T09:35:00+02:00", + "2023-06-15T09:40:00+02:00", + "2023-06-15T09:45:00+02:00", + "2023-06-15T09:50:00+02:00", + "2023-06-15T09:55:00+02:00", + "2023-06-15T10:00:00+02:00", + "2023-06-15T10:05:00+02:00", + "2023-06-15T10:10:00+02:00", + "2023-06-15T10:15:00+02:00", + "2023-06-15T10:20:00+02:00", + "2023-06-15T10:25:00+02:00", + "2023-06-15T10:30:00+02:00", + "2023-06-15T10:35:00+02:00", + "2023-06-15T10:40:00+02:00", + "2023-06-15T10:45:00+02:00", + "2023-06-15T10:50:00+02:00", + "2023-06-15T10:55:00+02:00", + "2023-06-15T11:00:00+02:00", + "2023-06-15T11:05:00+02:00", + "2023-06-15T11:10:00+02:00", + "2023-06-15T11:15:00+02:00", + "2023-06-15T11:20:00+02:00", + "2023-06-15T11:25:00+02:00", + "2023-06-15T11:30:00+02:00", + "2023-06-15T11:35:00+02:00", + "2023-06-15T11:40:00+02:00", + "2023-06-15T11:45:00+02:00", + "2023-06-15T11:50:00+02:00", + "2023-06-15T11:55:00+02:00", + "2023-06-15T12:00:00+02:00", + "2023-06-15T12:05:00+02:00", + "2023-06-15T12:10:00+02:00", + "2023-06-15T12:15:00+02:00", + "2023-06-15T12:20:00+02:00", + "2023-06-15T12:25:00+02:00", + "2023-06-15T12:30:00+02:00", + "2023-06-15T12:35:00+02:00", + "2023-06-15T12:40:00+02:00", + "2023-06-15T12:45:00+02:00", + "2023-06-15T12:50:00+02:00", + "2023-06-15T12:55:00+02:00", + "2023-06-15T13:00:00+02:00", + "2023-06-15T13:05:00+02:00", + "2023-06-15T13:10:00+02:00", + "2023-06-15T13:15:00+02:00", + "2023-06-15T13:20:00+02:00", + "2023-06-15T13:25:00+02:00", + "2023-06-15T13:30:00+02:00", + "2023-06-15T13:35:00+02:00", + "2023-06-15T13:40:00+02:00", + "2023-06-15T13:45:00+02:00", + "2023-06-15T13:50:00+02:00", + "2023-06-15T13:55:00+02:00", + "2023-06-15T14:00:00+02:00", + "2023-06-15T14:05:00+02:00", + "2023-06-15T14:10:00+02:00", + "2023-06-15T14:15:00+02:00", + "2023-06-15T14:20:00+02:00", + "2023-06-15T14:25:00+02:00", + "2023-06-15T14:30:00+02:00", + "2023-06-15T14:35:00+02:00", + "2023-06-15T14:40:00+02:00", + "2023-06-15T14:45:00+02:00", + "2023-06-15T14:50:00+02:00", + "2023-06-15T14:55:00+02:00", + "2023-06-15T15:00:00+02:00", + "2023-06-15T15:05:00+02:00", + "2023-06-15T15:10:00+02:00", + "2023-06-15T15:15:00+02:00", + "2023-06-15T15:20:00+02:00", + "2023-06-15T15:25:00+02:00", + "2023-06-15T15:30:00+02:00", + "2023-06-15T15:35:00+02:00", + "2023-06-15T15:40:00+02:00", + "2023-06-15T15:45:00+02:00", + "2023-06-15T15:50:00+02:00", + "2023-06-15T15:55:00+02:00", + "2023-06-15T16:00:00+02:00", + "2023-06-15T16:05:00+02:00", + "2023-06-15T16:10:00+02:00", + "2023-06-15T16:15:00+02:00", + "2023-06-15T16:20:00+02:00", + "2023-06-15T16:25:00+02:00", + "2023-06-15T16:30:00+02:00", + "2023-06-15T16:35:00+02:00", + "2023-06-15T16:40:00+02:00", + "2023-06-15T16:45:00+02:00", + "2023-06-15T16:50:00+02:00", + "2023-06-15T16:55:00+02:00", + "2023-06-15T17:00:00+02:00", + "2023-06-15T17:05:00+02:00", + "2023-06-15T17:10:00+02:00", + "2023-06-15T17:15:00+02:00", + "2023-06-15T17:20:00+02:00", + "2023-06-15T17:25:00+02:00", + "2023-06-15T17:30:00+02:00", + "2023-06-15T17:35:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayWithIncompleteValues.json b/centreon/packages/ui/src/Graph/mockedData/lastDayWithIncompleteValues.json similarity index 98% rename from centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayWithIncompleteValues.json rename to centreon/packages/ui/src/Graph/mockedData/lastDayWithIncompleteValues.json index 2d1399d187..69dd082285 100644 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayWithIncompleteValues.json +++ b/centreon/packages/ui/src/Graph/mockedData/lastDayWithIncompleteValues.json @@ -329,20 +329,7 @@ 0.32339333333, null ], - "prints": [ - [ - "Last:0.32" - ], - [ - "Min:0.03" - ], - [ - "Max:0.97" - ], - [ - "Average:0.51" - ] - ], + "prints": [["Last:0.32"], ["Min:0.03"], ["Max:0.97"], ["Average:0.51"]], "last_value": 0.32, "minimum_value": 0.03, "maximum_value": 0.97, @@ -667,18 +654,10 @@ null ], "prints": [ - [ - "Last:87.27" - ], - [ - "Min:70.31" - ], - [ - "Max:88.03" - ], - [ - "Average:78.07" - ] + ["Last:87.27"], + ["Min:70.31"], + ["Max:88.03"], + ["Average:78.07"] ], "last_value": 87.27, "minimum_value": 70.31, @@ -1006,20 +985,7 @@ 0.64624666667, null ], - "prints": [ - [ - "Last:0.65" - ], - [ - "Min:0.03" - ], - [ - "Max:0.98" - ], - [ - "Average:0.50" - ] - ], + "prints": [["Last:0.65"], ["Min:0.03"], ["Max:0.98"], ["Average:0.50"]], "last_value": 0.65, "minimum_value": 0.03, "maximum_value": 0.98, @@ -1317,4 +1283,4 @@ "2023-06-19T17:00:00+02:00", "2023-06-19T17:05:00+02:00" ] -} \ No newline at end of file +} diff --git a/centreon/packages/ui/src/Graph/mockedData/lastDayWithLotOfUnits.json b/centreon/packages/ui/src/Graph/mockedData/lastDayWithLotOfUnits.json new file mode 100644 index 0000000000..54b39ae3f2 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/lastDayWithLotOfUnits.json @@ -0,0 +1,1621 @@ +{ + "global": { + "title": "oracle-buffer-hit-ratio graph on srv-oracle-users", + "start": "2023-06-18T17:04:46+02:00", + "end": "2023-06-19T17:04:46+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 0, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 5614, + "metric_id": 13536, + "metric": "connTime", + "metric_legend": "connTime", + "unit": "b/s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#6699cc", + "ds_stack": true + }, + "legend": "connTime", + "stack": true, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.53123333333, + 0.56452, + 0.5341, + 0.51537666667, + 0.25730333333, + 0.48611333333, + 0.41435666667, + 0.42371, + 0.55438333333, + 0.60211, + 0.72619, + 0.67167333333, + 0.63883333333, + 0.52027666667, + 0.67368666667, + 0.83443333333, + 0.86102333333, + 0.76291666667, + 0.39081666667, + 0.22492333333, + 0.64388333333, + 0.81007666667, + 0.61811333333, + 0.58901, + 0.58737333333, + 0.60651333333, + 0.74783333333, + 0.92823, + 0.89503333333, + 0.82551333333, + 0.75017333333, + 0.33549666667, + 0.40213666667, + 0.60645666667, + 0.55312666667, + 0.31503666667, + 0.078203333333, + 0.44113, + 0.35953666667, + 0.41073333333, + 0.8358, + 0.86683333333, + 0.68390666667, + 0.28047333333, + 0.0607, + 0.49994666667, + 0.75459666667, + 0.51677333333, + 0.63137, + 0.74141666667, + 0.60566666667, + 0.32040666667, + 0.15528666667, + 0.43645333333, + 0.65261666667, + 0.46921666667, + 0.60091666667, + 0.47360333333, + 0.10643, + 0.29183, + 0.35995, + 0.40254333333, + 0.58827666667, + 0.45241333333, + 0.24455333333, + 0.18674, + 0.13640333333, + 0.34897666667, + 0.55044, + 0.52277666667, + 0.69064333333, + 0.56236333333, + 0.39762, + 0.65475666667, + 0.58477, + 0.49433, + 0.28894333333, + 0.49294333333, + 0.64683, + 0.35607666667, + 0.55465, + 0.45637333333, + 0.54171666667, + 0.42502666667, + 0.30588, + 0.32094, + 0.22269333333, + 0.44262, + 0.62073333333, + 0.60227666667, + 0.32498333333, + 0.25148, + 0.47383333333, + 0.30778333333, + 0.26413666667, + 0.58817, + 0.42611, + 0.44147, + 0.70327, + 0.61590333333, + 0.67324333333, + 0.71732333333, + 0.38394, + 0.23022, + 0.32007333333, + 0.37968, + 0.32084666667, + 0.54738333333, + 0.85402666667, + 0.72061666667, + 0.69251666667, + 0.87611666667, + 0.83591333333, + 0.36148, + 0.45470333333, + 0.68843, + 0.52516, + 0.50904666667, + 0.51209333333, + 0.6553, + 0.85674333333, + 0.51166, + 0.4353, + 0.76875333333, + 0.78365666667, + 0.71250666667, + 0.81178666667, + 0.67356666667, + 0.48919333333, + 0.55755, + 0.50259333333, + 0.28751333333, + 0.56895666667, + 0.46348666667, + 0.065866666667, + 0.56505666667, + 0.90545333333, + 0.80578666667, + 0.5926, + 0.60521333333, + 0.80492333333, + 0.46766666667, + 0.45899, + 0.67702333333, + 0.35113666667, + 0.47643666667, + 0.71041666667, + 0.55792, + 0.73992, + 0.76518, + 0.35002333333, + 0.26003, + 0.55407333333, + 0.76546333333, + 0.37679, + 0.067946666667, + 0.34679, + 0.26, + 0.66257333333, + 0.40848, + 0.53458333333, + 0.51552, + 0.61109, + 0.85858333333, + 0.68362, + 0.27503333333, + 0.2019, + 0.13221333333, + 0.79457, + 0.69949666667, + 0.35275333333, + 0.81529, + 0.078553333333, + 0.03339, + 0.39325333333, + 0.40176333333, + 0.14054333333, + 0.32028666667, + 0.33053666667, + 0.89415666667, + 0.35837666667, + 0.85846, + 0.44418, + 0.29612333333, + 0.84746333333, + 0.69179, + 0.15608666667, + 0.46017333333, + 0.52039333333, + 0.04379, + 0.20713333333, + 0.69767, + 0.073123333333, + 0.72342666667, + 0.16706, + 0.56104666667, + 0.7642, + 0.84448, + 0.12149, + 0.84398666667, + 0.17495, + 0.73171, + 0.31948666667, + 0.86547, + 0.51050333333, + 0.73184, + 0.24332, + 0.64512333333, + 0.87497666667, + 0.64631666667, + 0.93808666667, + 0.40630666667, + 0.58898666667, + 0.079853333333, + 0.52536666667, + 0.24560333333, + 0.08881, + 0.59968333333, + 0.76672666667, + 0.12605, + 0.57891, + 0.3994, + 0.93223, + 0.91706, + 0.73287333333, + 0.35697666667, + 0.76189, + 0.53946666667, + 0.80423333333, + 0.89725, + 0.11539666667, + 0.29745333333, + 0.77966666667, + 0.71089333333, + 0.26618666667, + 0.66581333333, + 0.72693, + 0.2858, + 0.21299, + 0.19799666667, + 0.73068666667, + 0.48692, + 0.5738, + 0.060393333333, + 0.36694333333, + 0.29905, + 0.70373, + 0.59026666667, + 0.95010333333, + 0.96899666667, + 0.18778333333, + 0.44893666667, + 0.54063333333, + 0.30962666667, + 0.67226, + 0.8979, + 0.61484, + 0.75435333333, + 0.21677, + 0.25687, + 0.73120666667, + 0.20676666667, + 0.32435333333, + 0.44787666667, + 0.89004333333, + 0.48926333333, + 0.36620666667, + 0.53720333333, + 0.77175333333, + 0.81031333333, + 0.68735, + 0.29566333333, + 0.64441333333, + 0.53196, + 0.57447666667, + 0.050853333333, + 0.28769333333, + 0.17988666667, + 0.10621333333, + 0.49249333333, + 0.81975, + 0.48222, + 0.25617333333, + 0.75395, + 0.36961, + 0.53932333333, + 0.65789666667, + 0.32339333333, + null + ], + "prints": [["Last:0.32"], ["Min:0.03"], ["Max:0.97"], ["Average:0.51"]], + "last_value": 0.32, + "minimum_value": 0.03, + "maximum_value": 0.97, + "average_value": 0.51 + }, + { + "index_id": 5614, + "metric_id": 13534, + "metric": "hitratio", + "metric_legend": "hitratio", + "unit": "%", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#cc9999" + }, + "legend": "hitratio", + "stack": 1, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 1, + "data": [ + 80.192446667, + 80.324963333, + 80.31374, + 80.043863333, + 78.97382, + 78.01196, + 77.85379, + 77.311446667, + 77.518806667, + 77.363833333, + 76.410303333, + 75.385206667, + 75.470793333, + 75.444866667, + 74.902366667, + 74.787096667, + 73.424696667, + 72.984073333, + 73.127803333, + 72.06457, + 71.092996667, + 70.652853333, + 72.838793333, + 74.3249, + 74.690726667, + 75.462586667, + 74.87943, + 75.429203333, + 76.836436667, + 77.9801, + 78.159586667, + 77.133953333, + 76.139193333, + 76.100923333, + 75.977446667, + 75.897756667, + 75.158033333, + 73.702993333, + 72.387816667, + 71.130253333, + 70.39241, + 71.103633333, + 71.842186667, + 72.052586667, + 71.766026667, + 71.548363333, + 71.128753333, + 72.8407, + 74.584996667, + 73.229936667, + 71.78108, + 71.673396667, + 71.184396667, + 70.4531, + 70.344756667, + 72.715336667, + 74.256866667, + 73.24873, + 73.652976667, + 75.191423333, + 75.63962, + 74.709446667, + 74.725396667, + 75.930556667, + 77.090426667, + 77.774146667, + 78.34251, + 79.083023333, + 79.19294, + 79.902196667, + 80.164726667, + 79.28103, + 78.529063333, + 77.409276667, + 75.7148, + 75.432493333, + 76.331206667, + 76.05935, + 76.290816667, + 76.174896667, + 74.520766667, + 74.641866667, + 75.632723333, + 75.710626667, + 74.692966667, + 73.84993, + 73.685023333, + 73.59346, + 73.485723333, + 74.233233333, + 76.036953333, + 77.343543333, + 77.40446, + 77.324593333, + 77.389233333, + 76.69522, + 75.906923333, + 75.531203333, + 75.230936667, + 74.892196667, + 75.257436667, + 76.047326667, + 76.83612, + 76.4245, + 74.62692, + 73.454276667, + 73.838346667, + 74.91667, + 75.654806667, + 75.07332, + 73.51074, + 72.497866667, + 72.15109, + 71.317343333, + 71.56787, + 72.18692, + 71.37498, + 70.426836667, + 70.611836667, + 71.692516667, + 72.545326667, + 71.79552, + 70.463443333, + 70.393413333, + 72.92507, + 75.238116667, + 74.41566, + 72.43751, + 70.750156667, + 70.50232, + 73.044236667, + 75.752553333, + 76.848816667, + 77.010526667, + 77.599906667, + 77.768733333, + 77.314866667, + 77.01545, + 77.704426667, + 78.521463333, + 79.173236667, + 79.92521, + 80.769776667, + 82.234066667, + 83.11997, + 82.61005, + 82.86877, + 83.577323333, + 84.011146667, + 84.565116667, + 84.8117, + 85.159493333, + 84.523926667, + 83.279573333, + 82.95924, + 83.57027, + 84.89847, + 83.853206667, + 84.676703333, + 86.10003, + 85.350266667, + 84.94219, + 85.116616667, + 84.75833, + 83.948586667, + 83.637406667, + 83.2102, + 82.458723333, + 82.4267, + 83.49822, + 83.83907, + 82.507316667, + 82.858513333, + 84.26815, + 83.920333333, + 84.255026667, + 82.74865, + 82.445566667, + 81.86038, + 80.631133333, + 81.62438, + 81.23579, + 80.95778, + 79.499446667, + 78.88417, + 78.406263333, + 76.631363333, + 75.627376667, + 75.485826667, + 73.82354, + 72.111716667, + 70.308843333, + 74.6297, + 75.690653333, + 74.810816667, + 75.50583, + 76.246803333, + 77.157083333, + 77.98975, + 77.812933333, + 77.722826667, + 79.01059, + 79.221413333, + 80.305683333, + 80.499336667, + 78.993733333, + 80.18652, + 81.94138, + 83.55718, + 82.897013333, + 82.29185, + 81.54342, + 82.708416667, + 83.576366667, + 83.04722, + 83.864086667, + 83.699626667, + 82.20913, + 81.32802, + 79.87446, + 79.22439, + 77.4626, + 78.31997, + 76.586803333, + 77.81823, + 77.163863333, + 77.913456667, + 79.026213333, + 77.37621, + 78.781353333, + 79.298723333, + 78.798236667, + 79.785363333, + 80.425, + 81.082246667, + 82.75068, + 83.45285, + 82.340293333, + 82.654883333, + 82.498793333, + 81.795116667, + 82.371406667, + 80.786006667, + 79.975043333, + 80.537633333, + 78.944543333, + 77.60028, + 76.822273333, + 75.409623333, + 74.17238, + 75.874883333, + 77.656453333, + 76.133693333, + 75.23148, + 76.698886667, + 76.538843333, + 77.68948, + 77.99752, + 79.06483, + 79.920213333, + 80.295163333, + 82.13812, + 81.25856, + 79.891413333, + 80.126633333, + 79.632393333, + 81.009086667, + 81.655146667, + 82.30286, + 83.57457, + 83.236493333, + 83.495466667, + 82.422156667, + 82.68833, + 83.218446667, + 84.335683333, + 85.520996667, + 85.508586667, + 85.91827, + 84.19682, + 86.29191, + 87.191866667, + 87.270053333, + 88.025836667, + 87.42611, + 86.863723333, + 86.564723333, + 87.268263333, + null + ], + "prints": [ + ["Last:87.27"], + ["Min:70.31"], + ["Max:88.03"], + ["Average:78.07"] + ], + "last_value": 87.27, + "minimum_value": 70.31, + "maximum_value": 88.03, + "average_value": 78.07 + }, + { + "index_id": 23, + "metric_id": 23, + "metric": "I/O input", + "metric_legend": "I/O input", + "unit": "b/s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#00ffcc", + "ds_stack": true + }, + "legend": "I/O input", + "stack": true, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 2, + "data": [ + 0.53123333333, + 0.56452, + 0.5341, + 0.51537666667, + 0.25730333333, + 0.48611333333, + 0.41435666667, + 0.42371, + 0.55438333333, + 0.60211, + 0.72619, + 0.67167333333, + 0.63883333333, + 0.52027666667, + 0.67368666667, + 0.83443333333, + 0.86102333333, + 0.76291666667, + 0.39081666667, + 0.22492333333, + 0.64388333333, + 0.81007666667, + 0.61811333333, + 0.58901, + 0.58737333333, + 0.60651333333, + 0.74783333333, + 0.92823, + 0.89503333333, + 0.82551333333, + 0.75017333333, + 0.33549666667, + 0.40213666667, + 0.60645666667, + 0.55312666667, + 0.31503666667, + 0.078203333333, + 0.44113, + 0.35953666667, + 0.41073333333, + 0.8358, + 0.86683333333, + 0.68390666667, + 0.28047333333, + 0.0607, + 0.49994666667, + 0.75459666667, + 0.51677333333, + 0.63137, + 0.74141666667, + 0.60566666667, + 0.32040666667, + 0.15528666667, + 0.43645333333, + 0.65261666667, + 0.46921666667, + 0.60091666667, + 0.47360333333, + 0.10643, + 0.29183, + 0.35995, + 0.40254333333, + 0.58827666667, + 0.45241333333, + 0.24455333333, + 0.18674, + 0.13640333333, + 0.34897666667, + 0.55044, + 0.52277666667, + 0.69064333333, + 0.56236333333, + 0.39762, + 0.65475666667, + 0.58477, + 0.49433, + 0.28894333333, + 0.49294333333, + 0.64683, + 0.35607666667, + 0.55465, + 0.45637333333, + 0.54171666667, + 0.42502666667, + 0.30588, + 0.32094, + 0.22269333333, + 0.44262, + 0.62073333333, + 0.60227666667, + 0.32498333333, + 0.25148, + 0.47383333333, + 0.30778333333, + 0.26413666667, + 0.58817, + 0.42611, + 0.44147, + 0.70327, + 0.61590333333, + 0.67324333333, + 0.71732333333, + 0.38394, + 0.23022, + 0.32007333333, + 0.37968, + 0.32084666667, + 0.54738333333, + 0.85402666667, + 0.72061666667, + 0.69251666667, + 0.87611666667, + 0.83591333333, + 0.36148, + 0.45470333333, + 0.68843, + 0.52516, + 0.50904666667, + 0.51209333333, + 0.6553, + 0.85674333333, + 0.51166, + 0.4353, + 0.76875333333, + 0.78365666667, + 0.71250666667, + 0.81178666667, + 0.67356666667, + 0.48919333333, + 0.55755, + 0.50259333333, + 0.28751333333, + 0.56895666667, + 0.46348666667, + 0.065866666667, + 0.56505666667, + 0.90545333333, + 0.80578666667, + 0.5926, + 0.60521333333, + 0.80492333333, + 0.46766666667, + 0.45899, + 0.67702333333, + 0.35113666667, + 0.47643666667, + 0.71041666667, + 0.55792, + 0.73992, + 0.76518, + 0.35002333333, + 0.26003, + 0.55407333333, + 0.76546333333, + 0.37679, + 0.067946666667, + 0.34679, + 0.26, + 0.66257333333, + 0.40848, + 0.53458333333, + 0.51552, + 0.61109, + 0.85858333333, + 0.68362, + 0.27503333333, + 0.2019, + 0.13221333333, + 0.79457, + 0.69949666667, + 0.35275333333, + 0.81529, + 0.078553333333, + 0.03339, + 0.39325333333, + 0.40176333333, + 0.14054333333, + 0.32028666667, + 0.33053666667, + 0.89415666667, + 0.35837666667, + 0.85846, + 0.44418, + 0.29612333333, + 0.84746333333, + 0.69179, + 0.15608666667, + 0.46017333333, + 0.52039333333, + 0.04379, + 0.20713333333, + 0.69767, + 0.073123333333, + 0.72342666667, + 0.16706, + 0.56104666667, + 0.7642, + 0.84448, + 0.12149, + 0.84398666667, + 0.17495, + 0.73171, + 0.31948666667, + 0.86547, + 0.51050333333, + 0.73184, + 0.24332, + 0.64512333333, + 0.87497666667, + 0.64631666667, + 0.93808666667, + 0.40630666667, + 0.58898666667, + 0.079853333333, + 0.52536666667, + 0.24560333333, + 0.08881, + 0.59968333333, + 0.76672666667, + 0.12605, + 0.57891, + 0.3994, + 0.93223, + 0.91706, + 0.73287333333, + 0.35697666667, + 0.76189, + 0.53946666667, + 0.80423333333, + 0.89725, + 0.11539666667, + 0.29745333333, + 0.77966666667, + 0.71089333333, + 0.26618666667, + 0.66581333333, + 0.72693, + 0.2858, + 0.21299, + 0.19799666667, + 0.73068666667, + 0.48692, + 0.5738, + 0.060393333333, + 0.36694333333, + 0.29905, + 0.70373, + 0.59026666667, + 0.95010333333, + 0.96899666667, + 0.18778333333, + 0.44893666667, + 0.54063333333, + 0.30962666667, + 0.67226, + 0.8979, + 0.61484, + 0.75435333333, + 0.21677, + 0.25687, + 0.73120666667, + 0.20676666667, + 0.32435333333, + 0.44787666667, + 0.89004333333, + 0.48926333333, + 0.36620666667, + 0.53720333333, + 0.77175333333, + 0.81031333333, + 0.68735, + 0.29566333333, + 0.64441333333, + 0.53196, + 0.57447666667, + 0.050853333333, + 0.28769333333, + 0.17988666667, + 0.10621333333, + 0.49249333333, + 0.81975, + 0.48222, + 0.25617333333, + 0.75395, + 0.36961, + 0.53932333333, + 0.65789666667, + 0.32339333333, + null + ], + "prints": [["Last:0.65"], ["Min:0.03"], ["Max:0.98"], ["Average:0.50"]], + "last_value": 0.65, + "minimum_value": 0.03, + "maximum_value": 0.98, + "average_value": 0.5 + }, + { + "index_id": 24, + "metric_id": 24, + "metric": "Space used", + "metric_legend": "Space used", + "unit": "B", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#aa6599" + }, + "legend": "Space used", + "stack": 1, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 3, + "data": [ + 7341.063043426099, + 3356.9571225594605, + 4794.4482380612235, + 1786.1428155756234, + 9563.094984676685, + 2851.588837226436, + 3797.830138923492, + 9196.119045752994, + 2551.3427684107996, + 6711.5263222104295, + 5587.096106325074, + 7946.588017348541, + 5524.526645923336, + 916.9642284888835, + 801.1386916005912, + 4879.934573574293, + 9232.824702768386, + 3270.955257592973, + 4739.988578986932, + 6853.8610184525605, + 5760.291046490363, + 77.36001736519428, + 4199.427031864697, + 2570.5345818260894, + 7169.271207331486, + 7313.294806041846, + 125.48886438893284, + 9828.969089665066, + 1705.1506160664392, + 1454.112466246275, + 2676.728539919377, + 6820.665080614934, + 46.20363567137262, + 4146.381695086781, + 2978.7527196539468, + 2562.7249196578837, + 250.5596330089894, + 731.3909394911477, + 8109.330481224131, + 9987.09436783469, + 300.1382288228879, + 3278.6066834996745, + 7208.337885504337, + 505.5253714787745, + 7778.700207531618, + 489.7386457148231, + 2369.7151176666766, + 3824.3639507940234, + 8554.773432705439, + 1390.8311341112596, + 2645.216634411965, + 9023.018950482721, + 1897.7011289077802, + 2219.8199640618036, + 3411.771670515491, + 8261.235689530447, + 7713.183755342174, + 9702.011527885648, + 766.4175329998144, + 3288.8318517724224, + 4498.98768380388, + 5715.142137158665, + 5024.354972325697, + 3715.7895021739278, + 8609.220801639782, + 4405.419489731788, + 7549.784036173957, + 2916.911431598847, + 7975.945328101473, + 1581.4277641594927, + 8468.790047973767, + 3508.257603672397, + 3201.9438103875964, + 9132.613213822677, + 2262.5525536465816, + 2460.0187045398825, + 6003.9176143594295, + 5995.951229041046, + 7842.370920862622, + 4498.577932026529, + 8357.48869015178, + 49.52677884087122, + 215.78029780710847, + 8775.631185825832, + 9756.77293267745, + 4296.91236095775, + 5971.825730952699, + 8792.006291633425, + 3753.9160123161246, + 6056.0451529027905, + 6480.680170996795, + 9806.999955923415, + 2182.228563505557, + 2945.5937364460538, + 4490.940589443893, + 3918.961146866535, + 9973.584956231962, + 4030.076187023923, + 1207.0512422703137, + 8525.884693019925, + 5292.685031345437, + 4680.395176356113, + 2024.6728053019672, + 5781.626717513468, + 4985.151103894174, + 8636.03534164651, + 5517.694924681153, + 9170.829040398705, + 9977.47243922835, + 8068.007414109319, + 9171.933158492206, + 3306.870061173763, + 4997.133809169505, + 2748.244679864153, + 2532.962023212052, + 3580.392497309455, + 4293.370629411513, + 2096.5582593971253, + 7731.839644976719, + 502.8614250108251, + 7296.230565947804, + 5294.058054882813, + 2544.644778348057, + 4611.789203221303, + 9075.680989780018, + 6030.402546092634, + 5400.979244183576, + 1351.3582528186587, + 3452.258206341347, + 381.82358787783824, + 7219.6549999644985, + 5291.703665508611, + 7166.208114053027, + 7486.587851876792, + 1947.417237408825, + 8570.034594896386, + 2884.5768718849263, + 7819.870722763809, + 8926.716607655302, + 6882.90123912904, + 3314.39007893635, + 8766.138664292177, + 8470.14074988817, + 7635.5557542490205, + 6219.61820853787, + 7038.708335934222, + 5795.447007701511, + 661.0144877601892, + 8951.344416961356, + 5232.906781935042, + 2828.1704759872173, + 6304.142282067777, + 2443.2435662762673, + 1099.7034346480089, + 4125.745194582217, + 2812.4649345660823, + 1121.447710364395, + 8383.063428562882, + 5957.5971722416425, + 898.6137737756707, + 1480.539422073472, + 9493.98833486201, + 4763.035972750268, + 3905.3721101210867, + 8343.386495139344, + 3416.3512853850784, + 4797.335446381687, + 4078.227028629929, + 2467.015532409246, + 7586.085254877912, + 3660.7643243531766, + 7301.541618224055, + 967.4699538617103, + 7283.919797529682, + 5995.283121369642, + 779.7401514511042, + 6575.943609473667, + 910.5945274914122, + 8829.05198983642, + 5165.7876248357825, + 5663.738391523165, + 4662.893963242967, + 9999.391562039187, + 2265.532407627091, + 5358.382318312016, + 9002.698389690666, + 3282.6599962956234, + 7626.044600638286, + 474.51753391286604, + 5117.193918781553, + 4115.508897202035, + 4577.8948842324535, + 5113.195268463116, + 9344.044808732888, + 4729.114827348023, + 3639.5152743283024, + 6503.876698293757, + 3249.571318958731, + 5634.6070985076185, + 3838.5741498038947, + 254.32396420951972, + 4384.401440760108, + 6436.6411903403, + 5739.193054121527, + 7412.266096582101, + 3430.122377018838, + 5057.447770503611, + 1803.0904885552422, + 7838.479782423389, + 5449.479227614817, + 2875.7122865017523, + 3730.4284299015308, + 7021.345882560218, + 5821.046279175767, + 2533.724119167128, + 8910.041365151046, + 7222.653925273184, + 1621.9276555732997, + 570.1254539551726, + 4424.298114493642, + 2188.6950018095777, + 973.7774046192695, + 8643.769948151094, + 9852.203052056953, + 8954.988590030423, + 5380.345214776778, + 2845.5576058848073, + 8458.942326703014, + 478.546356449505, + 7752.0545420145145, + 9261.284415695258, + 5261.573241518489, + 2937.7535568411, + 9639.843291600699, + 2054.0794504947053, + 4527.421021806636, + 3344.049547169402, + 6590.439753913984, + 708.382247208025, + 6915.39190391636, + 4267.174784163923, + 9075.371766656337, + 8610.045306877955, + 8320.7046788029, + 5952.155045460622, + 7133.754212299616, + 6667.362373280911, + 7832.8806886742495, + 3386.343354653804, + 5019.2325982320735, + 122.57326743840386, + 2877.86037939576, + 9861.76109040916, + 541.4724961810115, + 8907.335497795355, + 6963.817887643758, + 2294.8746878375287, + 498.07106383289636, + 7721.69118938436, + 2200.5964582257902, + 8430.740682723625, + 1252.9812029815919, + 7406.12451773185, + 7042.787385462412, + 4092.6084745361236, + 735.5263097704149, + 4138.348232658311, + 2412.8939787258414, + 7166.506259103524, + 5844.289868709522, + 3609.013569344602, + 4075.3823942719723, + 4396.133228659846, + 4009.725486674713, + 7866.397451550341, + 3817.0857469591056, + 5948.72361422666, + 1933.983353458924, + 8613.006015909748, + 170.70362071947898, + 7891.19581312885, + 5966.687331091486, + 7574.035701698151, + 4411.32423497854, + 1923.0112456014635, + 9835.02299544594, + 5131.178666005183, + 5221.543853127492, + null + ], + "prints": [["Last:0.65"], ["Min:0.03"], ["Max:0.98"], ["Average:0.50"]], + "last_value": 0.65, + "minimum_value": 0.03, + "maximum_value": 0.98, + "average_value": 0.5 + } + ], + "times": [ + "2023-06-18T17:05:00+02:00", + "2023-06-18T17:10:00+02:00", + "2023-06-18T17:15:00+02:00", + "2023-06-18T17:20:00+02:00", + "2023-06-18T17:25:00+02:00", + "2023-06-18T17:30:00+02:00", + "2023-06-18T17:35:00+02:00", + "2023-06-18T17:40:00+02:00", + "2023-06-18T17:45:00+02:00", + "2023-06-18T17:50:00+02:00", + "2023-06-18T17:55:00+02:00", + "2023-06-18T18:00:00+02:00", + "2023-06-18T18:05:00+02:00", + "2023-06-18T18:10:00+02:00", + "2023-06-18T18:15:00+02:00", + "2023-06-18T18:20:00+02:00", + "2023-06-18T18:25:00+02:00", + "2023-06-18T18:30:00+02:00", + "2023-06-18T18:35:00+02:00", + "2023-06-18T18:40:00+02:00", + "2023-06-18T18:45:00+02:00", + "2023-06-18T18:50:00+02:00", + "2023-06-18T18:55:00+02:00", + "2023-06-18T19:00:00+02:00", + "2023-06-18T19:05:00+02:00", + "2023-06-18T19:10:00+02:00", + "2023-06-18T19:15:00+02:00", + "2023-06-18T19:20:00+02:00", + "2023-06-18T19:25:00+02:00", + "2023-06-18T19:30:00+02:00", + "2023-06-18T19:35:00+02:00", + "2023-06-18T19:40:00+02:00", + "2023-06-18T19:45:00+02:00", + "2023-06-18T19:50:00+02:00", + "2023-06-18T19:55:00+02:00", + "2023-06-18T20:00:00+02:00", + "2023-06-18T20:05:00+02:00", + "2023-06-18T20:10:00+02:00", + "2023-06-18T20:15:00+02:00", + "2023-06-18T20:20:00+02:00", + "2023-06-18T20:25:00+02:00", + "2023-06-18T20:30:00+02:00", + "2023-06-18T20:35:00+02:00", + "2023-06-18T20:40:00+02:00", + "2023-06-18T20:45:00+02:00", + "2023-06-18T20:50:00+02:00", + "2023-06-18T20:55:00+02:00", + "2023-06-18T21:00:00+02:00", + "2023-06-18T21:05:00+02:00", + "2023-06-18T21:10:00+02:00", + "2023-06-18T21:15:00+02:00", + "2023-06-18T21:20:00+02:00", + "2023-06-18T21:25:00+02:00", + "2023-06-18T21:30:00+02:00", + "2023-06-18T21:35:00+02:00", + "2023-06-18T21:40:00+02:00", + "2023-06-18T21:45:00+02:00", + "2023-06-18T21:50:00+02:00", + "2023-06-18T21:55:00+02:00", + "2023-06-18T22:00:00+02:00", + "2023-06-18T22:05:00+02:00", + "2023-06-18T22:10:00+02:00", + "2023-06-18T22:15:00+02:00", + "2023-06-18T22:20:00+02:00", + "2023-06-18T22:25:00+02:00", + "2023-06-18T22:30:00+02:00", + "2023-06-18T22:35:00+02:00", + "2023-06-18T22:40:00+02:00", + "2023-06-18T22:45:00+02:00", + "2023-06-18T22:50:00+02:00", + "2023-06-18T22:55:00+02:00", + "2023-06-18T23:00:00+02:00", + "2023-06-18T23:05:00+02:00", + "2023-06-18T23:10:00+02:00", + "2023-06-18T23:15:00+02:00", + "2023-06-18T23:20:00+02:00", + "2023-06-18T23:25:00+02:00", + "2023-06-18T23:30:00+02:00", + "2023-06-18T23:35:00+02:00", + "2023-06-18T23:40:00+02:00", + "2023-06-18T23:45:00+02:00", + "2023-06-18T23:50:00+02:00", + "2023-06-18T23:55:00+02:00", + "2023-06-19T00:00:00+02:00", + "2023-06-19T00:05:00+02:00", + "2023-06-19T00:10:00+02:00", + "2023-06-19T00:15:00+02:00", + "2023-06-19T00:20:00+02:00", + "2023-06-19T00:25:00+02:00", + "2023-06-19T00:30:00+02:00", + "2023-06-19T00:35:00+02:00", + "2023-06-19T00:40:00+02:00", + "2023-06-19T00:45:00+02:00", + "2023-06-19T00:50:00+02:00", + "2023-06-19T00:55:00+02:00", + "2023-06-19T01:00:00+02:00", + "2023-06-19T01:05:00+02:00", + "2023-06-19T01:10:00+02:00", + "2023-06-19T01:15:00+02:00", + "2023-06-19T01:20:00+02:00", + "2023-06-19T01:25:00+02:00", + "2023-06-19T01:30:00+02:00", + "2023-06-19T01:35:00+02:00", + "2023-06-19T01:40:00+02:00", + "2023-06-19T01:45:00+02:00", + "2023-06-19T01:50:00+02:00", + "2023-06-19T01:55:00+02:00", + "2023-06-19T02:00:00+02:00", + "2023-06-19T02:05:00+02:00", + "2023-06-19T02:10:00+02:00", + "2023-06-19T02:15:00+02:00", + "2023-06-19T02:20:00+02:00", + "2023-06-19T02:25:00+02:00", + "2023-06-19T02:30:00+02:00", + "2023-06-19T02:35:00+02:00", + "2023-06-19T02:40:00+02:00", + "2023-06-19T02:45:00+02:00", + "2023-06-19T02:50:00+02:00", + "2023-06-19T02:55:00+02:00", + "2023-06-19T03:00:00+02:00", + "2023-06-19T03:05:00+02:00", + "2023-06-19T03:10:00+02:00", + "2023-06-19T03:15:00+02:00", + "2023-06-19T03:20:00+02:00", + "2023-06-19T03:25:00+02:00", + "2023-06-19T03:30:00+02:00", + "2023-06-19T03:35:00+02:00", + "2023-06-19T03:40:00+02:00", + "2023-06-19T03:45:00+02:00", + "2023-06-19T03:50:00+02:00", + "2023-06-19T03:55:00+02:00", + "2023-06-19T04:00:00+02:00", + "2023-06-19T04:05:00+02:00", + "2023-06-19T04:10:00+02:00", + "2023-06-19T04:15:00+02:00", + "2023-06-19T04:20:00+02:00", + "2023-06-19T04:25:00+02:00", + "2023-06-19T04:30:00+02:00", + "2023-06-19T04:35:00+02:00", + "2023-06-19T04:40:00+02:00", + "2023-06-19T04:45:00+02:00", + "2023-06-19T04:50:00+02:00", + "2023-06-19T04:55:00+02:00", + "2023-06-19T05:00:00+02:00", + "2023-06-19T05:05:00+02:00", + "2023-06-19T05:10:00+02:00", + "2023-06-19T05:15:00+02:00", + "2023-06-19T05:20:00+02:00", + "2023-06-19T05:25:00+02:00", + "2023-06-19T05:30:00+02:00", + "2023-06-19T05:35:00+02:00", + "2023-06-19T05:40:00+02:00", + "2023-06-19T05:45:00+02:00", + "2023-06-19T05:50:00+02:00", + "2023-06-19T05:55:00+02:00", + "2023-06-19T06:00:00+02:00", + "2023-06-19T06:05:00+02:00", + "2023-06-19T06:10:00+02:00", + "2023-06-19T06:15:00+02:00", + "2023-06-19T06:20:00+02:00", + "2023-06-19T06:25:00+02:00", + "2023-06-19T06:30:00+02:00", + "2023-06-19T06:35:00+02:00", + "2023-06-19T06:40:00+02:00", + "2023-06-19T06:45:00+02:00", + "2023-06-19T06:50:00+02:00", + "2023-06-19T06:55:00+02:00", + "2023-06-19T07:00:00+02:00", + "2023-06-19T07:05:00+02:00", + "2023-06-19T07:10:00+02:00", + "2023-06-19T07:15:00+02:00", + "2023-06-19T07:20:00+02:00", + "2023-06-19T07:25:00+02:00", + "2023-06-19T07:30:00+02:00", + "2023-06-19T07:35:00+02:00", + "2023-06-19T07:40:00+02:00", + "2023-06-19T07:45:00+02:00", + "2023-06-19T07:50:00+02:00", + "2023-06-19T07:55:00+02:00", + "2023-06-19T08:00:00+02:00", + "2023-06-19T08:05:00+02:00", + "2023-06-19T08:10:00+02:00", + "2023-06-19T08:15:00+02:00", + "2023-06-19T08:20:00+02:00", + "2023-06-19T08:25:00+02:00", + "2023-06-19T08:30:00+02:00", + "2023-06-19T08:35:00+02:00", + "2023-06-19T08:40:00+02:00", + "2023-06-19T08:45:00+02:00", + "2023-06-19T08:50:00+02:00", + "2023-06-19T08:55:00+02:00", + "2023-06-19T09:00:00+02:00", + "2023-06-19T09:05:00+02:00", + "2023-06-19T09:10:00+02:00", + "2023-06-19T09:15:00+02:00", + "2023-06-19T09:20:00+02:00", + "2023-06-19T09:25:00+02:00", + "2023-06-19T09:30:00+02:00", + "2023-06-19T09:35:00+02:00", + "2023-06-19T09:40:00+02:00", + "2023-06-19T09:45:00+02:00", + "2023-06-19T09:50:00+02:00", + "2023-06-19T09:55:00+02:00", + "2023-06-19T10:00:00+02:00", + "2023-06-19T10:05:00+02:00", + "2023-06-19T10:10:00+02:00", + "2023-06-19T10:15:00+02:00", + "2023-06-19T10:20:00+02:00", + "2023-06-19T10:25:00+02:00", + "2023-06-19T10:30:00+02:00", + "2023-06-19T10:35:00+02:00", + "2023-06-19T10:40:00+02:00", + "2023-06-19T10:45:00+02:00", + "2023-06-19T10:50:00+02:00", + "2023-06-19T10:55:00+02:00", + "2023-06-19T11:00:00+02:00", + "2023-06-19T11:05:00+02:00", + "2023-06-19T11:10:00+02:00", + "2023-06-19T11:15:00+02:00", + "2023-06-19T11:20:00+02:00", + "2023-06-19T11:25:00+02:00", + "2023-06-19T11:30:00+02:00", + "2023-06-19T11:35:00+02:00", + "2023-06-19T11:40:00+02:00", + "2023-06-19T11:45:00+02:00", + "2023-06-19T11:50:00+02:00", + "2023-06-19T11:55:00+02:00", + "2023-06-19T12:00:00+02:00", + "2023-06-19T12:05:00+02:00", + "2023-06-19T12:10:00+02:00", + "2023-06-19T12:15:00+02:00", + "2023-06-19T12:20:00+02:00", + "2023-06-19T12:25:00+02:00", + "2023-06-19T12:30:00+02:00", + "2023-06-19T12:35:00+02:00", + "2023-06-19T12:40:00+02:00", + "2023-06-19T12:45:00+02:00", + "2023-06-19T12:50:00+02:00", + "2023-06-19T12:55:00+02:00", + "2023-06-19T13:00:00+02:00", + "2023-06-19T13:05:00+02:00", + "2023-06-19T13:10:00+02:00", + "2023-06-19T13:15:00+02:00", + "2023-06-19T13:20:00+02:00", + "2023-06-19T13:25:00+02:00", + "2023-06-19T13:30:00+02:00", + "2023-06-19T13:35:00+02:00", + "2023-06-19T13:40:00+02:00", + "2023-06-19T13:45:00+02:00", + "2023-06-19T13:50:00+02:00", + "2023-06-19T13:55:00+02:00", + "2023-06-19T14:00:00+02:00", + "2023-06-19T14:05:00+02:00", + "2023-06-19T14:10:00+02:00", + "2023-06-19T14:15:00+02:00", + "2023-06-19T14:20:00+02:00", + "2023-06-19T14:25:00+02:00", + "2023-06-19T14:30:00+02:00", + "2023-06-19T14:35:00+02:00", + "2023-06-19T14:40:00+02:00", + "2023-06-19T14:45:00+02:00", + "2023-06-19T14:50:00+02:00", + "2023-06-19T14:55:00+02:00", + "2023-06-19T15:00:00+02:00", + "2023-06-19T15:05:00+02:00", + "2023-06-19T15:10:00+02:00", + "2023-06-19T15:15:00+02:00", + "2023-06-19T15:20:00+02:00", + "2023-06-19T15:25:00+02:00", + "2023-06-19T15:30:00+02:00", + "2023-06-19T15:35:00+02:00", + "2023-06-19T15:40:00+02:00", + "2023-06-19T15:45:00+02:00", + "2023-06-19T15:50:00+02:00", + "2023-06-19T15:55:00+02:00", + "2023-06-19T16:00:00+02:00", + "2023-06-19T16:05:00+02:00", + "2023-06-19T16:10:00+02:00", + "2023-06-19T16:15:00+02:00", + "2023-06-19T16:20:00+02:00", + "2023-06-19T16:25:00+02:00", + "2023-06-19T16:30:00+02:00", + "2023-06-19T16:35:00+02:00", + "2023-06-19T16:40:00+02:00", + "2023-06-19T16:45:00+02:00", + "2023-06-19T16:50:00+02:00", + "2023-06-19T16:55:00+02:00", + "2023-06-19T17:00:00+02:00", + "2023-06-19T17:05:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayWithNullValues.json b/centreon/packages/ui/src/Graph/mockedData/lastDayWithNullValues.json similarity index 98% rename from centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayWithNullValues.json rename to centreon/packages/ui/src/Graph/mockedData/lastDayWithNullValues.json index 65ca51aa7f..c26514fc17 100644 --- a/centreon/packages/ui/src/Graph/LineChart/mockedData/lastDayWithNullValues.json +++ b/centreon/packages/ui/src/Graph/mockedData/lastDayWithNullValues.json @@ -329,20 +329,7 @@ 0.32339333333, null ], - "prints": [ - [ - "Last:0.32" - ], - [ - "Min:0.03" - ], - [ - "Max:0.97" - ], - [ - "Average:0.51" - ] - ], + "prints": [["Last:0.32"], ["Min:0.03"], ["Max:0.97"], ["Average:0.51"]], "last_value": 0.32, "minimum_value": 0.03, "maximum_value": 0.97, @@ -667,18 +654,10 @@ null ], "prints": [ - [ - "Last:87.27" - ], - [ - "Min:70.31" - ], - [ - "Max:88.03" - ], - [ - "Average:78.07" - ] + ["Last:87.27"], + ["Min:70.31"], + ["Max:88.03"], + ["Average:78.07"] ], "last_value": 87.27, "minimum_value": 70.31, @@ -1003,20 +982,7 @@ 0.64624666667, null ], - "prints": [ - [ - "Last:0.65" - ], - [ - "Min:0.03" - ], - [ - "Max:0.98" - ], - [ - "Average:0.50" - ] - ], + "prints": [["Last:0.65"], ["Min:0.03"], ["Max:0.98"], ["Average:0.50"]], "last_value": 0.65, "minimum_value": 0.03, "maximum_value": 0.98, @@ -1311,4 +1277,4 @@ "2023-06-19T17:00:00+02:00", "2023-06-19T17:05:00+02:00" ] -} \ No newline at end of file +} diff --git a/centreon/packages/ui/src/Graph/mockedData/lastMonth.json b/centreon/packages/ui/src/Graph/mockedData/lastMonth.json new file mode 100644 index 0000000000..02490790f0 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/lastMonth.json @@ -0,0 +1,1641 @@ +{ + "global": { + "title": "oracle-shared-spool-ratio graph on srv-oracle-crm", + "start": "2023-04-22T16:01:06+02:00", + "end": "2023-05-23T16:01:06+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 0, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 5320, + "metric_id": 12879, + "metric": "connTime", + "metric_legend": "connTime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#990033" + }, + "legend": "connTime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.50033458333, + 0.61945916667, + 0.51819333333, + 0.60382916667, + 0.49840361111, + 0.49933972222, + 0.55467208333, + 0.56382444444, + 0.62704972222, + 0.54424180556, + 0.50082777778, + 0.45984555556, + 0.49584861111, + 0.35677083333, + 0.47271861111, + 0.52795972222, + 0.45791944444, + 0.43084166667, + 0.502125, + 0.38325833333, + 0.594375, + 0.594125, + 0.45928333333, + 0.5255, + 0.41265, + 0.40810833333, + 0.5416, + 0.48815, + 0.42519166667, + 0.58961666667, + 0.41775833333, + 0.43450833333, + 0.4493, + 0.39341666667, + 0.49969166667, + 0.50023333333, + 0.46121305556, + 0.5069475, + 0.50755055556, + 0.44471013889, + 0.47222291667, + 0.45869027778, + 0.41597888889, + 0.59415055556, + 0.52623305556, + 0.54249277778, + 0.58356333333, + 0.46177041667, + 0.49658555556, + 0.60377222222, + 0.56200958333, + 0.63443444444, + 0.52070555556, + 0.6246475, + 0.52999069444, + 0.42607777778, + 0.55257444444, + 0.45891888889, + 0.51791611111, + 0.423755, + 0.45616666667, + 0.54159055556, + 0.46024222222, + 0.41285333333, + 0.48092277778, + 0.46342777778, + 0.57123, + 0.56956111111, + 0.58442833333, + 0.52641388889, + 0.46058166667, + 0.40469458333, + 0.54256736111, + 0.56656111111, + 0.54332777778, + 0.49598680556, + 0.59200763889, + 0.44712708333, + 0.55852083333, + 0.58329166667, + 0.53323611111, + 0.57300416667, + 0.52716597222, + 0.40442291667, + 0.42211111111, + 0.63572708333, + 0.55759166667, + 0.46749166667, + 0.37702361111, + 0.56483055556, + 0.47474236111, + 0.43567847222, + 0.50577638889, + 0.44973305556, + 0.52211083333, + 0.44430083333, + 0.48803333333, + 0.42062833333, + 0.5597925, + 0.50754166667, + 0.4506775, + 0.38088333333, + 0.53365583333, + 0.43125333333, + 0.44724166667, + 0.44108833333, + 0.49138916667, + 0.610585, + 0.578545, + 0.49276666667, + 0.51599833333, + 0.55685166667, + 0.50467416667, + 0.51643916667, + 0.50236833333, + 0.60251916667, + 0.38275916667, + 0.4105925, + 0.48575833333, + 0.43170166667, + 0.63278916667, + 0.416565, + 0.46697902778, + 0.4740475, + 0.44771, + 0.59884472222, + 0.4627625, + 0.4531975, + 0.60965916667, + 0.63874180556, + 0.51233305556, + 0.55861527778, + 0.50454416667, + 0.43259527778, + 0.51321444444, + 0.48314888889, + 0.59840555556, + 0.55625777778, + 0.46488611111, + 0.45740694444, + 0.51038611111, + 0.61267083333, + 0.51206944444, + 0.56741666667, + 0.58174305556, + 0.38422222222, + 0.55132083333, + 0.54504722222, + 0.48465, + 0.47887083333, + 0.46282638889, + 0.48750277778, + 0.53763055556, + 0.53980833333, + 0.42661527778, + 0.4728375, + 0.46515694444, + 0.50543333333, + 0.58466666667, + 0.4641875, + 0.42224305556, + 0.45730555556, + 0.53627777778, + 0.49995833333, + 0.53940972222, + 0.41956944444, + 0.45699305556, + 0.52835416667, + 0.50822222222, + 0.44841666667, + 0.43936111111, + 0.54340277778, + 0.46944444444, + 0.57169444444, + 0.52923611111, + 0.56581944444, + 0.56853472222, + 0.59384027778, + 0.46910555556, + 0.43805694444, + 0.58207083333, + 0.55213888889, + 0.44952777778, + 0.47930555556, + 0.44179861111, + 0.41134027778, + 0.42866666667, + 0.511375, + 0.50978472222, + 0.477875, + 0.53188194444, + 0.44010416667, + 0.48233333333, + 0.55613347222, + 0.47067416667, + 0.54952611111, + 0.52073277778, + 0.50571736111, + 0.61287555556, + 0.48102388889, + 0.49271569444, + 0.44343125, + 0.53625333333, + 0.563685, + 0.466765, + 0.49876166667, + 0.47815333333, + 0.49052666667, + 0.40544, + 0.558505, + 0.504925, + 0.56809666667, + 0.51643166667, + 0.500375, + 0.46229833333, + 0.41243, + 0.39154166667, + 0.46627166667, + 0.55276111111, + 0.39044694444, + 0.56729583333, + 0.56158388889, + 0.41965333333, + 0.52013361111, + 0.39681166667, + 0.50957805556, + 0.51941666667, + 0.55553763889, + 0.46638333333, + 0.44483722222, + 0.57280722222, + 0.68180791667, + 0.48812944444, + 0.59093375, + 0.54439763889, + 0.48189972222, + 0.49061152778, + 0.59989930556, + 0.58490055556, + 0.61258930556, + 0.60397902778, + 0.52981402778, + 0.50435, + 0.41884722222, + 0.45518055556, + 0.46851111111, + 0.61096944444, + 0.49326944444, + 0.419725, + 0.46484722222, + 0.48892222222, + 0.42955, + 0.53626388889, + 0.56575833333, + 0.50948888889, + 0.46735555556, + 0.51255555556, + 0.50625555556, + 0.49493333333, + 0.45309444444, + 0.44096111111, + 0.52035277778, + 0.41961388889, + 0.4463, + 0.48494444444, + 0.55550277778, + 0.51151111111, + 0.53519444444, + 0.39882902778, + 0.47607, + 0.47141388889, + 0.54625083333, + 0.49487166667, + 0.56357083333, + 0.54315833333, + 0.55606277778, + 0.46999027778, + 0.60634083333, + 0.45837861111, + 0.46508805556, + 0.46517861111, + 0.50517722222, + 0.49639833333, + 0.45971111111, + 0.53749027778, + 0.42077611111, + 0.36337027778, + 0.57174166667, + 0.51783333333, + 0.46205166667, + 0.54008333333, + 0.46243833333, + 0.49854333333, + 0.52208666667, + 0.45309833333, + 0.54164166667, + 0.50293666667, + 0.58052444444, + 0.48480416667, + 0.44963611111, + 0.57046319444, + 0.49653611111, + 0.55977222222, + 0.46650694444, + 0.57683680556, + 0.37171111111, + 0.46325, + 0.48231680556, + 0.48979055556, + 0.51859361111, + 0.50016222222, + 0.45968583333, + 0.51421583333, + 0.56765638889, + 0.57335111111, + 0.41111875, + 0.50796958333, + 0.395305, + 0.48056722222, + 0.49464361111, + 0.46999875, + 0.44863527778, + 0.44513208333, + 0.52571097222, + 0.59808069444, + 0.51411833333, + 0.61205444444, + 0.52014583333, + 0.44387916667, + 0.47595416667, + 0.4776, + 0.54218333333, + 0.42116666667, + 0.41662916667, + 0.47499583333, + 0.55535416667, + 0.44424583333, + 0.4812375, + 0.54995, + 0.4826875, + 0.46228333333, + 0.42069166667, + 0.50894583333, + 0.52455305556, + 0.43574513889, + 0.47146680556, + 0.52494444444, + 0.61506833333, + 0.34888958333, + 0.53983305556, + 0.51920916667, + 0.46683319444, + 0.58013, + 0.39148333333, + 0.52852666667, + 0.49618611111, + 0.42079, + 0.44302666667, + 0.61560833333, + 0.40733777778, + 0.55178333333, + 0.5079175, + 0.47183541667, + 0.517075, + 0.38027541667, + 0.51537569444, + 0.40031805556, + 0.51048138889, + 0.59283166667, + 0.49227166667, + 0.48328611111, + 0.52946541667, + null + ], + "prints": [["Last:0.53"], ["Min:0.35"], ["Max:0.68"], ["Average:0.50"]], + "last_value": 0.53, + "minimum_value": 0.35, + "maximum_value": 0.68, + "average_value": 0.5 + }, + { + "index_id": 5320, + "metric_id": 12878, + "metric": "querytime", + "metric_legend": "querytime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#ff3333" + }, + "legend": "querytime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.4820075, + 0.54786666667, + 0.537675, + 0.44466583333, + 0.56231069444, + 0.51092194444, + 0.50375861111, + 0.51052875, + 0.50798208333, + 0.44864861111, + 0.4147725, + 0.50207305556, + 0.49094888889, + 0.50487722222, + 0.51480555556, + 0.60383333333, + 0.57061194444, + 0.56269166667, + 0.50226666667, + 0.36955, + 0.48694166667, + 0.5011, + 0.50590833333, + 0.39789166667, + 0.43364166667, + 0.46898333333, + 0.5747, + 0.43391666667, + 0.58044166667, + 0.55174166667, + 0.462675, + 0.52405833333, + 0.46514166667, + 0.57273333333, + 0.52735833333, + 0.5592, + 0.51948305556, + 0.50549694444, + 0.50488861111, + 0.36735625, + 0.53613972222, + 0.50677708333, + 0.44981055556, + 0.43704833333, + 0.45431930556, + 0.56507055556, + 0.41380861111, + 0.55419958333, + 0.45757708333, + 0.45671305556, + 0.4972675, + 0.38788166667, + 0.53776583333, + 0.52779277778, + 0.53221736111, + 0.47106277778, + 0.56903944444, + 0.4783, + 0.48126111111, + 0.54720222222, + 0.474135, + 0.45746888889, + 0.51297277778, + 0.606045, + 0.41071444444, + 0.41101222222, + 0.552105, + 0.45999388889, + 0.51995777778, + 0.56436611111, + 0.50154, + 0.47195055556, + 0.43405972222, + 0.5065, + 0.51008125, + 0.52819375, + 0.48212777778, + 0.49300902778, + 0.57922916667, + 0.46563888889, + 0.4014375, + 0.49352152778, + 0.46820347222, + 0.3917, + 0.50307152778, + 0.43910972222, + 0.57312708333, + 0.56125138889, + 0.50412708333, + 0.53868194444, + 0.51587361111, + 0.60080208333, + 0.47862986111, + 0.48106152778, + 0.38717166667, + 0.526345, + 0.40869833333, + 0.4253675, + 0.5569475, + 0.46934416667, + 0.50617083333, + 0.44834, + 0.51131333333, + 0.55684916667, + 0.51484166667, + 0.56658, + 0.41325583333, + 0.54179416667, + 0.57034416667, + 0.47756916667, + 0.62718666667, + 0.5509725, + 0.5502525, + 0.47039333333, + 0.42288916667, + 0.53411083333, + 0.5683725, + 0.602335, + 0.47520916667, + 0.50628583333, + 0.521265, + 0.52259861111, + 0.48722541667, + 0.53608763889, + 0.59789305556, + 0.44855902778, + 0.53649930556, + 0.54616166667, + 0.58590708333, + 0.45782208333, + 0.4642825, + 0.49553166667, + 0.67386, + 0.50180402778, + 0.47037763889, + 0.46473833333, + 0.41795972222, + 0.47257958333, + 0.53391527778, + 0.57262361111, + 0.48405138889, + 0.4508, + 0.54903055556, + 0.42190694444, + 0.43467777778, + 0.53279027778, + 0.58740972222, + 0.56928333333, + 0.63375833333, + 0.5663125, + 0.46767638889, + 0.57531388889, + 0.45455277778, + 0.39892222222, + 0.5952875, + 0.44328333333, + 0.49716944444, + 0.49061111111, + 0.55089583333, + 0.542875, + 0.44646527778, + 0.47390277778, + 0.495, + 0.55122222222, + 0.54713888889, + 0.47925694444, + 0.645625, + 0.58602083333, + 0.54818055556, + 0.58030555556, + 0.5108125, + 0.48620138889, + 0.44344444444, + 0.62082638889, + 0.53688888889, + 0.4769375, + 0.45626388889, + 0.43636111111, + 0.48725416667, + 0.56865277778, + 0.47129722222, + 0.50325, + 0.48446527778, + 0.55102083333, + 0.58122916667, + 0.45869444444, + 0.55117361111, + 0.38622916667, + 0.49203472222, + 0.39611111111, + 0.52322222222, + 0.50911111111, + 0.545875, + 0.49933166667, + 0.51926611111, + 0.49907486111, + 0.50863486111, + 0.53831486111, + 0.53933319444, + 0.57828930556, + 0.47896819444, + 0.40125291667, + 0.504445, + 0.53565, + 0.28999666667, + 0.48051666667, + 0.44803833333, + 0.42531, + 0.54171166667, + 0.484515, + 0.46153833333, + 0.47544666667, + 0.43798, + 0.401075, + 0.407455, + 0.41547666667, + 0.54620333333, + 0.45932666667, + 0.45051930556, + 0.57091819444, + 0.46523319444, + 0.43658833333, + 0.48776138889, + 0.53602388889, + 0.51612527778, + 0.51619833333, + 0.49428416667, + 0.43790222222, + 0.44653958333, + 0.43712486111, + 0.40300513889, + 0.56234097222, + 0.474555, + 0.44655097222, + 0.54056597222, + 0.45041430556, + 0.52533972222, + 0.52445375, + 0.63305347222, + 0.48278055556, + 0.52841361111, + 0.53922430556, + 0.56528333333, + 0.44198055556, + 0.49815555556, + 0.44740277778, + 0.53225, + 0.47143611111, + 0.50535, + 0.50532222222, + 0.38877222222, + 0.45349166667, + 0.4699, + 0.527325, + 0.48013055556, + 0.45149444444, + 0.51115555556, + 0.47300555556, + 0.40672222222, + 0.54794722222, + 0.57065555556, + 0.43134444444, + 0.54095555556, + 0.46501388889, + 0.53646111111, + 0.52628611111, + 0.55696944444, + 0.33851666667, + 0.56513861111, + 0.39431041667, + 0.48249513889, + 0.53899666667, + 0.54166638889, + 0.50782888889, + 0.52590805556, + 0.45245333333, + 0.45541916667, + 0.47155583333, + 0.51281972222, + 0.44810166667, + 0.50835138889, + 0.58544388889, + 0.52371805556, + 0.44599805556, + 0.43898777778, + 0.47267722222, + 0.52452208333, + 0.61510333333, + 0.50854166667, + 0.46054833333, + 0.56622, + 0.42615, + 0.53491666667, + 0.52652833333, + 0.527335, + 0.67556333333, + 0.45109166667, + 0.59083541667, + 0.45191319444, + 0.54146805556, + 0.48338333333, + 0.53249097222, + 0.44949444444, + 0.51941736111, + 0.58977708333, + 0.50848402778, + 0.40556944444, + 0.42585305556, + 0.5207375, + 0.4586325, + 0.40217944444, + 0.56245944444, + 0.55036388889, + 0.472395, + 0.40083444444, + 0.46645652778, + 0.47231375, + 0.61049125, + 0.43026055556, + 0.49318791667, + 0.49176569444, + 0.50923013889, + 0.65010805556, + 0.60687861111, + 0.48488833333, + 0.54808833333, + 0.57673444444, + 0.52415, + 0.3968375, + 0.4255625, + 0.49525, + 0.635625, + 0.54183333333, + 0.47456666667, + 0.35498333333, + 0.53386666667, + 0.51248333333, + 0.557225, + 0.51565833333, + 0.46278333333, + 0.5115125, + 0.53826666667, + 0.54737347222, + 0.50048930556, + 0.55215569444, + 0.52576833333, + 0.45016569444, + 0.36885777778, + 0.45052347222, + 0.45691166667, + 0.47295736111, + 0.48539277778, + 0.53254333333, + 0.62901055556, + 0.524615, + 0.49281166667, + 0.48531888889, + 0.52359944444, + 0.52044388889, + 0.482585, + 0.45909666667, + 0.56092263889, + 0.51403375, + 0.56277125, + 0.53915708333, + 0.49189180556, + 0.54154763889, + 0.50087736111, + 0.44601666667, + 0.48657333333, + 0.52078888889, + 0.47333972222, + null + ], + "prints": [["Last:0.47"], ["Min:0.29"], ["Max:0.68"], ["Average:0.50"]], + "last_value": 0.47, + "minimum_value": 0.29, + "maximum_value": 0.68, + "average_value": 0.5 + }, + { + "index_id": 5320, + "metric_id": 12877, + "metric": "used", + "metric_legend": "used", + "unit": "%", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 8, + "host_id": null, + "service_id": null, + "name": "Used", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": "used", + "ds_color_line": "#2B28D7", + "ds_color_line_mode": "0", + "ds_color_area": "#050AF9", + "ds_color_area_warn": null, + "ds_color_area_crit": null, + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "used", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 1, + "data": [ + 93.53473625, + 95.4705575, + 90.78131625, + 88.229732917, + 91.46288, + 96.404586389, + 90.425950694, + 92.482070417, + 95.38929375, + 98.065868472, + 91.3271225, + 92.991402361, + 96.059254028, + 95.253403889, + 92.0200325, + 86.169484583, + 91.723414306, + 95.545441667, + 91.213633333, + 96.978266667, + 92.047108333, + 94.362, + 97.349091667, + 91.6958, + 90.930558333, + 92.126758333, + 92.515791667, + 90.98285, + 94.291941667, + 94.6313, + 93.0995, + 96.032566667, + 97.73195, + 97.437383333, + 97.234416667, + 97.020591667, + 92.502736528, + 92.181365972, + 91.755329306, + 89.611361389, + 81.009381389, + 82.697088333, + 82.949993889, + 92.676847917, + 92.367398889, + 90.054948889, + 88.724102778, + 95.362512083, + 98.273312639, + 94.797704722, + 91.9214025, + 93.706965556, + 95.219553889, + 98.321218333, + 97.808040972, + 97.677885, + 96.704646111, + 93.720406667, + 92.002689444, + 89.145115, + 96.180838889, + 98.572950556, + 91.615067778, + 92.582652222, + 96.859334444, + 90.42448, + 91.813913889, + 92.037367778, + 91.581648889, + 79.763948889, + 73.738103333, + 72.813350972, + 74.061651389, + 78.564606944, + 73.625989583, + 74.61276875, + 75.664770833, + 84.789911111, + 91.562385417, + 92.0473125, + 90.717729167, + 84.731822917, + 84.325086111, + 84.78401875, + 86.0260625, + 87.469259028, + 88.298977778, + 86.075078472, + 86.349101389, + 88.635159028, + 89.006238889, + 91.320934722, + 88.318921528, + 77.251426528, + 73.456744167, + 81.2534625, + 84.409346667, + 85.268703333, + 86.337475833, + 83.730001667, + 79.989916667, + 86.847673333, + 93.467304167, + 95.524714167, + 94.551674167, + 87.080203333, + 80.839834167, + 79.757945, + 81.624870833, + 88.540388333, + 96.682811667, + 96.2668275, + 95.1485025, + 90.362938333, + 88.677029167, + 89.1434075, + 88.386136667, + 94.904750833, + 97.1479475, + 90.782644167, + 88.3413525, + 89.247638056, + 92.222419444, + 82.727468889, + 81.888297083, + 85.957462222, + 89.885201806, + 97.087708472, + 93.182506389, + 84.728676111, + 83.442598056, + 81.057695972, + 73.105455972, + 77.261483333, + 86.681160278, + 90.515781111, + 83.858407917, + 84.912508194, + 89.196070833, + 89.980515278, + 88.662130556, + 90.962719444, + 90.9171, + 97.05835, + 97.970702778, + 94.598463889, + 97.041998611, + 97.571281944, + 90.000070833, + 84.775991667, + 77.098211111, + 73.768095833, + 87.708554167, + 95.292305556, + 92.661397222, + 91.698375, + 94.734926389, + 85.569593056, + 78.765402778, + 73.1415625, + 75.643798611, + 79.100340278, + 80.757395833, + 75.441020833, + 74.254395833, + 75.555159722, + 73.148548611, + 74.245520833, + 80.435673611, + 78.429381944, + 73.619902778, + 73.574881944, + 74.838986111, + 76.178506944, + 73.361840278, + 73.252270833, + 74.580708333, + 77.323736111, + 89.248868056, + 95.394506944, + 83.555773611, + 73.377284722, + 72.989409722, + 72.345833333, + 77.278854167, + 77.246506944, + 75.3070625, + 74.816506944, + 73.262715278, + 78.040527778, + 75.361666667, + 79.701270833, + 80.888388889, + 77.274089722, + 78.965599028, + 76.581835833, + 81.1598125, + 82.532069722, + 81.2063575, + 79.699761389, + 84.279743333, + 82.0001075, + 77.98224, + 80.77859, + 77.558431667, + 75.035186667, + 79.77859, + 76.498343333, + 75.270236667, + 74.502018333, + 76.987243333, + 77.314198333, + 73.739925, + 76.768341667, + 80.002403333, + 79.50922, + 79.793135, + 83.32031, + 90.690696528, + 91.855036111, + 95.152990556, + 90.662471667, + 87.878877778, + 86.474365833, + 93.031389722, + 91.1510425, + 89.524025, + 87.79133125, + 83.196835417, + 86.905329028, + 84.796714861, + 86.477819306, + 90.215054722, + 90.689078611, + 90.069447917, + 94.064490972, + 92.910771806, + 90.168341389, + 86.005012778, + 82.007541389, + 82.4444, + 84.725972361, + 81.079969444, + 82.071788889, + 74.344436111, + 73.304477778, + 73.895147222, + 76.732205556, + 81.682944444, + 86.026041667, + 87.382563889, + 88.904291667, + 87.770433333, + 80.927844444, + 77.038666667, + 81.157086111, + 82.575377778, + 91.568616667, + 96.412636111, + 96.376172222, + 91.875827778, + 95.524025, + 97.76045, + 96.818305556, + 92.319038889, + 89.773883333, + 80.555247222, + 85.832455556, + 77.946490833, + 82.205994583, + 88.74038125, + 83.006198333, + 78.297281111, + 74.590896667, + 75.900935833, + 74.595134722, + 78.369969722, + 81.004014167, + 85.035468056, + 81.22037, + 84.639056944, + 84.586663333, + 78.015843889, + 80.189820833, + 76.739529722, + 78.387696111, + 78.584917361, + 84.938538333, + 90.97361, + 90.789226667, + 90.425228333, + 91.381495, + 96.852533333, + 91.220391667, + 97.581593333, + 97.245176667, + 95.096153333, + 95.391049444, + 93.119884028, + 81.892788889, + 77.476779861, + 80.188209028, + 80.098774306, + 86.978205556, + 94.64235625, + 97.311053472, + 97.048621528, + 90.545117639, + 88.905369444, + 93.880626944, + 93.685805556, + 96.881301944, + 96.753013056, + 97.337800278, + 95.696868611, + 97.011245139, + 96.984615833, + 87.825530556, + 90.718932639, + 92.912039028, + 86.380014028, + 84.796867639, + 92.66191625, + 91.698228056, + 90.882975, + 96.128683194, + 98.014940139, + 96.4936875, + 93.528679167, + 97.463633333, + 95.379266667, + 90.4649625, + 89.087520833, + 86.6875375, + 77.421904167, + 74.396995833, + 73.215158333, + 76.235308333, + 76.3625, + 80.6953625, + 82.4897875, + 86.9769875, + 92.331467222, + 94.825957917, + 89.40248875, + 89.796999167, + 91.073693194, + 92.296046667, + 97.467716528, + 90.982410139, + 92.016604583, + 91.068401389, + 86.059646667, + 81.936524444, + 81.474296111, + 75.121141667, + 76.126827778, + 78.021423333, + 79.388627778, + 72.908920556, + 76.873109444, + 88.14395875, + 92.47338, + 90.283409167, + 87.865566667, + 84.918092222, + 78.515823889, + 73.144546111, + 77.194361667, + 74.75668, + 83.207912778, + 81.414109306, + null + ], + "prints": [["Last:81.41"], ["Average:86.52"]], + "last_value": 81.41, + "minimum_value": null, + "maximum_value": null, + "average_value": 86.52 + } + ], + "times": [ + "2023-04-22T18:00:00+02:00", + "2023-04-22T20:00:00+02:00", + "2023-04-22T22:00:00+02:00", + "2023-04-23T00:00:00+02:00", + "2023-04-23T02:00:00+02:00", + "2023-04-23T04:00:00+02:00", + "2023-04-23T06:00:00+02:00", + "2023-04-23T08:00:00+02:00", + "2023-04-23T10:00:00+02:00", + "2023-04-23T12:00:00+02:00", + "2023-04-23T14:00:00+02:00", + "2023-04-23T16:00:00+02:00", + "2023-04-23T18:00:00+02:00", + "2023-04-23T20:00:00+02:00", + "2023-04-23T22:00:00+02:00", + "2023-04-24T00:00:00+02:00", + "2023-04-24T02:00:00+02:00", + "2023-04-24T04:00:00+02:00", + "2023-04-24T06:00:00+02:00", + "2023-04-24T08:00:00+02:00", + "2023-04-24T10:00:00+02:00", + "2023-04-24T12:00:00+02:00", + "2023-04-24T14:00:00+02:00", + "2023-04-24T16:00:00+02:00", + "2023-04-24T18:00:00+02:00", + "2023-04-24T20:00:00+02:00", + "2023-04-24T22:00:00+02:00", + "2023-04-25T00:00:00+02:00", + "2023-04-25T02:00:00+02:00", + "2023-04-25T04:00:00+02:00", + "2023-04-25T06:00:00+02:00", + "2023-04-25T08:00:00+02:00", + "2023-04-25T10:00:00+02:00", + "2023-04-25T12:00:00+02:00", + "2023-04-25T14:00:00+02:00", + "2023-04-25T16:00:00+02:00", + "2023-04-25T18:00:00+02:00", + "2023-04-25T20:00:00+02:00", + "2023-04-25T22:00:00+02:00", + "2023-04-26T00:00:00+02:00", + "2023-04-26T02:00:00+02:00", + "2023-04-26T04:00:00+02:00", + "2023-04-26T06:00:00+02:00", + "2023-04-26T08:00:00+02:00", + "2023-04-26T10:00:00+02:00", + "2023-04-26T12:00:00+02:00", + "2023-04-26T14:00:00+02:00", + "2023-04-26T16:00:00+02:00", + "2023-04-26T18:00:00+02:00", + "2023-04-26T20:00:00+02:00", + "2023-04-26T22:00:00+02:00", + "2023-04-27T00:00:00+02:00", + "2023-04-27T02:00:00+02:00", + "2023-04-27T04:00:00+02:00", + "2023-04-27T06:00:00+02:00", + "2023-04-27T08:00:00+02:00", + "2023-04-27T10:00:00+02:00", + "2023-04-27T12:00:00+02:00", + "2023-04-27T14:00:00+02:00", + "2023-04-27T16:00:00+02:00", + "2023-04-27T18:00:00+02:00", + "2023-04-27T20:00:00+02:00", + "2023-04-27T22:00:00+02:00", + "2023-04-28T00:00:00+02:00", + "2023-04-28T02:00:00+02:00", + "2023-04-28T04:00:00+02:00", + "2023-04-28T06:00:00+02:00", + "2023-04-28T08:00:00+02:00", + "2023-04-28T10:00:00+02:00", + "2023-04-28T12:00:00+02:00", + "2023-04-28T14:00:00+02:00", + "2023-04-28T16:00:00+02:00", + "2023-04-28T18:00:00+02:00", + "2023-04-28T20:00:00+02:00", + "2023-04-28T22:00:00+02:00", + "2023-04-29T00:00:00+02:00", + "2023-04-29T02:00:00+02:00", + "2023-04-29T04:00:00+02:00", + "2023-04-29T06:00:00+02:00", + "2023-04-29T08:00:00+02:00", + "2023-04-29T10:00:00+02:00", + "2023-04-29T12:00:00+02:00", + "2023-04-29T14:00:00+02:00", + "2023-04-29T16:00:00+02:00", + "2023-04-29T18:00:00+02:00", + "2023-04-29T20:00:00+02:00", + "2023-04-29T22:00:00+02:00", + "2023-04-30T00:00:00+02:00", + "2023-04-30T02:00:00+02:00", + "2023-04-30T04:00:00+02:00", + "2023-04-30T06:00:00+02:00", + "2023-04-30T08:00:00+02:00", + "2023-04-30T10:00:00+02:00", + "2023-04-30T12:00:00+02:00", + "2023-04-30T14:00:00+02:00", + "2023-04-30T16:00:00+02:00", + "2023-04-30T18:00:00+02:00", + "2023-04-30T20:00:00+02:00", + "2023-04-30T22:00:00+02:00", + "2023-05-01T00:00:00+02:00", + "2023-05-01T02:00:00+02:00", + "2023-05-01T04:00:00+02:00", + "2023-05-01T06:00:00+02:00", + "2023-05-01T08:00:00+02:00", + "2023-05-01T10:00:00+02:00", + "2023-05-01T12:00:00+02:00", + "2023-05-01T14:00:00+02:00", + "2023-05-01T16:00:00+02:00", + "2023-05-01T18:00:00+02:00", + "2023-05-01T20:00:00+02:00", + "2023-05-01T22:00:00+02:00", + "2023-05-02T00:00:00+02:00", + "2023-05-02T02:00:00+02:00", + "2023-05-02T04:00:00+02:00", + "2023-05-02T06:00:00+02:00", + "2023-05-02T08:00:00+02:00", + "2023-05-02T10:00:00+02:00", + "2023-05-02T12:00:00+02:00", + "2023-05-02T14:00:00+02:00", + "2023-05-02T16:00:00+02:00", + "2023-05-02T18:00:00+02:00", + "2023-05-02T20:00:00+02:00", + "2023-05-02T22:00:00+02:00", + "2023-05-03T00:00:00+02:00", + "2023-05-03T02:00:00+02:00", + "2023-05-03T04:00:00+02:00", + "2023-05-03T06:00:00+02:00", + "2023-05-03T08:00:00+02:00", + "2023-05-03T10:00:00+02:00", + "2023-05-03T12:00:00+02:00", + "2023-05-03T14:00:00+02:00", + "2023-05-03T16:00:00+02:00", + "2023-05-03T18:00:00+02:00", + "2023-05-03T20:00:00+02:00", + "2023-05-03T22:00:00+02:00", + "2023-05-04T00:00:00+02:00", + "2023-05-04T02:00:00+02:00", + "2023-05-04T04:00:00+02:00", + "2023-05-04T06:00:00+02:00", + "2023-05-04T08:00:00+02:00", + "2023-05-04T10:00:00+02:00", + "2023-05-04T12:00:00+02:00", + "2023-05-04T14:00:00+02:00", + "2023-05-04T16:00:00+02:00", + "2023-05-04T18:00:00+02:00", + "2023-05-04T20:00:00+02:00", + "2023-05-04T22:00:00+02:00", + "2023-05-05T00:00:00+02:00", + "2023-05-05T02:00:00+02:00", + "2023-05-05T04:00:00+02:00", + "2023-05-05T06:00:00+02:00", + "2023-05-05T08:00:00+02:00", + "2023-05-05T10:00:00+02:00", + "2023-05-05T12:00:00+02:00", + "2023-05-05T14:00:00+02:00", + "2023-05-05T16:00:00+02:00", + "2023-05-05T18:00:00+02:00", + "2023-05-05T20:00:00+02:00", + "2023-05-05T22:00:00+02:00", + "2023-05-06T00:00:00+02:00", + "2023-05-06T02:00:00+02:00", + "2023-05-06T04:00:00+02:00", + "2023-05-06T06:00:00+02:00", + "2023-05-06T08:00:00+02:00", + "2023-05-06T10:00:00+02:00", + "2023-05-06T12:00:00+02:00", + "2023-05-06T14:00:00+02:00", + "2023-05-06T16:00:00+02:00", + "2023-05-06T18:00:00+02:00", + "2023-05-06T20:00:00+02:00", + "2023-05-06T22:00:00+02:00", + "2023-05-07T00:00:00+02:00", + "2023-05-07T02:00:00+02:00", + "2023-05-07T04:00:00+02:00", + "2023-05-07T06:00:00+02:00", + "2023-05-07T08:00:00+02:00", + "2023-05-07T10:00:00+02:00", + "2023-05-07T12:00:00+02:00", + "2023-05-07T14:00:00+02:00", + "2023-05-07T16:00:00+02:00", + "2023-05-07T18:00:00+02:00", + "2023-05-07T20:00:00+02:00", + "2023-05-07T22:00:00+02:00", + "2023-05-08T00:00:00+02:00", + "2023-05-08T02:00:00+02:00", + "2023-05-08T04:00:00+02:00", + "2023-05-08T06:00:00+02:00", + "2023-05-08T08:00:00+02:00", + "2023-05-08T10:00:00+02:00", + "2023-05-08T12:00:00+02:00", + "2023-05-08T14:00:00+02:00", + "2023-05-08T16:00:00+02:00", + "2023-05-08T18:00:00+02:00", + "2023-05-08T20:00:00+02:00", + "2023-05-08T22:00:00+02:00", + "2023-05-09T00:00:00+02:00", + "2023-05-09T02:00:00+02:00", + "2023-05-09T04:00:00+02:00", + "2023-05-09T06:00:00+02:00", + "2023-05-09T08:00:00+02:00", + "2023-05-09T10:00:00+02:00", + "2023-05-09T12:00:00+02:00", + "2023-05-09T14:00:00+02:00", + "2023-05-09T16:00:00+02:00", + "2023-05-09T18:00:00+02:00", + "2023-05-09T20:00:00+02:00", + "2023-05-09T22:00:00+02:00", + "2023-05-10T00:00:00+02:00", + "2023-05-10T02:00:00+02:00", + "2023-05-10T04:00:00+02:00", + "2023-05-10T06:00:00+02:00", + "2023-05-10T08:00:00+02:00", + "2023-05-10T10:00:00+02:00", + "2023-05-10T12:00:00+02:00", + "2023-05-10T14:00:00+02:00", + "2023-05-10T16:00:00+02:00", + "2023-05-10T18:00:00+02:00", + "2023-05-10T20:00:00+02:00", + "2023-05-10T22:00:00+02:00", + "2023-05-11T00:00:00+02:00", + "2023-05-11T02:00:00+02:00", + "2023-05-11T04:00:00+02:00", + "2023-05-11T06:00:00+02:00", + "2023-05-11T08:00:00+02:00", + "2023-05-11T10:00:00+02:00", + "2023-05-11T12:00:00+02:00", + "2023-05-11T14:00:00+02:00", + "2023-05-11T16:00:00+02:00", + "2023-05-11T18:00:00+02:00", + "2023-05-11T20:00:00+02:00", + "2023-05-11T22:00:00+02:00", + "2023-05-12T00:00:00+02:00", + "2023-05-12T02:00:00+02:00", + "2023-05-12T04:00:00+02:00", + "2023-05-12T06:00:00+02:00", + "2023-05-12T08:00:00+02:00", + "2023-05-12T10:00:00+02:00", + "2023-05-12T12:00:00+02:00", + "2023-05-12T14:00:00+02:00", + "2023-05-12T16:00:00+02:00", + "2023-05-12T18:00:00+02:00", + "2023-05-12T20:00:00+02:00", + "2023-05-12T22:00:00+02:00", + "2023-05-13T00:00:00+02:00", + "2023-05-13T02:00:00+02:00", + "2023-05-13T04:00:00+02:00", + "2023-05-13T06:00:00+02:00", + "2023-05-13T08:00:00+02:00", + "2023-05-13T10:00:00+02:00", + "2023-05-13T12:00:00+02:00", + "2023-05-13T14:00:00+02:00", + "2023-05-13T16:00:00+02:00", + "2023-05-13T18:00:00+02:00", + "2023-05-13T20:00:00+02:00", + "2023-05-13T22:00:00+02:00", + "2023-05-14T00:00:00+02:00", + "2023-05-14T02:00:00+02:00", + "2023-05-14T04:00:00+02:00", + "2023-05-14T06:00:00+02:00", + "2023-05-14T08:00:00+02:00", + "2023-05-14T10:00:00+02:00", + "2023-05-14T12:00:00+02:00", + "2023-05-14T14:00:00+02:00", + "2023-05-14T16:00:00+02:00", + "2023-05-14T18:00:00+02:00", + "2023-05-14T20:00:00+02:00", + "2023-05-14T22:00:00+02:00", + "2023-05-15T00:00:00+02:00", + "2023-05-15T02:00:00+02:00", + "2023-05-15T04:00:00+02:00", + "2023-05-15T06:00:00+02:00", + "2023-05-15T08:00:00+02:00", + "2023-05-15T10:00:00+02:00", + "2023-05-15T12:00:00+02:00", + "2023-05-15T14:00:00+02:00", + "2023-05-15T16:00:00+02:00", + "2023-05-15T18:00:00+02:00", + "2023-05-15T20:00:00+02:00", + "2023-05-15T22:00:00+02:00", + "2023-05-16T00:00:00+02:00", + "2023-05-16T02:00:00+02:00", + "2023-05-16T04:00:00+02:00", + "2023-05-16T06:00:00+02:00", + "2023-05-16T08:00:00+02:00", + "2023-05-16T10:00:00+02:00", + "2023-05-16T12:00:00+02:00", + "2023-05-16T14:00:00+02:00", + "2023-05-16T16:00:00+02:00", + "2023-05-16T18:00:00+02:00", + "2023-05-16T20:00:00+02:00", + "2023-05-16T22:00:00+02:00", + "2023-05-17T00:00:00+02:00", + "2023-05-17T02:00:00+02:00", + "2023-05-17T04:00:00+02:00", + "2023-05-17T06:00:00+02:00", + "2023-05-17T08:00:00+02:00", + "2023-05-17T10:00:00+02:00", + "2023-05-17T12:00:00+02:00", + "2023-05-17T14:00:00+02:00", + "2023-05-17T16:00:00+02:00", + "2023-05-17T18:00:00+02:00", + "2023-05-17T20:00:00+02:00", + "2023-05-17T22:00:00+02:00", + "2023-05-18T00:00:00+02:00", + "2023-05-18T02:00:00+02:00", + "2023-05-18T04:00:00+02:00", + "2023-05-18T06:00:00+02:00", + "2023-05-18T08:00:00+02:00", + "2023-05-18T10:00:00+02:00", + "2023-05-18T12:00:00+02:00", + "2023-05-18T14:00:00+02:00", + "2023-05-18T16:00:00+02:00", + "2023-05-18T18:00:00+02:00", + "2023-05-18T20:00:00+02:00", + "2023-05-18T22:00:00+02:00", + "2023-05-19T00:00:00+02:00", + "2023-05-19T02:00:00+02:00", + "2023-05-19T04:00:00+02:00", + "2023-05-19T06:00:00+02:00", + "2023-05-19T08:00:00+02:00", + "2023-05-19T10:00:00+02:00", + "2023-05-19T12:00:00+02:00", + "2023-05-19T14:00:00+02:00", + "2023-05-19T16:00:00+02:00", + "2023-05-19T18:00:00+02:00", + "2023-05-19T20:00:00+02:00", + "2023-05-19T22:00:00+02:00", + "2023-05-20T00:00:00+02:00", + "2023-05-20T02:00:00+02:00", + "2023-05-20T04:00:00+02:00", + "2023-05-20T06:00:00+02:00", + "2023-05-20T08:00:00+02:00", + "2023-05-20T10:00:00+02:00", + "2023-05-20T12:00:00+02:00", + "2023-05-20T14:00:00+02:00", + "2023-05-20T16:00:00+02:00", + "2023-05-20T18:00:00+02:00", + "2023-05-20T20:00:00+02:00", + "2023-05-20T22:00:00+02:00", + "2023-05-21T00:00:00+02:00", + "2023-05-21T02:00:00+02:00", + "2023-05-21T04:00:00+02:00", + "2023-05-21T06:00:00+02:00", + "2023-05-21T08:00:00+02:00", + "2023-05-21T10:00:00+02:00", + "2023-05-21T12:00:00+02:00", + "2023-05-21T14:00:00+02:00", + "2023-05-21T16:00:00+02:00", + "2023-05-21T18:00:00+02:00", + "2023-05-21T20:00:00+02:00", + "2023-05-21T22:00:00+02:00", + "2023-05-22T00:00:00+02:00", + "2023-05-22T02:00:00+02:00", + "2023-05-22T04:00:00+02:00", + "2023-05-22T06:00:00+02:00", + "2023-05-22T08:00:00+02:00", + "2023-05-22T10:00:00+02:00", + "2023-05-22T12:00:00+02:00", + "2023-05-22T14:00:00+02:00", + "2023-05-22T16:00:00+02:00", + "2023-05-22T18:00:00+02:00", + "2023-05-22T20:00:00+02:00", + "2023-05-22T22:00:00+02:00", + "2023-05-23T00:00:00+02:00", + "2023-05-23T02:00:00+02:00", + "2023-05-23T04:00:00+02:00", + "2023-05-23T06:00:00+02:00", + "2023-05-23T08:00:00+02:00", + "2023-05-23T10:00:00+02:00", + "2023-05-23T12:00:00+02:00", + "2023-05-23T14:00:00+02:00", + "2023-05-23T16:00:00+02:00", + "2023-05-23T18:00:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/lastWeek.json b/centreon/packages/ui/src/Graph/mockedData/lastWeek.json new file mode 100644 index 0000000000..306a3d4ef4 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/lastWeek.json @@ -0,0 +1,2169 @@ +{ + "global": { + "title": "oracle-shared-spool-ratio graph on srv-oracle-users", + "start": "2023-05-31T21:38:30+02:00", + "end": "2023-06-07T21:38:30+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 0, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 4811, + "metric_id": 11758, + "metric": "connTime", + "metric_legend": "connTime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#ff99cc" + }, + "legend": "connTime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + null, + 0.717525, + 0.3018625, + 0.6411125, + 0.6719375, + 0.5789875, + 0.375325, + 0.434875, + 0.7254375, + 0.41635, + 0.5296625, + 0.5241625, + 0.5008125, + 0.328025, + 0.24695, + 0.5298875, + 0.5998875, + 0.5346, + 0.508, + 0.5056375, + 0.4966125, + 0.5914375, + 0.701275, + 0.3506625, + 0.63425, + 0.5625, + 0.504375, + 0.6008125, + 0.3560625, + 0.3476125, + 0.6056125, + 0.4730875, + 0.4119875, + 0.3657125, + 0.3893625, + 0.546625, + 0.4844125, + 0.490725, + 0.61925, + 0.38985, + 0.6627375, + 0.63485, + 0.6175375, + 0.6968625, + 0.5562375, + 0.5588125, + 0.538375, + 0.4368875, + 0.3541, + 0.5216625, + 0.6249375, + 0.503875, + 0.6219, + 0.522975, + 0.5200125, + 0.2984625, + 0.5670125, + 0.5595875, + 0.552775, + 0.2506625, + 0.6193875, + 0.6573125, + 0.409525, + 0.59644833333, + 0.36721, + 0.62277333333, + 0.47325666667, + 0.61849, + 0.4591, + 0.33787, + 0.38395, + 0.34516666667, + 0.59038333333, + 0.51955333333, + 0.47505333333, + 0.43277666667, + 0.59717, + 0.70510333333, + 0.66649, + 0.46514, + 0.46619333333, + 0.40967, + 0.42753666667, + 0.56417333333, + 0.44391333333, + 0.22163333333, + 0.41199, + 0.31270666667, + 0.12166333333, + 0.45610333333, + 0.58512333333, + 0.29505333333, + 0.44652333333, + 0.38225416667, + 0.55458916667, + 0.55572166667, + 0.70581083333, + 0.38728666667, + 0.33232083333, + 0.44731583333, + 0.46990666667, + 0.5206225, + 0.35315583333, + 0.23610666667, + 0.5165575, + 0.67101083333, + 0.54885083333, + 0.64442083333, + 0.5659775, + 0.51162166667, + 0.6147, + 0.29876833333, + 0.2973525, + 0.60096416667, + 0.4574825, + 0.23486, + 0.38384916667, + 0.65109333333, + 0.51326333333, + 0.52025916667, + 0.65400666667, + 0.61474333333, + 0.550155, + 0.495895, + 0.5000875, + 0.29316166667, + 0.42695416667, + 0.54268916667, + 0.40367333333, + 0.70920166667, + 0.47661666667, + 0.78255833333, + 0.63996833333, + 0.23638833333, + 0.62122166667, + 0.30513333333, + 0.48345333333, + 0.54869083333, + 0.58614, + 0.39769583333, + 0.53929416667, + 0.69158416667, + 0.37134333333, + 0.4304575, + 0.35328833333, + 0.54430333333, + 0.33399583333, + 0.3304475, + 0.49739083333, + 0.52327, + 0.44271583333, + 0.62411083333, + 0.33883916667, + 0.57436083333, + 0.372225, + 0.47777083333, + 0.50257083333, + 0.39460083333, + 0.3795, + 0.45644333333, + 0.48521833333, + 0.25798083333, + 0.43766083333, + 0.5164875, + 0.390385, + 0.43386166667, + 0.71189833333, + 0.65404416667, + 0.336205, + 0.24493833333, + 0.57420333333, + 0.62064333333, + 0.54600666667, + 0.63159083333, + 0.50600083333, + 0.628085, + 0.42937, + 0.355585, + 0.637485, + 0.45999166667, + 0.38066166667, + 0.38246416667, + 0.45208416667, + 0.52603666667, + 0.58880416667, + 0.5446225, + 0.4066625, + 0.75533666667, + 0.499815, + 0.52572166667, + 0.32579166667, + 0.50101583333, + 0.17458583333, + 0.56188333333, + 0.62301666667, + 0.56505, + 0.5881, + 0.5673, + 0.36425, + 0.42038333333, + 0.37036666667, + 0.58353333333, + 0.50581666667, + 0.5374, + 0.22163333333, + 0.53886666667, + 0.41891666667, + 0.67956666667, + 0.5002, + 0.31088333333, + 0.62308333333, + 0.53451666667, + 0.4744, + 0.3157, + 0.77371666667, + 0.35426666667, + 0.51916666667, + 0.60275, + 0.58133333333, + 0.46916666667, + 0.40691666667, + 0.80266666667, + 0.59691666667, + 0.46365, + 0.84005, + 0.51505, + 0.61381666667, + 0.48591666667, + 0.28575, + 0.37908333333, + 0.5565, + 0.6975, + 0.47025, + 0.466, + 0.35141666667, + 0.52208333333, + 0.37233333333, + 0.34675, + 0.42075, + 0.64435, + 0.24191666667, + 0.61901666667, + 0.55591666667, + 0.51921666667, + 0.5654, + 0.38245, + 0.46736666667, + 0.65755, + 0.50645, + 0.55333333333, + 0.37858333333, + 0.50808333333, + 0.58433333333, + 0.35175, + 0.42908333333, + 0.36233333333, + 0.56158333333, + 0.31195, + 0.68023333333, + 0.59651666667, + 0.64825, + 0.71858333333, + 0.54138333333, + 0.73991666667, + 0.55478333333, + 0.4892, + 0.56783333333, + 0.63965, + 0.47205, + 0.27215, + 0.25745, + 0.70008333333, + 0.59661666667, + 0.5026, + 0.49326666667, + 0.3655, + 0.60356333333, + 0.2132275, + 0.8226925, + 0.36787, + 0.4914825, + 0.3909675, + 0.5646075, + 0.3643125, + 0.457405, + 0.471935, + 0.4731125, + 0.7753075, + 0.49163, + 0.244405, + 0.557185, + 0.4107075, + 0.54546666667, + 0.64036666667, + 0.29668, + 0.3992, + 0.63089666667, + 0.75758666667, + 0.56485, + 0.413955, + 0.5602, + 0.431975, + 0.43485666667, + 0.30827166667, + 0.39586333333, + 0.37732833333, + 0.51866333333, + 0.52611333333, + 0.31280166667, + 0.50100333333, + 0.549735, + 0.42203833333, + 0.45060333333, + 0.42550666667, + 0.54967666667, + 0.37341666667, + 0.38782333333, + 0.51425166667, + 0.51834, + 0.45271833333, + 0.711285, + 0.577775, + 0.47911833333, + 0.44316666667, + 0.34324666667, + 0.33805833333, + 0.27513166667, + 0.53801166667, + 0.77332333333, + 0.47316, + 0.574345, + 0.60672666667, + 0.62811833333, + 0.50659, + 0.42655083333, + 0.2728925, + 0.67187, + 0.3979, + 0.50411166667, + 0.65740666667, + 0.63976833333, + 0.6468725, + 0.47726833333, + 0.4558775, + 0.30631666667, + 0.5109975, + 0.5717275, + 0.66228083333, + 0.69612166667, + 0.426675, + 0.35191333333, + 0.38965666667, + 0.2744825, + 0.5117825, + 0.55155416667, + 0.41036583333, + 0.46853916667, + 0.62363833333, + 0.3687475, + 0.44296916667, + 0.24307666667, + 0.765635, + 0.63333083333, + 0.4951, + 0.3801225, + 0.4771775, + 0.39723416667, + 0.4643, + 0.4289525, + 0.44795416667, + 0.76632583333, + 0.59939916667, + 0.2934925, + 0.19469416667, + 0.19469333333, + 0.492425, + 0.63350833333, + 0.33733833333, + 0.52109916667, + 0.7505775, + 0.40881, + 0.69642, + 0.76366, + 0.58523, + 0.44103, + 0.6813, + 0.65428, + 0.50898, + 0.58906, + 0.26844, + 0.38626, + 0.44927, + 0.40626, + 0.43084, + 0.54353, + 0.15838, + 0.66925, + 0.37817, + 0.4707, + 0.51832, + 0.5091, + 0.8043, + 0.40112, + 0.4939, + 0.54619, + 0.55022, + 0.59386, + 0.32591, + 0.2247, + 0.52951, + 0.51087, + 0.45835, + 0.33692, + 0.67881, + 0.62172, + 0.52216, + 0.45299, + 0.56436, + 0.49893, + 0.55314, + 0.49332, + 0.46613, + 0.23186, + 0.5636, + 0.11787, + 0.55091, + 0.44308, + 0.39479, + 0.25959, + 0.46345, + 0.41195, + 0.64631, + 0.78474, + 0.5461, + 0.60538, + 0.36694, + 0.61858, + 0.62356, + 0.72798, + 0.65403, + 0.44993, + 0.41512, + 0.408, + 0.57437, + 0.52494, + 0.56954, + 0.61914, + 0.41972, + 0.56292, + 0.66072, + 0.60597, + 0.3471, + 0.50783, + 0.55257, + 0.61786, + 0.43487, + 0.50873, + 0.4697, + 0.67452, + 0.63891, + 0.42052, + 0.50675, + 0.65396, + 0.44012, + 0.49093, + 0.62349, + 0.24831, + 0.40325, + 0.3517, + 0.2406375, + 0.4074125, + 0.57481666667, + 0.44426666667, + 0.57990416667, + 0.3584625, + 0.56930833333, + 0.461075, + 0.69519166667, + 0.58419166667, + 0.6644625, + 0.58740833333, + 0.502175, + 0.54106666667, + 0.39467916667, + 0.54319166667, + 0.675225, + 0.6772375, + 0.4582625, + 0.4673875, + 0.43303333333, + 0.44830416667, + 0.421425, + 0.4474125, + 0.72664583333, + 0.55170833333, + 0.4613375, + 0.71693333333, + 0.35159583333, + 0.49416666667, + 0.41411666667, + 0.52532083333, + 0.46037916667, + 0.63142083333, + 0.6827625, + 0.40663333333 + ], + "prints": [["Last:0.41"], ["Min:0.12"], ["Max:0.84"], ["Average:0.50"]], + "last_value": 0.41, + "minimum_value": 0.12, + "maximum_value": 0.84, + "average_value": 0.5 + }, + { + "index_id": 4811, + "metric_id": 11757, + "metric": "querytime", + "metric_legend": "querytime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#6666ff" + }, + "legend": "querytime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + null, + 0.3822375, + 0.338175, + 0.729925, + 0.6532, + 0.6622875, + 0.45505, + 0.60315, + 0.401275, + 0.54565, + 0.4648375, + 0.56345, + 0.2957375, + 0.4214125, + 0.5022875, + 0.52665, + 0.3344125, + 0.634875, + 0.33875, + 0.5235, + 0.43645, + 0.45645, + 0.61025, + 0.653525, + 0.44325, + 0.398125, + 0.350875, + 0.3941875, + 0.4985875, + 0.2608125, + 0.269875, + 0.4928875, + 0.292925, + 0.43555, + 0.6956375, + 0.615925, + 0.3165375, + 0.6310875, + 0.5219875, + 0.5560875, + 0.5781875, + 0.427875, + 0.272275, + 0.7289, + 0.5525875, + 0.626725, + 0.6548, + 0.56645, + 0.3159625, + 0.5493, + 0.5752875, + 0.46215, + 0.3014875, + 0.3867625, + 0.539775, + 0.6039375, + 0.4355875, + 0.411425, + 0.4830375, + 0.3762125, + 0.71735, + 0.269, + 0.567975, + 0.49262833333, + 0.40225333333, + 0.62421, + 0.34907333333, + 0.66614, + 0.64291666667, + 0.47280333333, + 0.5396, + 0.39403, + 0.44625666667, + 0.72860333333, + 0.22214666667, + 0.76609, + 0.47886666667, + 0.50008, + 0.70910666667, + 0.52188, + 0.44055, + 0.36468666667, + 0.36503333333, + 0.41122, + 0.5653, + 0.22648, + 0.47388333333, + 0.40938666667, + 0.54979333333, + 0.4558, + 0.27218, + 0.84006333333, + 0.25509833333, + 0.34533916667, + 0.37986833333, + 0.41476833333, + 0.36977166667, + 0.24393166667, + 0.5005625, + 0.374215, + 0.85380833333, + 0.4801225, + 0.31904166667, + 0.4585075, + 0.752745, + 0.21556833333, + 0.4998575, + 0.60881666667, + 0.40523416667, + 0.48311333333, + 0.6045525, + 0.20181833333, + 0.59113666667, + 0.61002333333, + 0.480365, + 0.37949833333, + 0.24222583333, + 0.7307925, + 0.38327416667, + 0.40005166667, + 0.50885, + 0.44563666667, + 0.55531166667, + 0.49530833333, + 0.36818666667, + 0.5764775, + 0.64380083333, + 0.42206, + 0.29359166667, + 0.49560666667, + 0.443325, + 0.25875833333, + 0.30041833333, + 0.3564575, + 0.58502416667, + 0.74223416667, + 0.50057833333, + 0.4538275, + 0.34179333333, + 0.29270583333, + 0.60702083333, + 0.4216275, + 0.25602583333, + 0.56200416667, + 0.41060916667, + 0.3873225, + 0.7328475, + 0.44749666667, + 0.48708083333, + 0.31724666667, + 0.542455, + 0.32911083333, + 0.24504166667, + 0.4943, + 0.69643166667, + 0.45696916667, + 0.57769166667, + 0.53687416667, + 0.34264083333, + 0.46102416667, + 0.47288583333, + 0.581615, + 0.65317833333, + 0.46009833333, + 0.52495416667, + 0.41317166667, + 0.55043333333, + 0.57696583333, + 0.48937083333, + 0.18298166667, + 0.656815, + 0.54156916667, + 0.62982333333, + 0.55033916667, + 0.60631083333, + 0.76121, + 0.18459, + 0.76492, + 0.66709, + 0.50244, + 0.39493, + 0.65535666667, + 0.35731916667, + 0.64019916667, + 0.456475, + 0.55792416667, + 0.66605916667, + 0.21065083333, + 0.4248575, + 0.850955, + 0.53539416667, + 0.40172916667, + 0.606185, + 0.58081666667, + 0.54806666667, + 0.33323333333, + 0.51793333333, + 0.55431666667, + 0.59668333333, + 0.49018333333, + 0.59998333333, + 0.44546666667, + 0.33053333333, + 0.26628333333, + 0.28708333333, + 0.39905, + 0.6059, + 0.66223333333, + 0.61336666667, + 0.64191666667, + 0.64243333333, + 0.2932, + 0.46686666667, + 0.6745, + 0.43336666667, + 0.44585, + 0.55441666667, + 0.39591666667, + 0.59966666667, + 0.53675, + 0.15408333333, + 0.418, + 0.6015, + 0.5368, + 0.60053333333, + 0.59256666667, + 0.49055, + 0.51608333333, + 0.56116666667, + 0.48791666667, + 0.27166666667, + 0.44933333333, + 0.30175, + 0.532, + 0.29925, + 0.68191666667, + 0.69808333333, + 0.39383333333, + 0.64958333333, + 0.59386666667, + 0.60863333333, + 0.4553, + 0.44306666667, + 0.35461666667, + 0.23823333333, + 0.39873333333, + 0.31028333333, + 0.28183333333, + 0.51358333333, + 0.53908333333, + 0.38191666667, + 0.6085, + 0.557, + 0.55133333333, + 0.46758333333, + 0.43775, + 0.45041666667, + 0.52871666667, + 0.62766666667, + 0.16445, + 0.56378333333, + 0.6319, + 0.71301666667, + 0.19243333333, + 0.36086666667, + 0.52955, + 0.56008333333, + 0.46958333333, + 0.61478333333, + 0.5179, + 0.37285, + 0.54513333333, + 0.89198333333, + 0.34831666667, + 0.79711666667, + 0.46571666667, + 0.45108583333, + 0.65635, + 0.710995, + 0.62707, + 0.3558975, + 0.49199, + 0.3899075, + 0.34151, + 0.380945, + 0.455615, + 0.5316275, + 0.4313475, + 0.560775, + 0.4743425, + 0.5747375, + 0.4835775, + 0.65969916667, + 0.42680333333, + 0.600725, + 0.32630666667, + 0.64745666667, + 0.31762833333, + 0.42268333333, + 0.35116833333, + 0.47142, + 0.26832333333, + 0.34496666667, + 0.688725, + 0.49774833333, + 0.34480666667, + 0.54177, + 0.55014166667, + 0.37234166667, + 0.60997, + 0.59000833333, + 0.565245, + 0.37924666667, + 0.389445, + 0.35244833333, + 0.827515, + 0.41951166667, + 0.65853166667, + 0.42363333333, + 0.68144666667, + 0.44951, + 0.26957, + 0.33074833333, + 0.72332666667, + 0.50786833333, + 0.42016166667, + 0.59982, + 0.66384833333, + 0.3585, + 0.622105, + 0.5329, + 0.44583666667, + 0.39592083333, + 0.675235, + 0.71880166667, + 0.43023166667, + 0.35486, + 0.53464583333, + 0.33980833333, + 0.5025275, + 0.73073, + 0.37100083333, + 0.458425, + 0.16272833333, + 0.66322666667, + 0.46470333333, + 0.5706925, + 0.51309583333, + 0.4167775, + 0.51913833333, + 0.36356833333, + 0.67057583333, + 0.46865333333, + 0.56207416667, + 0.64422833333, + 0.55513166667, + 0.69586833333, + 0.64558416667, + 0.39396166667, + 0.70361083333, + 0.38941333333, + 0.46966833333, + 0.479135, + 0.51729916667, + 0.34119666667, + 0.52859583333, + 0.4759925, + 0.28715, + 0.47405416667, + 0.27516, + 0.23419833333, + 0.31827916667, + 0.46054416667, + 0.64301333333, + 0.52912333333, + 0.45455166667, + 0.73102333333, + 0.40912583333, + 0.3304225, + 0.4438325, + 0.34953, + 0.53485, + 0.81125, + 0.25488, + 0.55834, + 0.35964, + 0.26034, + 0.37592, + 0.39875, + 0.66929, + 0.66451, + 0.5947, + 0.27555, + 0.68353, + 0.49617, + 0.653, + 0.48443, + 0.39418, + 0.36428, + 0.53593, + 0.3297, + 0.43443, + 0.46853, + 0.64149, + 0.38523, + 0.39072, + 0.44623, + 0.36313, + 0.50542, + 0.43385, + 0.55568, + 0.79068, + 0.46728, + 0.54486, + 0.60739, + 0.46496, + 0.61119, + 0.38873, + 0.56806, + 0.747, + 0.53613, + 0.53121, + 0.46506, + 0.59626, + 0.69317, + 0.68011, + 0.51598, + 0.50257, + 0.54439, + 0.40571, + 0.2189, + 0.64132, + 0.29015, + 0.43577, + 0.37661, + 0.46952, + 0.45527, + 0.66985, + 0.40971, + 0.63007, + 0.63755, + 0.65143, + 0.57865, + 0.65552, + 0.36992, + 0.23763, + 0.48393, + 0.36113, + 0.39058, + 0.40755, + 0.56333, + 0.48995, + 0.55673, + 0.37367, + 0.48381, + 0.40106, + 0.48643, + 0.51592, + 0.29743, + 0.5026, + 0.42763, + 0.46854, + 0.41662, + 0.50732, + 0.385, + 0.61506, + 0.49011, + 0.36046, + 0.5442, + 0.61745833333, + 0.392325, + 0.4967625, + 0.30943333333, + 0.58880416667, + 0.57861666667, + 0.72248333333, + 0.42585, + 0.6050125, + 0.64172083333, + 0.4269375, + 0.20662083333, + 0.43435833333, + 0.71460833333, + 0.42285833333, + 0.48760416667, + 0.5523, + 0.55450833333, + 0.5237, + 0.77244166667, + 0.69525, + 0.58763333333, + 0.44484166667, + 0.61220833333, + 0.50095416667, + 0.54782916667, + 0.5573, + 0.7095625, + 0.41794583333, + 0.49679166667, + 0.4172, + 0.53237916667, + 0.48497083333, + 0.608475, + 0.55396666667, + 0.62546666667 + ], + "prints": [["Last:0.63"], ["Min:0.15"], ["Max:0.89"], ["Average:0.49"]], + "last_value": 0.63, + "minimum_value": 0.15, + "maximum_value": 0.89, + "average_value": 0.49 + }, + { + "index_id": 4811, + "metric_id": 11756, + "metric": "used", + "metric_legend": "used", + "unit": "%", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 8, + "host_id": null, + "service_id": null, + "name": "Used", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": "used", + "ds_color_line": "#2B28D7", + "ds_color_line_mode": "0", + "ds_color_area": "#050AF9", + "ds_color_area_warn": null, + "ds_color_area_crit": null, + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "used", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 1, + "data": [ + null, + 75.3011875, + 72.701875, + 76.0167625, + 77.1073125, + 77.69285, + 80.2417, + 78.7382375, + 79.45205, + 81.0908625, + 80.5548625, + 80.668475, + 78.979675, + 79.0966875, + 82.8746, + 83.72185, + 84.4060125, + 88.59015, + 90.0966875, + 89.238625, + 87.6741375, + 86.301075, + 85.9866375, + 84.2715875, + 80.7764375, + 81.1740625, + 80.62725, + 82.847125, + 84.5257125, + 79.901275, + 79.2864875, + 80.3480625, + 80.181925, + 80.396225, + 82.583625, + 84.016875, + 84.045875, + 86.91195, + 87.9055, + 86.8288875, + 81.1321375, + 77.683675, + 80.9037, + 81.4005125, + 80.3968625, + 80.5861125, + 80.9034875, + 80.96685, + 77.6486125, + 78.8831625, + 80.6013125, + 82.2192125, + 83.39895, + 84.18365, + 86.6931625, + 87.6480875, + 88.556875, + 86.548725, + 85.8728875, + 87.7177, + 87.7906, + 88.5137875, + 86.34185, + 84.619306667, + 86.954396667, + 87.26102, + 85.965446667, + 81.80268, + 78.111126667, + 74.197206667, + 77.399083333, + 78.85909, + 79.281386667, + 82.736843333, + 85.45574, + 85.426433333, + 89.254713333, + 91.27352, + 92.164943333, + 90.351, + 90.002126667, + 91.9092, + 95.647476667, + 97.08391, + 98.31337, + 95.339653333, + 95.52575, + 93.628453333, + 93.64629, + 94.364876667, + 91.26281, + 94.746766667, + 91.7748525, + 88.535216667, + 90.4502975, + 91.635938333, + 94.736506667, + 95.6047775, + 97.476596667, + 94.989260833, + 95.033961667, + 96.242233333, + 93.5059225, + 94.352619167, + 92.387683333, + 94.498268333, + 94.36248, + 94.02465, + 92.065673333, + 90.508024167, + 89.030559167, + 87.58097, + 89.509935, + 92.812699167, + 91.202060833, + 91.9585075, + 94.023786667, + 92.90212, + 90.4467425, + 89.739971667, + 92.775635, + 93.825290833, + 90.636063333, + 89.875763333, + 86.827475, + 88.0182975, + 91.871829167, + 91.756616667, + 91.505121667, + 89.615869167, + 91.229351667, + 94.891750833, + 94.960114167, + 95.58294, + 95.994029167, + 95.9366675, + 96.498086667, + 97.487198333, + 93.075826667, + 94.302755833, + 93.073150833, + 90.271178333, + 89.814095, + 87.417926667, + 86.022469167, + 85.3772725, + 85.730900833, + 87.691193333, + 88.513690833, + 89.176271667, + 89.875075, + 92.313001667, + 94.845433333, + 96.612829167, + 94.3659575, + 94.697136667, + 96.204745833, + 97.567138333, + 97.420164167, + 98.677866667, + 98.801283333, + 98.172911667, + 97.751070833, + 96.347039167, + 94.636588333, + 92.814395, + 92.377689167, + 92.916798333, + 93.032718333, + 94.1146975, + 93.295709167, + 90.99396, + 92.248504167, + 93.131444167, + 91.676540833, + 93.38632, + 95.87702, + 95.42711, + 96.049845, + 98.458085833, + 98.224996667, + 95.8955225, + 93.5389625, + 90.5482675, + 88.2340275, + 87.588475, + 85.262625833, + 86.147955, + 85.77075, + 86.131816667, + 86.20979, + 84.288503333, + 86.749560833, + 82.449683333, + 79.403566667, + 80.40625, + 77.62185, + 77.505733333, + 75.580283333, + 75.1924, + 74.935433333, + 75.530216667, + 76.428483333, + 75.221, + 75.210733333, + 75.364483333, + 74.642916667, + 72.729216667, + 72.219733333, + 72.1265, + 76.7763, + 80.489316667, + 81.445283333, + 79.979783333, + 81.412816667, + 84.612216667, + 87.098833333, + 89.32225, + 91.17525, + 91.2465, + 88.707333333, + 88.058916667, + 87.372083333, + 84.8882, + 84.867116667, + 85.636633333, + 83.310733333, + 82.562333333, + 81.755333333, + 79.718333333, + 77.312666667, + 77.36875, + 79.187666667, + 80.764166667, + 82.968083333, + 81.657916667, + 80.852166667, + 82.371916667, + 85.612, + 84.52515, + 81.67235, + 83.9048, + 85.694816667, + 88.53345, + 88.750566667, + 87.80635, + 87.07455, + 87.095933333, + 84.714483333, + 84.81275, + 88.785, + 90.634, + 91.73825, + 93.27175, + 91.766333333, + 90.315, + 86.82625, + 86.059816667, + 90.49965, + 90.212416667, + 91.374283333, + 92.0294, + 91.482916667, + 94.464233333, + 95.869833333, + 97.885783333, + 98.732733333, + 97.9996, + 97.174766667, + 96.148283333, + 97.29175, + 96.05795, + 96.3868, + 97.399783333, + 95.241033333, + 96.880383333, + 97.934975833, + 95.40756, + 93.9280425, + 92.8780525, + 90.131495, + 89.3369225, + 88.7673325, + 87.5925, + 88.31823, + 92.36844, + 90.9536425, + 91.4629525, + 88.317385, + 86.5111225, + 85.572935, + 84.9701425, + 86.193996667, + 87.876206667, + 91.04955, + 92.813215, + 92.907306667, + 92.374458333, + 93.688358333, + 93.683388333, + 93.016803333, + 92.019563333, + 93.503391667, + 90.542578333, + 92.529488333, + 92.534118333, + 93.654428333, + 92.217821667, + 93.979301667, + 93.334701667, + 90.995645, + 89.265961667, + 90.142598333, + 92.359028333, + 92.355875, + 90.124831667, + 90.137076667, + 91.351265, + 92.609895, + 94.423845, + 95.92939, + 96.94342, + 97.658953333, + 98.350373333, + 98.860638333, + 97.971453333, + 95.972083333, + 92.49751, + 90.06317, + 90.96775, + 92.706511667, + 91.154745833, + 93.041470833, + 95.212069167, + 95.547953333, + 93.797341667, + 94.932218333, + 94.738048333, + 92.303049167, + 93.12273, + 95.324159167, + 97.788798333, + 96.461085, + 97.918005, + 97.656589167, + 95.453511667, + 93.404599167, + 96.0549925, + 96.180735, + 92.732435833, + 90.8238375, + 91.933284167, + 91.178560833, + 92.574173333, + 91.4252825, + 87.24002, + 86.583490833, + 86.893840833, + 87.912079167, + 85.586765, + 78.548946667, + 77.958821667, + 79.511501667, + 82.340836667, + 81.43414, + 82.6612425, + 85.1368525, + 84.618974167, + 83.406545833, + 83.217361667, + 84.796903333, + 88.710369167, + 89.576425, + 87.697465, + 85.419298333, + 89.328040833, + 89.288233333, + 89.594449167, + 89.396855833, + 89.352433333, + 87.07019, + 84.88146, + 84.18839, + 83.16835, + 79.62206, + 79.43043, + 79.3563, + 79.27835, + 79.17697, + 76.76732, + 75.29581, + 75.70572, + 77.68538, + 76.74653, + 77.60974, + 79.9725, + 83.84825, + 85.77623, + 88.76174, + 86.57208, + 88.47665, + 90.85134, + 90.79955, + 87.98236, + 89.54416, + 86.85839, + 84.23926, + 84.02244, + 79.67462, + 79.58342, + 82.33326, + 82.35789, + 81.01324, + 81.55955, + 81.87204, + 83.22185, + 81.36665, + 81.08699, + 84.38985, + 86.73615, + 85.82253, + 86.40703, + 89.32901, + 88.43318, + 91.59042, + 91.78025, + 93.31614, + 96.78994, + 98.67566, + 98.30026, + 96.97067, + 96.7663, + 94.81573, + 95.48175, + 98.94147, + 97.88792, + 96.25044, + 95.91016, + 95.94154, + 98.28326, + 97.84947, + 96.28364, + 97.1102, + 95.14073, + 93.46838, + 96.50306, + 98.20423, + 98.88803, + 98.65825, + 98.88318, + 98.68902, + 97.16819, + 95.18848, + 94.46906, + 95.27017, + 93.6273, + 90.02585, + 88.44419, + 86.68886, + 87.13106, + 88.26944, + 86.24131, + 85.55237, + 82.99216, + 82.86858, + 84.60967, + 83.1773, + 83.97271, + 82.51906, + 84.892720833, + 86.416304167, + 84.4, + 86.107516667, + 82.4546875, + 79.498166667, + 78.921458333, + 76.025141667, + 72.7244875, + 72.484195833, + 74.67945, + 76.033079167, + 74.760233333, + 72.661283333, + 74.655441667, + 78.608441667, + 78.245175, + 77.557866667, + 78.07075, + 79.527925, + 81.827258333, + 84.270954167, + 84.8338625, + 87.5681375, + 87.761895833, + 88.1756375, + 86.58295, + 86.034920833, + 82.764025, + 83.575166667, + 84.764741667, + 86.313608333, + 91.112654167, + 90.49295, + 92.0893625, + 92.936327778 + ], + "prints": [["Last:92.94"], ["Average:88.05"]], + "last_value": 92.94, + "minimum_value": null, + "maximum_value": null, + "average_value": 88.05 + } + ], + "times": [ + "2023-05-31T21:40:00+02:00", + "2023-05-31T22:00:00+02:00", + "2023-05-31T22:20:00+02:00", + "2023-05-31T22:40:00+02:00", + "2023-05-31T23:00:00+02:00", + "2023-05-31T23:20:00+02:00", + "2023-05-31T23:40:00+02:00", + "2023-06-01T00:00:00+02:00", + "2023-06-01T00:20:00+02:00", + "2023-06-01T00:40:00+02:00", + "2023-06-01T01:00:00+02:00", + "2023-06-01T01:20:00+02:00", + "2023-06-01T01:40:00+02:00", + "2023-06-01T02:00:00+02:00", + "2023-06-01T02:20:00+02:00", + "2023-06-01T02:40:00+02:00", + "2023-06-01T03:00:00+02:00", + "2023-06-01T03:20:00+02:00", + "2023-06-01T03:40:00+02:00", + "2023-06-01T04:00:00+02:00", + "2023-06-01T04:20:00+02:00", + "2023-06-01T04:40:00+02:00", + "2023-06-01T05:00:00+02:00", + "2023-06-01T05:20:00+02:00", + "2023-06-01T05:40:00+02:00", + "2023-06-01T06:00:00+02:00", + "2023-06-01T06:20:00+02:00", + "2023-06-01T06:40:00+02:00", + "2023-06-01T07:00:00+02:00", + "2023-06-01T07:20:00+02:00", + "2023-06-01T07:40:00+02:00", + "2023-06-01T08:00:00+02:00", + "2023-06-01T08:20:00+02:00", + "2023-06-01T08:40:00+02:00", + "2023-06-01T09:00:00+02:00", + "2023-06-01T09:20:00+02:00", + "2023-06-01T09:40:00+02:00", + "2023-06-01T10:00:00+02:00", + "2023-06-01T10:20:00+02:00", + "2023-06-01T10:40:00+02:00", + "2023-06-01T11:00:00+02:00", + "2023-06-01T11:20:00+02:00", + "2023-06-01T11:40:00+02:00", + "2023-06-01T12:00:00+02:00", + "2023-06-01T12:20:00+02:00", + "2023-06-01T12:40:00+02:00", + "2023-06-01T13:00:00+02:00", + "2023-06-01T13:20:00+02:00", + "2023-06-01T13:40:00+02:00", + "2023-06-01T14:00:00+02:00", + "2023-06-01T14:20:00+02:00", + "2023-06-01T14:40:00+02:00", + "2023-06-01T15:00:00+02:00", + "2023-06-01T15:20:00+02:00", + "2023-06-01T15:40:00+02:00", + "2023-06-01T16:00:00+02:00", + "2023-06-01T16:20:00+02:00", + "2023-06-01T16:40:00+02:00", + "2023-06-01T17:00:00+02:00", + "2023-06-01T17:20:00+02:00", + "2023-06-01T17:40:00+02:00", + "2023-06-01T18:00:00+02:00", + "2023-06-01T18:20:00+02:00", + "2023-06-01T18:40:00+02:00", + "2023-06-01T19:00:00+02:00", + "2023-06-01T19:20:00+02:00", + "2023-06-01T19:40:00+02:00", + "2023-06-01T20:00:00+02:00", + "2023-06-01T20:20:00+02:00", + "2023-06-01T20:40:00+02:00", + "2023-06-01T21:00:00+02:00", + "2023-06-01T21:20:00+02:00", + "2023-06-01T21:40:00+02:00", + "2023-06-01T22:00:00+02:00", + "2023-06-01T22:20:00+02:00", + "2023-06-01T22:40:00+02:00", + "2023-06-01T23:00:00+02:00", + "2023-06-01T23:20:00+02:00", + "2023-06-01T23:40:00+02:00", + "2023-06-02T00:00:00+02:00", + "2023-06-02T00:20:00+02:00", + "2023-06-02T00:40:00+02:00", + "2023-06-02T01:00:00+02:00", + "2023-06-02T01:20:00+02:00", + "2023-06-02T01:40:00+02:00", + "2023-06-02T02:00:00+02:00", + "2023-06-02T02:20:00+02:00", + "2023-06-02T02:40:00+02:00", + "2023-06-02T03:00:00+02:00", + "2023-06-02T03:20:00+02:00", + "2023-06-02T03:40:00+02:00", + "2023-06-02T04:00:00+02:00", + "2023-06-02T04:20:00+02:00", + "2023-06-02T04:40:00+02:00", + "2023-06-02T05:00:00+02:00", + "2023-06-02T05:20:00+02:00", + "2023-06-02T05:40:00+02:00", + "2023-06-02T06:00:00+02:00", + "2023-06-02T06:20:00+02:00", + "2023-06-02T06:40:00+02:00", + "2023-06-02T07:00:00+02:00", + "2023-06-02T07:20:00+02:00", + "2023-06-02T07:40:00+02:00", + "2023-06-02T08:00:00+02:00", + "2023-06-02T08:20:00+02:00", + "2023-06-02T08:40:00+02:00", + "2023-06-02T09:00:00+02:00", + "2023-06-02T09:20:00+02:00", + "2023-06-02T09:40:00+02:00", + "2023-06-02T10:00:00+02:00", + "2023-06-02T10:20:00+02:00", + "2023-06-02T10:40:00+02:00", + "2023-06-02T11:00:00+02:00", + "2023-06-02T11:20:00+02:00", + "2023-06-02T11:40:00+02:00", + "2023-06-02T12:00:00+02:00", + "2023-06-02T12:20:00+02:00", + "2023-06-02T12:40:00+02:00", + "2023-06-02T13:00:00+02:00", + "2023-06-02T13:20:00+02:00", + "2023-06-02T13:40:00+02:00", + "2023-06-02T14:00:00+02:00", + "2023-06-02T14:20:00+02:00", + "2023-06-02T14:40:00+02:00", + "2023-06-02T15:00:00+02:00", + "2023-06-02T15:20:00+02:00", + "2023-06-02T15:40:00+02:00", + "2023-06-02T16:00:00+02:00", + "2023-06-02T16:20:00+02:00", + "2023-06-02T16:40:00+02:00", + "2023-06-02T17:00:00+02:00", + "2023-06-02T17:20:00+02:00", + "2023-06-02T17:40:00+02:00", + "2023-06-02T18:00:00+02:00", + "2023-06-02T18:20:00+02:00", + "2023-06-02T18:40:00+02:00", + "2023-06-02T19:00:00+02:00", + "2023-06-02T19:20:00+02:00", + "2023-06-02T19:40:00+02:00", + "2023-06-02T20:00:00+02:00", + "2023-06-02T20:20:00+02:00", + "2023-06-02T20:40:00+02:00", + "2023-06-02T21:00:00+02:00", + "2023-06-02T21:20:00+02:00", + "2023-06-02T21:40:00+02:00", + "2023-06-02T22:00:00+02:00", + "2023-06-02T22:20:00+02:00", + "2023-06-02T22:40:00+02:00", + "2023-06-02T23:00:00+02:00", + "2023-06-02T23:20:00+02:00", + "2023-06-02T23:40:00+02:00", + "2023-06-03T00:00:00+02:00", + "2023-06-03T00:20:00+02:00", + "2023-06-03T00:40:00+02:00", + "2023-06-03T01:00:00+02:00", + "2023-06-03T01:20:00+02:00", + "2023-06-03T01:40:00+02:00", + "2023-06-03T02:00:00+02:00", + "2023-06-03T02:20:00+02:00", + "2023-06-03T02:40:00+02:00", + "2023-06-03T03:00:00+02:00", + "2023-06-03T03:20:00+02:00", + "2023-06-03T03:40:00+02:00", + "2023-06-03T04:00:00+02:00", + "2023-06-03T04:20:00+02:00", + "2023-06-03T04:40:00+02:00", + "2023-06-03T05:00:00+02:00", + "2023-06-03T05:20:00+02:00", + "2023-06-03T05:40:00+02:00", + "2023-06-03T06:00:00+02:00", + "2023-06-03T06:20:00+02:00", + "2023-06-03T06:40:00+02:00", + "2023-06-03T07:00:00+02:00", + "2023-06-03T07:20:00+02:00", + "2023-06-03T07:40:00+02:00", + "2023-06-03T08:00:00+02:00", + "2023-06-03T08:20:00+02:00", + "2023-06-03T08:40:00+02:00", + "2023-06-03T09:00:00+02:00", + "2023-06-03T09:20:00+02:00", + "2023-06-03T09:40:00+02:00", + "2023-06-03T10:00:00+02:00", + "2023-06-03T10:20:00+02:00", + "2023-06-03T10:40:00+02:00", + "2023-06-03T11:00:00+02:00", + "2023-06-03T11:20:00+02:00", + "2023-06-03T11:40:00+02:00", + "2023-06-03T12:00:00+02:00", + "2023-06-03T12:20:00+02:00", + "2023-06-03T12:40:00+02:00", + "2023-06-03T13:00:00+02:00", + "2023-06-03T13:20:00+02:00", + "2023-06-03T13:40:00+02:00", + "2023-06-03T14:00:00+02:00", + "2023-06-03T14:20:00+02:00", + "2023-06-03T14:40:00+02:00", + "2023-06-03T15:00:00+02:00", + "2023-06-03T15:20:00+02:00", + "2023-06-03T15:40:00+02:00", + "2023-06-03T16:00:00+02:00", + "2023-06-03T16:20:00+02:00", + "2023-06-03T16:40:00+02:00", + "2023-06-03T17:00:00+02:00", + "2023-06-03T17:20:00+02:00", + "2023-06-03T17:40:00+02:00", + "2023-06-03T18:00:00+02:00", + "2023-06-03T18:20:00+02:00", + "2023-06-03T18:40:00+02:00", + "2023-06-03T19:00:00+02:00", + "2023-06-03T19:20:00+02:00", + "2023-06-03T19:40:00+02:00", + "2023-06-03T20:00:00+02:00", + "2023-06-03T20:20:00+02:00", + "2023-06-03T20:40:00+02:00", + "2023-06-03T21:00:00+02:00", + "2023-06-03T21:20:00+02:00", + "2023-06-03T21:40:00+02:00", + "2023-06-03T22:00:00+02:00", + "2023-06-03T22:20:00+02:00", + "2023-06-03T22:40:00+02:00", + "2023-06-03T23:00:00+02:00", + "2023-06-03T23:20:00+02:00", + "2023-06-03T23:40:00+02:00", + "2023-06-04T00:00:00+02:00", + "2023-06-04T00:20:00+02:00", + "2023-06-04T00:40:00+02:00", + "2023-06-04T01:00:00+02:00", + "2023-06-04T01:20:00+02:00", + "2023-06-04T01:40:00+02:00", + "2023-06-04T02:00:00+02:00", + "2023-06-04T02:20:00+02:00", + "2023-06-04T02:40:00+02:00", + "2023-06-04T03:00:00+02:00", + "2023-06-04T03:20:00+02:00", + "2023-06-04T03:40:00+02:00", + "2023-06-04T04:00:00+02:00", + "2023-06-04T04:20:00+02:00", + "2023-06-04T04:40:00+02:00", + "2023-06-04T05:00:00+02:00", + "2023-06-04T05:20:00+02:00", + "2023-06-04T05:40:00+02:00", + "2023-06-04T06:00:00+02:00", + "2023-06-04T06:20:00+02:00", + "2023-06-04T06:40:00+02:00", + "2023-06-04T07:00:00+02:00", + "2023-06-04T07:20:00+02:00", + "2023-06-04T07:40:00+02:00", + "2023-06-04T08:00:00+02:00", + "2023-06-04T08:20:00+02:00", + "2023-06-04T08:40:00+02:00", + "2023-06-04T09:00:00+02:00", + "2023-06-04T09:20:00+02:00", + "2023-06-04T09:40:00+02:00", + "2023-06-04T10:00:00+02:00", + "2023-06-04T10:20:00+02:00", + "2023-06-04T10:40:00+02:00", + "2023-06-04T11:00:00+02:00", + "2023-06-04T11:20:00+02:00", + "2023-06-04T11:40:00+02:00", + "2023-06-04T12:00:00+02:00", + "2023-06-04T12:20:00+02:00", + "2023-06-04T12:40:00+02:00", + "2023-06-04T13:00:00+02:00", + "2023-06-04T13:20:00+02:00", + "2023-06-04T13:40:00+02:00", + "2023-06-04T14:00:00+02:00", + "2023-06-04T14:20:00+02:00", + "2023-06-04T14:40:00+02:00", + "2023-06-04T15:00:00+02:00", + "2023-06-04T15:20:00+02:00", + "2023-06-04T15:40:00+02:00", + "2023-06-04T16:00:00+02:00", + "2023-06-04T16:20:00+02:00", + "2023-06-04T16:40:00+02:00", + "2023-06-04T17:00:00+02:00", + "2023-06-04T17:20:00+02:00", + "2023-06-04T17:40:00+02:00", + "2023-06-04T18:00:00+02:00", + "2023-06-04T18:20:00+02:00", + "2023-06-04T18:40:00+02:00", + "2023-06-04T19:00:00+02:00", + "2023-06-04T19:20:00+02:00", + "2023-06-04T19:40:00+02:00", + "2023-06-04T20:00:00+02:00", + "2023-06-04T20:20:00+02:00", + "2023-06-04T20:40:00+02:00", + "2023-06-04T21:00:00+02:00", + "2023-06-04T21:20:00+02:00", + "2023-06-04T21:40:00+02:00", + "2023-06-04T22:00:00+02:00", + "2023-06-04T22:20:00+02:00", + "2023-06-04T22:40:00+02:00", + "2023-06-04T23:00:00+02:00", + "2023-06-04T23:20:00+02:00", + "2023-06-04T23:40:00+02:00", + "2023-06-05T00:00:00+02:00", + "2023-06-05T00:20:00+02:00", + "2023-06-05T00:40:00+02:00", + "2023-06-05T01:00:00+02:00", + "2023-06-05T01:20:00+02:00", + "2023-06-05T01:40:00+02:00", + "2023-06-05T02:00:00+02:00", + "2023-06-05T02:20:00+02:00", + "2023-06-05T02:40:00+02:00", + "2023-06-05T03:00:00+02:00", + "2023-06-05T03:20:00+02:00", + "2023-06-05T03:40:00+02:00", + "2023-06-05T04:00:00+02:00", + "2023-06-05T04:20:00+02:00", + "2023-06-05T04:40:00+02:00", + "2023-06-05T05:00:00+02:00", + "2023-06-05T05:20:00+02:00", + "2023-06-05T05:40:00+02:00", + "2023-06-05T06:00:00+02:00", + "2023-06-05T06:20:00+02:00", + "2023-06-05T06:40:00+02:00", + "2023-06-05T07:00:00+02:00", + "2023-06-05T07:20:00+02:00", + "2023-06-05T07:40:00+02:00", + "2023-06-05T08:00:00+02:00", + "2023-06-05T08:20:00+02:00", + "2023-06-05T08:40:00+02:00", + "2023-06-05T09:00:00+02:00", + "2023-06-05T09:20:00+02:00", + "2023-06-05T09:40:00+02:00", + "2023-06-05T10:00:00+02:00", + "2023-06-05T10:20:00+02:00", + "2023-06-05T10:40:00+02:00", + "2023-06-05T11:00:00+02:00", + "2023-06-05T11:20:00+02:00", + "2023-06-05T11:40:00+02:00", + "2023-06-05T12:00:00+02:00", + "2023-06-05T12:20:00+02:00", + "2023-06-05T12:40:00+02:00", + "2023-06-05T13:00:00+02:00", + "2023-06-05T13:20:00+02:00", + "2023-06-05T13:40:00+02:00", + "2023-06-05T14:00:00+02:00", + "2023-06-05T14:20:00+02:00", + "2023-06-05T14:40:00+02:00", + "2023-06-05T15:00:00+02:00", + "2023-06-05T15:20:00+02:00", + "2023-06-05T15:40:00+02:00", + "2023-06-05T16:00:00+02:00", + "2023-06-05T16:20:00+02:00", + "2023-06-05T16:40:00+02:00", + "2023-06-05T17:00:00+02:00", + "2023-06-05T17:20:00+02:00", + "2023-06-05T17:40:00+02:00", + "2023-06-05T18:00:00+02:00", + "2023-06-05T18:20:00+02:00", + "2023-06-05T18:40:00+02:00", + "2023-06-05T19:00:00+02:00", + "2023-06-05T19:20:00+02:00", + "2023-06-05T19:40:00+02:00", + "2023-06-05T20:00:00+02:00", + "2023-06-05T20:20:00+02:00", + "2023-06-05T20:40:00+02:00", + "2023-06-05T21:00:00+02:00", + "2023-06-05T21:20:00+02:00", + "2023-06-05T21:40:00+02:00", + "2023-06-05T22:00:00+02:00", + "2023-06-05T22:20:00+02:00", + "2023-06-05T22:40:00+02:00", + "2023-06-05T23:00:00+02:00", + "2023-06-05T23:20:00+02:00", + "2023-06-05T23:40:00+02:00", + "2023-06-06T00:00:00+02:00", + "2023-06-06T00:20:00+02:00", + "2023-06-06T00:40:00+02:00", + "2023-06-06T01:00:00+02:00", + "2023-06-06T01:20:00+02:00", + "2023-06-06T01:40:00+02:00", + "2023-06-06T02:00:00+02:00", + "2023-06-06T02:20:00+02:00", + "2023-06-06T02:40:00+02:00", + "2023-06-06T03:00:00+02:00", + "2023-06-06T03:20:00+02:00", + "2023-06-06T03:40:00+02:00", + "2023-06-06T04:00:00+02:00", + "2023-06-06T04:20:00+02:00", + "2023-06-06T04:40:00+02:00", + "2023-06-06T05:00:00+02:00", + "2023-06-06T05:20:00+02:00", + "2023-06-06T05:40:00+02:00", + "2023-06-06T06:00:00+02:00", + "2023-06-06T06:20:00+02:00", + "2023-06-06T06:40:00+02:00", + "2023-06-06T07:00:00+02:00", + "2023-06-06T07:20:00+02:00", + "2023-06-06T07:40:00+02:00", + "2023-06-06T08:00:00+02:00", + "2023-06-06T08:20:00+02:00", + "2023-06-06T08:40:00+02:00", + "2023-06-06T09:00:00+02:00", + "2023-06-06T09:20:00+02:00", + "2023-06-06T09:40:00+02:00", + "2023-06-06T10:00:00+02:00", + "2023-06-06T10:20:00+02:00", + "2023-06-06T10:40:00+02:00", + "2023-06-06T11:00:00+02:00", + "2023-06-06T11:20:00+02:00", + "2023-06-06T11:40:00+02:00", + "2023-06-06T12:00:00+02:00", + "2023-06-06T12:20:00+02:00", + "2023-06-06T12:40:00+02:00", + "2023-06-06T13:00:00+02:00", + "2023-06-06T13:20:00+02:00", + "2023-06-06T13:40:00+02:00", + "2023-06-06T14:00:00+02:00", + "2023-06-06T14:20:00+02:00", + "2023-06-06T14:40:00+02:00", + "2023-06-06T15:00:00+02:00", + "2023-06-06T15:20:00+02:00", + "2023-06-06T15:40:00+02:00", + "2023-06-06T16:00:00+02:00", + "2023-06-06T16:20:00+02:00", + "2023-06-06T16:40:00+02:00", + "2023-06-06T17:00:00+02:00", + "2023-06-06T17:20:00+02:00", + "2023-06-06T17:40:00+02:00", + "2023-06-06T18:00:00+02:00", + "2023-06-06T18:20:00+02:00", + "2023-06-06T18:40:00+02:00", + "2023-06-06T19:00:00+02:00", + "2023-06-06T19:20:00+02:00", + "2023-06-06T19:40:00+02:00", + "2023-06-06T20:00:00+02:00", + "2023-06-06T20:20:00+02:00", + "2023-06-06T20:40:00+02:00", + "2023-06-06T21:00:00+02:00", + "2023-06-06T21:20:00+02:00", + "2023-06-06T21:40:00+02:00", + "2023-06-06T22:00:00+02:00", + "2023-06-06T22:20:00+02:00", + "2023-06-06T22:40:00+02:00", + "2023-06-06T23:00:00+02:00", + "2023-06-06T23:20:00+02:00", + "2023-06-06T23:40:00+02:00", + "2023-06-07T00:00:00+02:00", + "2023-06-07T00:20:00+02:00", + "2023-06-07T00:40:00+02:00", + "2023-06-07T01:00:00+02:00", + "2023-06-07T01:20:00+02:00", + "2023-06-07T01:40:00+02:00", + "2023-06-07T02:00:00+02:00", + "2023-06-07T02:20:00+02:00", + "2023-06-07T02:40:00+02:00", + "2023-06-07T03:00:00+02:00", + "2023-06-07T03:20:00+02:00", + "2023-06-07T03:40:00+02:00", + "2023-06-07T04:00:00+02:00", + "2023-06-07T04:20:00+02:00", + "2023-06-07T04:40:00+02:00", + "2023-06-07T05:00:00+02:00", + "2023-06-07T05:20:00+02:00", + "2023-06-07T05:40:00+02:00", + "2023-06-07T06:00:00+02:00", + "2023-06-07T06:20:00+02:00", + "2023-06-07T06:40:00+02:00", + "2023-06-07T07:00:00+02:00", + "2023-06-07T07:20:00+02:00", + "2023-06-07T07:40:00+02:00", + "2023-06-07T08:00:00+02:00", + "2023-06-07T08:20:00+02:00", + "2023-06-07T08:40:00+02:00", + "2023-06-07T09:00:00+02:00", + "2023-06-07T09:20:00+02:00", + "2023-06-07T09:40:00+02:00", + "2023-06-07T10:00:00+02:00", + "2023-06-07T10:20:00+02:00", + "2023-06-07T10:40:00+02:00", + "2023-06-07T11:00:00+02:00", + "2023-06-07T11:20:00+02:00", + "2023-06-07T11:40:00+02:00", + "2023-06-07T12:00:00+02:00", + "2023-06-07T12:20:00+02:00", + "2023-06-07T12:40:00+02:00", + "2023-06-07T13:00:00+02:00", + "2023-06-07T13:20:00+02:00", + "2023-06-07T13:40:00+02:00", + "2023-06-07T14:00:00+02:00", + "2023-06-07T14:20:00+02:00", + "2023-06-07T14:40:00+02:00", + "2023-06-07T15:00:00+02:00", + "2023-06-07T15:20:00+02:00", + "2023-06-07T15:40:00+02:00", + "2023-06-07T16:00:00+02:00", + "2023-06-07T16:20:00+02:00", + "2023-06-07T16:40:00+02:00", + "2023-06-07T17:00:00+02:00", + "2023-06-07T17:20:00+02:00", + "2023-06-07T17:40:00+02:00", + "2023-06-07T18:00:00+02:00", + "2023-06-07T18:20:00+02:00", + "2023-06-07T18:40:00+02:00", + "2023-06-07T19:00:00+02:00", + "2023-06-07T19:20:00+02:00", + "2023-06-07T19:40:00+02:00", + "2023-06-07T20:00:00+02:00", + "2023-06-07T20:20:00+02:00", + "2023-06-07T20:40:00+02:00", + "2023-06-07T21:00:00+02:00", + "2023-06-07T21:20:00+02:00", + "2023-06-07T21:40:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/pingService.json b/centreon/packages/ui/src/Graph/mockedData/pingService.json new file mode 100644 index 0000000000..823ca37347 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/pingService.json @@ -0,0 +1,240 @@ +{ + "global": { + "base": 1000, + "title": "Ping service" + }, + "metrics": [ + { + "metric_id": 2, + "metric": "Centreon-Server: pl", + "metric_legend": "Centreon-Server: pl", + "unit": "%", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#F30B23", + "ds_color_area": "#F30B23", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Packet Loss", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 10.0, + 20.0, + null, + null + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 10, + "metric": "Space used", + "metric_legend": "Space used", + "unit": "B", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#654321", + "ds_color_area": "#654321", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Space used", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 7277.536221378278, 1070.9229992641347, 5417.157870751178, + 7650.368581547736, 3062.1382654626154, 6896.485403855089, + 6016.271762192416, 592.4173666516415, 9130.151161464735, + 2556.376532531991, 8085.328518673757, 6283.734720996918, + 5617.226479531896 + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 1, + "metric": "Centreon-Server: rta", + "metric_legend": "Centreon-Server: rta", + "unit": "ms", + "min": 0.0, + "max": null, + "ds_data": { + "ds_color_line": "#29AFEE", + "ds_color_area": "#29AFEE", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Average Time", + "stack": 0, + "warning_high_threshold": 200.0, + "critical_high_threshold": 400.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.04508, + 0.0242, + 0.03592, + 0.01304, + 0.025, + 0.02748, + 0.05296, + 0.01864, + 0.02688, + 0.03676, + 0.03696, + null, + null + ], + "last_value": 0.04, + "minimum_value": null, + "maximum_value": null, + "average_value": 0.03 + }, + { + "metric_id": 3, + "metric": "Centreon-Server: rtmax", + "metric_legend": "Centreon-Server: rtmax", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#525256", + "ds_color_area": "#525256", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Maximum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.11372, + 0.05604, + 0.08556, + 0.02548, + 0.05352, + 0.05336, + 0.109, + 0.04112, + 0.05504, + 0.06812, + 0.08644, + null, + null + ], + "last_value": 0.09, + "minimum_value": null, + "maximum_value": 0.11, + "average_value": null + }, + { + "metric_id": 4, + "metric": "Centreon-Server: rtmin", + "metric_legend": "Centreon-Server: rtmin", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#191777", + "ds_color_area": "#191777", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Minimum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.00984, + 0.008, + 0.00784, + 0.00624, + 0.00932, + 0.01348, + 0.01796, + 0.0064, + 0.01148, + 0.01644, + 0.01168, + null, + null + ], + "last_value": 0.01, + "minimum_value": 0.01, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2024-06-19T10:50:00+02:00", + "2024-06-19T10:55:00+02:00", + "2024-06-19T11:00:00+02:00", + "2024-06-19T11:05:00+02:00", + "2024-06-19T11:10:00+02:00", + "2024-06-19T11:15:00+02:00", + "2024-06-19T11:20:00+02:00", + "2024-06-19T11:25:00+02:00", + "2024-06-19T11:30:00+02:00", + "2024-06-19T11:35:00+02:00", + "2024-06-19T11:40:00+02:00", + "2024-06-19T11:45:00+02:00", + "2024-06-19T11:50:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBars.json b/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBars.json new file mode 100644 index 0000000000..a3a2e41023 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBars.json @@ -0,0 +1,245 @@ +{ + "global": { + "base": 1000, + "title": "ping service" + }, + "metrics": [ + { + "metric_id": 2, + "metric": "centreon-server: pl", + "metric_legend": "centreon-server: pl", + "unit": "%", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#f30b23", + "ds_color_area": "#f30b23", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "bar", + "legend": "centreon-server: packet loss", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 10.0, + 20.0, + null, + null + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 10, + "metric": "space used", + "metric_legend": "space used", + "unit": "b", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#654321", + "ds_color_area": "#654321", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "bar", + "legend": "space used", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 7277.536221378278, 1070.9229992641347, 5417.157870751178, + 7650.368581547736, 3062.1382654626154, 6896.485403855089, + 6016.271762192416, 592.4173666516415, 9130.151161464735, + 2556.376532531991, 8085.328518673757, 6283.734720996918, + 5617.226479531896 + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 1, + "metric": "centreon-server: rta", + "metric_legend": "centreon-server: rta", + "unit": "ms", + "min": 0.0, + "max": null, + "ds_data": { + "ds_color_line": "#29afee", + "ds_color_area": "#29afee", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "centreon-server: round-trip average time", + "stack": 0, + "warning_high_threshold": 200.0, + "critical_high_threshold": 400.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.04508, + 0.0242, + 0.03592, + 0.01304, + 0.025, + 0.02748, + 0.05296, + 0.01864, + 0.02688, + 0.03676, + 0.03696, + null, + null + ], + "last_value": 0.04, + "minimum_value": null, + "maximum_value": null, + "average_value": 0.03 + }, + { + "metric_id": 3, + "metric": "centreon-server: rtmax", + "metric_legend": "centreon-server: rtmax", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#525256", + "ds_color_area": "#525256", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "centreon-server: round-trip maximum time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.11372, + 0.05604, + 0.08556, + 0.02548, + 0.05352, + 0.05336, + 0.109, + 0.04112, + 0.05504, + 0.06812, + 0.08644, + null, + null + ], + "last_value": 0.09, + "minimum_value": null, + "maximum_value": 0.11, + "average_value": null + }, + { + "metric_id": 4, + "metric": "centreon-server: rtmin", + "metric_legend": "centreon-server: rtmin", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#191777", + "ds_color_area": "#191777", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "centreon-server: round-trip minimum time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.00984, + 0.008, + 0.00784, + 0.00624, + 0.00932, + 0.01348, + 0.01796, + 0.0064, + 0.01148, + 0.01644, + 0.01168, + null, + null + ], + "last_value": 0.01, + "minimum_value": 0.01, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2024-06-19t10:50:00+02:00", + "2024-06-19t10:55:00+02:00", + "2024-06-19t11:00:00+02:00", + "2024-06-19t11:05:00+02:00", + "2024-06-19t11:10:00+02:00", + "2024-06-19t11:15:00+02:00", + "2024-06-19t11:20:00+02:00", + "2024-06-19t11:25:00+02:00", + "2024-06-19t11:30:00+02:00", + "2024-06-19t11:35:00+02:00", + "2024-06-19t11:40:00+02:00", + "2024-06-19t11:45:00+02:00", + "2024-06-19t11:50:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBarsMixed.json b/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBarsMixed.json new file mode 100644 index 0000000000..fd707b7a47 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBarsMixed.json @@ -0,0 +1,245 @@ +{ + "global": { + "base": 1000, + "title": "Ping service" + }, + "metrics": [ + { + "metric_id": 2, + "metric": "Centreon-Server: pl", + "metric_legend": "Centreon-Server: pl", + "unit": "%", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#F30B23", + "ds_color_area": "#F30B23", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "bar", + "legend": "Centreon-Server: Packet Loss", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 10.0, + 20.0, + null, + null + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 10, + "metric": "Space used", + "metric_legend": "Space used", + "unit": "B", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#654321", + "ds_color_area": "#654321", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "bar", + "legend": "Space used", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 7277.536221378278, 1070.9229992641347, 5417.157870751178, + 7650.368581547736, 3062.1382654626154, 6896.485403855089, + 6016.271762192416, 592.4173666516415, 9130.151161464735, + 2556.376532531991, 8085.328518673757, 6283.734720996918, + 5617.226479531896 + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 1, + "metric": "Centreon-Server: rta", + "metric_legend": "Centreon-Server: rta", + "unit": "ms", + "min": 0.0, + "max": null, + "ds_data": { + "ds_color_line": "#29AFEE", + "ds_color_area": "#29AFEE", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "Centreon-Server: Round-Trip Average Time", + "stack": 0, + "warning_high_threshold": 200.0, + "critical_high_threshold": 400.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.04508, + 0.0242, + 0.03592, + 0.01304, + 0.025, + 0.02748, + 0.05296, + 0.01864, + 0.02688, + 0.03676, + 0.03696, + null, + null + ], + "last_value": 0.04, + "minimum_value": null, + "maximum_value": null, + "average_value": 0.03 + }, + { + "metric_id": 3, + "metric": "Centreon-Server: rtmax", + "metric_legend": "Centreon-Server: rtmax", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#525256", + "ds_color_area": "#525256", + "ds_filled": false, + "ds_invert": true, + "ds_legend": null, + "ds_stack": true, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "Centreon-Server: Round-Trip Maximum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.11372, + 0.05604, + 0.08556, + 0.02548, + 0.05352, + 0.05336, + 0.109, + 0.04112, + 0.05504, + 0.06812, + 0.08644, + null, + null + ], + "last_value": 0.09, + "minimum_value": null, + "maximum_value": 0.11, + "average_value": null + }, + { + "metric_id": 4, + "metric": "Centreon-Server: rtmin", + "metric_legend": "Centreon-Server: rtmin", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#191777", + "ds_color_area": "#191777", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "Centreon-Server: Round-Trip Minimum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.00984, + 0.008, + 0.00784, + 0.00624, + 0.00932, + 0.01348, + 0.01796, + 0.0064, + 0.01148, + 0.01644, + 0.01168, + null, + null + ], + "last_value": 0.01, + "minimum_value": 0.01, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2024-06-19T10:50:00+02:00", + "2024-06-19T10:55:00+02:00", + "2024-06-19T11:00:00+02:00", + "2024-06-19T11:05:00+02:00", + "2024-06-19T11:10:00+02:00", + "2024-06-19T11:15:00+02:00", + "2024-06-19T11:20:00+02:00", + "2024-06-19T11:25:00+02:00", + "2024-06-19T11:30:00+02:00", + "2024-06-19T11:35:00+02:00", + "2024-06-19T11:40:00+02:00", + "2024-06-19T11:45:00+02:00", + "2024-06-19T11:50:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBarsStacked.json b/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBarsStacked.json new file mode 100644 index 0000000000..6e6903326b --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/pingServiceLinesBarsStacked.json @@ -0,0 +1,245 @@ +{ + "global": { + "base": 1000, + "title": "Ping service" + }, + "metrics": [ + { + "metric_id": 2, + "metric": "Centreon-Server: pl", + "metric_legend": "Centreon-Server: pl", + "unit": "B", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#F30B23", + "ds_color_area": "#F30B23", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "bar", + "legend": "Centreon-Server: Packet Loss", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 1243.0, + 3562.0, + 3532.0, + 9843.0, + 3332.0, + 6576.0, + 5647.0, + 8763.0, + 7487.0, + 4783.0, + 6835.0, + null, + null + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 10, + "metric": "Space used", + "metric_legend": "Space used", + "unit": "B", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#654321", + "ds_color_area": "#654321", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "bar", + "legend": "Space used", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 7277.536221378278, 1070.9229992641347, 5417.157870751178, + 7650.368581547736, 3062.1382654626154, 6896.485403855089, + 6016.271762192416, 592.4173666516415, 9130.151161464735, + 2556.376532531991, 8085.328518673757, 6283.734720996918, + 5617.226479531896 + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 1, + "metric": "Centreon-Server: rta", + "metric_legend": "Centreon-Server: rta", + "unit": "ms", + "min": 0.0, + "max": null, + "ds_data": { + "ds_color_line": "#29AFEE", + "ds_color_area": "#29AFEE", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "Centreon-Server: Round-Trip Average Time", + "stack": 0, + "warning_high_threshold": 200.0, + "critical_high_threshold": 400.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.04508, + 0.0242, + 0.03592, + 0.01304, + 0.025, + 0.02748, + 0.05296, + 0.01864, + 0.02688, + 0.03676, + 0.03696, + null, + null + ], + "last_value": 0.04, + "minimum_value": null, + "maximum_value": null, + "average_value": 0.03 + }, + { + "metric_id": 3, + "metric": "Centreon-Server: rtmax", + "metric_legend": "Centreon-Server: rtmax", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#525256", + "ds_color_area": "#525256", + "ds_filled": false, + "ds_invert": true, + "ds_legend": null, + "ds_stack": true, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "Centreon-Server: Round-Trip Maximum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.11372, + 0.05604, + 0.08556, + 0.02548, + 0.05352, + 0.05336, + 0.109, + 0.04112, + 0.05504, + 0.06812, + 0.08644, + null, + null + ], + "last_value": 0.09, + "minimum_value": null, + "maximum_value": 0.11, + "average_value": null + }, + { + "metric_id": 4, + "metric": "Centreon-Server: rtmin", + "metric_legend": "Centreon-Server: rtmin", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#191777", + "ds_color_area": "#191777", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "displayAs": "line", + "legend": "Centreon-Server: Round-Trip Minimum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.00984, + 0.008, + 0.00784, + 0.00624, + 0.00932, + 0.01348, + 0.01796, + 0.0064, + 0.01148, + 0.01644, + 0.01168, + null, + null + ], + "last_value": 0.01, + "minimum_value": 0.01, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2024-06-19T10:50:00+02:00", + "2024-06-19T10:55:00+02:00", + "2024-06-19T11:00:00+02:00", + "2024-06-19T11:05:00+02:00", + "2024-06-19T11:10:00+02:00", + "2024-06-19T11:15:00+02:00", + "2024-06-19T11:20:00+02:00", + "2024-06-19T11:25:00+02:00", + "2024-06-19T11:30:00+02:00", + "2024-06-19T11:35:00+02:00", + "2024-06-19T11:40:00+02:00", + "2024-06-19T11:45:00+02:00", + "2024-06-19T11:50:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/pingServiceMixedStacked.json b/centreon/packages/ui/src/Graph/mockedData/pingServiceMixedStacked.json new file mode 100644 index 0000000000..09e62c9985 --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/pingServiceMixedStacked.json @@ -0,0 +1,240 @@ +{ + "global": { + "base": 1000, + "title": "Ping service" + }, + "metrics": [ + { + "metric_id": 10, + "metric": "Space used", + "metric_legend": "Space used", + "unit": "B", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#654321", + "ds_color_area": "#654321", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Space used", + "stack": 1, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 7277.536221378278, 1070.9229992641347, 5417.157870751178, + 7650.368581547736, 3062.1382654626154, 6896.485403855089, + 6016.271762192416, 592.4173666516415, 9130.151161464735, + 2556.376532531991, 8085.328518673757, 6283.734720996918, + 5617.226479531896 + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 2, + "metric": "Centreon-Server: pl", + "metric_legend": "Centreon-Server: pl", + "unit": "%", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#F30B23", + "ds_color_area": "#F30B23", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Packet Loss", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 10.0, + 20.0, + null, + null + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 1, + "metric": "Centreon-Server: rta", + "metric_legend": "Centreon-Server: rta", + "unit": "ms", + "min": 0.0, + "max": null, + "ds_data": { + "ds_color_line": "#29AFEE", + "ds_color_area": "#29AFEE", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Average Time", + "stack": 0, + "warning_high_threshold": 200.0, + "critical_high_threshold": 400.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.04508, + 0.0242, + 0.03592, + 0.01304, + 0.025, + 0.02748, + 0.05296, + 0.01864, + 0.02688, + 0.03676, + 0.03696, + null, + null + ], + "last_value": 0.04, + "minimum_value": null, + "maximum_value": null, + "average_value": 0.03 + }, + { + "metric_id": 3, + "metric": "Centreon-Server: rtmax", + "metric_legend": "Centreon-Server: rtmax", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#525256", + "ds_color_area": "#525256", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Maximum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.11372, + 0.05604, + 0.08556, + 0.02548, + 0.05352, + 0.05336, + 0.109, + 0.04112, + 0.05504, + 0.06812, + 0.08644, + null, + null + ], + "last_value": 0.09, + "minimum_value": null, + "maximum_value": 0.11, + "average_value": null + }, + { + "metric_id": 4, + "metric": "Centreon-Server: rtmin", + "metric_legend": "Centreon-Server: rtmin", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#191777", + "ds_color_area": "#191777", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Minimum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.00984, + 0.008, + 0.00784, + 0.00624, + 0.00932, + 0.01348, + 0.01796, + 0.0064, + 0.01148, + 0.01644, + 0.01168, + null, + null + ], + "last_value": 0.01, + "minimum_value": 0.01, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2024-06-19T10:50:00+02:00", + "2024-06-19T10:55:00+02:00", + "2024-06-19T11:00:00+02:00", + "2024-06-19T11:05:00+02:00", + "2024-06-19T11:10:00+02:00", + "2024-06-19T11:15:00+02:00", + "2024-06-19T11:20:00+02:00", + "2024-06-19T11:25:00+02:00", + "2024-06-19T11:30:00+02:00", + "2024-06-19T11:35:00+02:00", + "2024-06-19T11:40:00+02:00", + "2024-06-19T11:45:00+02:00", + "2024-06-19T11:50:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/pingServiceStacked.json b/centreon/packages/ui/src/Graph/mockedData/pingServiceStacked.json new file mode 100644 index 0000000000..47115ae99b --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/pingServiceStacked.json @@ -0,0 +1,240 @@ +{ + "global": { + "base": 1000, + "title": "Ping service" + }, + "metrics": [ + { + "metric_id": 2, + "metric": "Centreon-Server: pl", + "metric_legend": "Centreon-Server: pl", + "unit": "%", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#F30B23", + "ds_color_area": "#F30B23", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Packet Loss", + "stack": 0, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -10.0, + 20.0, + null, + null + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 10, + "metric": "Space used", + "metric_legend": "Space used", + "unit": "B", + "min": 0.0, + "max": 100.0, + "ds_data": { + "ds_color_line": "#654321", + "ds_color_area": "#654321", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": false, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Space used", + "stack": 1, + "warning_high_threshold": 20.0, + "critical_high_threshold": 50.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 2, + "data": [ + 7277.536221378278, 1070.9229992641347, 5417.157870751178, + 7650.368581547736, 3062.1382654626154, 6896.485403855089, + 6016.271762192416, 592.4173666516415, 9130.151161464735, + 2556.376532531991, 8085.328518673757, 6283.734720996918, + 5617.226479531896 + ], + "last_value": 0.0, + "minimum_value": null, + "maximum_value": 0.0, + "average_value": 0.0 + }, + { + "metric_id": 1, + "metric": "Centreon-Server: rta", + "metric_legend": "Centreon-Server: rta", + "unit": "ms", + "min": 0.0, + "max": null, + "ds_data": { + "ds_color_line": "#29AFEE", + "ds_color_area": "#29AFEE", + "ds_filled": true, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 1, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Average Time", + "stack": 0, + "warning_high_threshold": 200.0, + "critical_high_threshold": 400.0, + "warning_low_threshold": 0.0, + "critical_low_threshold": 0.0, + "ds_order": 1, + "data": [ + 0.04508, + 0.0242, + 0.03592, + 0.01304, + 0.025, + 0.02748, + 0.05296, + 0.01864, + 0.02688, + 0.03676, + 0.03696, + null, + null + ], + "last_value": 0.04, + "minimum_value": null, + "maximum_value": null, + "average_value": 0.03 + }, + { + "metric_id": 3, + "metric": "Centreon-Server: rtmax", + "metric_legend": "Centreon-Server: rtmax", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#525256", + "ds_color_area": "#525256", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Maximum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.11372, + 0.05604, + 0.08556, + 0.02548, + 0.05352, + 0.05336, + 0.109, + 0.04112, + 0.05504, + 0.06812, + 0.08644, + null, + null + ], + "last_value": 0.09, + "minimum_value": null, + "maximum_value": 0.11, + "average_value": null + }, + { + "metric_id": 4, + "metric": "Centreon-Server: rtmin", + "metric_legend": "Centreon-Server: rtmin", + "unit": "ms", + "min": null, + "max": null, + "ds_data": { + "ds_color_line": "#191777", + "ds_color_area": "#191777", + "ds_filled": false, + "ds_invert": false, + "ds_legend": null, + "ds_stack": true, + "ds_order": 2, + "ds_transparency": 80.0, + "ds_color_line_mode": 0 + }, + "legend": "Centreon-Server: Round-Trip Minimum Time", + "stack": 0, + "warning_high_threshold": null, + "critical_high_threshold": null, + "warning_low_threshold": null, + "critical_low_threshold": null, + "ds_order": 2, + "data": [ + 0.00984, + 0.008, + 0.00784, + 0.00624, + 0.00932, + 0.01348, + 0.01796, + 0.0064, + 0.01148, + 0.01644, + 0.01168, + null, + null + ], + "last_value": 0.01, + "minimum_value": 0.01, + "maximum_value": null, + "average_value": null + } + ], + "times": [ + "2024-06-19T10:50:00+02:00", + "2024-06-19T10:55:00+02:00", + "2024-06-19T11:00:00+02:00", + "2024-06-19T11:05:00+02:00", + "2024-06-19T11:10:00+02:00", + "2024-06-19T11:15:00+02:00", + "2024-06-19T11:20:00+02:00", + "2024-06-19T11:25:00+02:00", + "2024-06-19T11:30:00+02:00", + "2024-06-19T11:35:00+02:00", + "2024-06-19T11:40:00+02:00", + "2024-06-19T11:45:00+02:00", + "2024-06-19T11:50:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Graph/mockedData/zoomPreview.json b/centreon/packages/ui/src/Graph/mockedData/zoomPreview.json new file mode 100644 index 0000000000..558316156f --- /dev/null +++ b/centreon/packages/ui/src/Graph/mockedData/zoomPreview.json @@ -0,0 +1,372 @@ +{ + "global": { + "title": "oracle-shared-spool-ratio graph on srv-oracle-users", + "start": "2023-06-01T23:54:23+02:00", + "end": "2023-06-02T11:29:24+02:00", + "vertical-label": "Value", + "base": 1000, + "width": 550, + "height": 140, + "scaled": 0, + "multiple_services": false + }, + "metrics": [ + { + "index_id": 4811, + "metric_id": 11758, + "metric": "connTime", + "metric_legend": "connTime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#ff99cc" + }, + "legend": "connTime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.56718666667, 0.30173333333, 0.25002666667, 0.49318666667, + 0.38298666667, 0.73857333333, 0.12757333333, 0.87394666667, 0.25628, + 0.38088, 0.70997333333, 0.38341333333, 0.22105333333, 0.39570666667, + 0.26684, 0.81090666667, 0.56462666667, 0.61432, 0.037693333333, + 0.73582666667, 0.76090666667, 0.24122666667, 0.24229333333, + 0.078333333333, 0.28768, 0.27822666667, 0.20410666667, 0.27005333333, + 0.5438, 0.63, 0.16918666667, 0.33612, 0.18606666667, 0.55945333333, + 0.24682666667, 0.14942666667, 0.063586666667, 0.026813333333, 0.1102, + 0.80133333333, 0.49825333333, 0.41462666667, 0.066413333333, 0.77688, + 0.53873333333, 0.95846666667, 0.202, 0.34449333333, 0.53013333333, + 0.10358666667, 0.91396, 0.25573333333, 0.17638, 0.44002, 0.50977, + 0.098876666667, 0.16456, 0.75581, 0.67874333333, 0.10694333333, + 0.88898333333, 0.54368666667, 0.96525333333, 0.72881, 0.30359333333, + 0.22523, 0.51537666667, 0.48394666667, 0.96304333333, 0.86087666667, + 0.15870666667, 0.42924333333, 0.88948, 0.071716666667, 0.14552, 0.02565, + 0.27741666667, 0.88069666667, 0.73016333333, 0.15583, 0.82667, 0.0766, + 0.70442666667, 0.51388333333, 0.12266666667, 0.53865, 0.45085666667, + 0.60248, 0.72897333333, 0.30018, 0.58435666667, 0.25868333333, 0.03707, + 0.53251333333, 0.11963333333, 0.10149, 0.61234333333, 0.11096, + 0.28370333333, 0.025263333333, 0.83724666667, 0.92001666667, 0.22016, + 0.77135666667, 0.85794, 0.83458666667, 0.6349, 0.60224666667, + 0.26517333333, 0.69308333333, 0.94262666667, 0.94751, 0.60268333333, + 0.084863333333, 0.77193333333, 0.49709666667, 0.41857, 0.57631, + 0.55958666667, 0.22972, 0.34301, 0.91417, 0.15937333333, 0.94685, + 0.80927666667, 0.5433, 0.68836666667, 0.045213333333, 0.20221333333, + 0.25928, 0.028996666667, 0.55647333333, 0.53334333333, 0.070596666667, + 0.37599666667, 0.55636666667, 0.92541, 0.54608333333, 0.40597, 0.78954 + ], + "prints": [["Last:0.79"], ["Min:0.03"], ["Max:0.97"], ["Average:0.45"]], + "last_value": 0.79, + "minimum_value": 0.03, + "maximum_value": 0.97, + "average_value": 0.45 + }, + { + "index_id": 4811, + "metric_id": 11757, + "metric": "querytime", + "metric_legend": "querytime", + "unit": "s", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "ds_min": "1", + "ds_max": "1", + "ds_minmax_int": "0", + "ds_last": "1", + "ds_average": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_color_line_mode": "1", + "ds_color_line": "#6666ff" + }, + "legend": "querytime", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 0, + "data": [ + 0.21217333333, 0.87482666667, 0.37050666667, 0.22261333333, + 0.27658666667, 0.89249333333, 0.42810666667, 0.17090666667, 0.19776, + 0.66197333333, 0.74858666667, 0.16696, 0.069626666667, 0.47496, 0.2282, + 0.0994, 0.64774666667, 0.66953333333, 0.77124, 0.3936, 0.15710666667, + 0.93925333333, 0.20773333333, 0.071226666667, 0.41626666667, + 0.21069333333, 0.6382, 0.44053333333, 0.60597333333, 0.21082666667, + 0.47862666667, 0.29146666667, 0.209, 0.65845333333, 0.04784, + 0.76081333333, 0.65816, 0.73236, 0.28733333333, 0.59522666667, + 0.62157333333, 0.31906666667, 0.18461333333, 0.26982666667, + 0.040226666667, 0.59405333333, 0.90810666667, 0.78957333333, + 0.80093333333, 0.86164, 0.1834, 0.018146666667, 0.72887666667, 0.08997, + 0.00938, 0.26547333333, 0.70833, 0.39817333333, 0.76854, 0.04771, + 0.083183333333, 0.62004, 0.63879333333, 0.82478, 0.11057666667, + 0.084923333333, 0.49069, 0.54518666667, 0.23475666667, 0.20845333333, + 0.23913, 0.13912, 0.51599333333, 0.081483333333, 0.69169333333, 0.74981, + 0.28310666667, 0.27764, 0.67425666667, 0.26406666667, 0.16725, + 0.39128666667, 0.76818333333, 0.89565333333, 0.85860666667, 0.89279, + 0.55445666667, 0.45664666667, 0.85574666667, 0.05364, 0.59358333333, + 0.29600333333, 0.050543333333, 0.33603666667, 0.05402, 0.63879, + 0.65424666667, 0.48697333333, 0.57888, 0.87366, 0.76553666667, + 0.79290333333, 0.19598333333, 0.070383333333, 0.51874333333, + 0.077163333333, 0.81027, 0.29754666667, 0.74227, 0.14934333333, + 0.27802666667, 0.43610333333, 0.76007333333, 0.96106333333, + 0.30789333333, 0.44346, 0.66247666667, 0.20710666667, 0.91763, + 0.39694333333, 0.43186333333, 0.18601666667, 0.22477, 0.93644333333, + 0.53752, 0.71947666667, 0.15373666667, 0.28785666667, 0.09141, 0.27427, + 0.76049666667, 0.46826666667, 0.54427666667, 0.59150666667, + 0.72795333333, 0.67562666667, 0.97103666667, 0.065476666667, + 0.35148666667, 0.81253666667 + ], + "prints": [["Last:0.81"], ["Min:0.01"], ["Max:0.97"], ["Average:0.45"]], + "last_value": 0.81, + "minimum_value": 0.01, + "maximum_value": 0.97, + "average_value": 0.45 + }, + { + "index_id": 4811, + "metric_id": 11756, + "metric": "used", + "metric_legend": "used", + "unit": "%", + "hidden": 0, + "min": null, + "max": null, + "virtual": 0, + "ds_data": { + "compo_id": 8, + "host_id": null, + "service_id": null, + "name": "Used", + "ds_order": 1, + "ds_hidecurve": null, + "ds_name": "used", + "ds_color_line": "#2B28D7", + "ds_color_line_mode": "0", + "ds_color_area": "#050AF9", + "ds_color_area_warn": null, + "ds_color_area_crit": null, + "ds_filled": "1", + "ds_max": null, + "ds_min": null, + "ds_minmax_int": "0", + "ds_average": "1", + "ds_last": "1", + "ds_total": "0", + "ds_tickness": 1, + "ds_transparency": "80", + "ds_invert": null, + "ds_legend": null, + "ds_jumpline": "0", + "ds_stack": null, + "default_tpl1": null, + "comment": null + }, + "legend": "used", + "stack": 0, + "warn": null, + "warn_low": null, + "crit": null, + "crit_low": null, + "ds_color_area_warn": "#ff9a13", + "ds_color_area_crit": "#e00b3d", + "ds_order": 1, + "data": [ + 91.596026667, 90.088853333, 89.076053333, 90.53204, 90.893426667, + 89.506986667, 90.81108, 90.729013333, 92.19964, 93.897066667, + 95.224346667, 94.630386667, 95.821773333, 96.9134, 97.077026667, + 97.41528, 97.024093333, 96.81924, 97.259613333, 98.342426667, + 99.564506667, 98.086933333, 96.482493333, 95.24396, 95.435546667, + 94.196613333, 95.7448, 96.646346667, 95.380866667, 94.330986667, + 93.289573333, 94.292373333, 93.915586667, 93.01628, 93.919346667, + 92.278466667, 93.340773333, 95.046573333, 95.62464, 94.912653333, + 93.616666667, 93.305546667, 91.418546667, 90.48372, 91.884453333, + 91.26452, 93.03976, 94.966226667, 95.96928, 95.0118, 93.965733333, + 92.588453333, 90.644313333, 89.90091, 88.758356667, 88.809916667, + 87.401056667, 89.171536667, 88.56418, 90.24447, 92.145993333, + 90.846546667, 89.730936667, 91.40096, 92.009683333, 93.402173333, + 94.77448, 94.395426667, 95.178323333, 94.597796667, 93.762883333, + 94.440423333, 96.117853333, 98.09795, 98.096856667, 98.0051, 97.2076, + 96.59683, 95.66872, 94.895236667, 94.183176667, 95.20991, 93.487326667, + 95.11196, 96.17254, 95.36402, 95.04598, 95.81108, 96.592856667, + 97.519016667, 95.694766667, 93.71986, 92.31186, 92.297203333, + 93.977303333, 94.92134, 94.19941, 94.312423333, 93.282446667, + 92.786066667, 91.01389, 92.46833, 93.794936667, 93.967106667, 95.2182, + 95.01283, 94.80073, 93.796613333, 93.586066667, 95.26651, 94.24732, + 94.895046667, 94.41728, 92.538953333, 91.597866667, 91.568753333, + 92.31712, 92.778953333, 91.32957, 90.589156667, 89.515163333, + 90.598206667, 89.587826667, 88.00329, 89.227006667, 89.304113333, + 89.37475, 87.6527, 87.395236667, 85.901193333, 87.65716, 89.258466667, + 90.305483333, 90.81863, 92.16478, 93.21469, 93.78806, 92.083266667, + 92.926106667, 91.584036667 + ], + "prints": [["Last:91.58"], ["Average:93.26"]], + "last_value": 91.58, + "minimum_value": null, + "maximum_value": null, + "average_value": 93.26 + } + ], + "times": [ + "2023-06-01T23:55:00+02:00", + "2023-06-02T00:00:00+02:00", + "2023-06-02T00:05:00+02:00", + "2023-06-02T00:10:00+02:00", + "2023-06-02T00:15:00+02:00", + "2023-06-02T00:20:00+02:00", + "2023-06-02T00:25:00+02:00", + "2023-06-02T00:30:00+02:00", + "2023-06-02T00:35:00+02:00", + "2023-06-02T00:40:00+02:00", + "2023-06-02T00:45:00+02:00", + "2023-06-02T00:50:00+02:00", + "2023-06-02T00:55:00+02:00", + "2023-06-02T01:00:00+02:00", + "2023-06-02T01:05:00+02:00", + "2023-06-02T01:10:00+02:00", + "2023-06-02T01:15:00+02:00", + "2023-06-02T01:20:00+02:00", + "2023-06-02T01:25:00+02:00", + "2023-06-02T01:30:00+02:00", + "2023-06-02T01:35:00+02:00", + "2023-06-02T01:40:00+02:00", + "2023-06-02T01:45:00+02:00", + "2023-06-02T01:50:00+02:00", + "2023-06-02T01:55:00+02:00", + "2023-06-02T02:00:00+02:00", + "2023-06-02T02:05:00+02:00", + "2023-06-02T02:10:00+02:00", + "2023-06-02T02:15:00+02:00", + "2023-06-02T02:20:00+02:00", + "2023-06-02T02:25:00+02:00", + "2023-06-02T02:30:00+02:00", + "2023-06-02T02:35:00+02:00", + "2023-06-02T02:40:00+02:00", + "2023-06-02T02:45:00+02:00", + "2023-06-02T02:50:00+02:00", + "2023-06-02T02:55:00+02:00", + "2023-06-02T03:00:00+02:00", + "2023-06-02T03:05:00+02:00", + "2023-06-02T03:10:00+02:00", + "2023-06-02T03:15:00+02:00", + "2023-06-02T03:20:00+02:00", + "2023-06-02T03:25:00+02:00", + "2023-06-02T03:30:00+02:00", + "2023-06-02T03:35:00+02:00", + "2023-06-02T03:40:00+02:00", + "2023-06-02T03:45:00+02:00", + "2023-06-02T03:50:00+02:00", + "2023-06-02T03:55:00+02:00", + "2023-06-02T04:00:00+02:00", + "2023-06-02T04:05:00+02:00", + "2023-06-02T04:10:00+02:00", + "2023-06-02T04:15:00+02:00", + "2023-06-02T04:20:00+02:00", + "2023-06-02T04:25:00+02:00", + "2023-06-02T04:30:00+02:00", + "2023-06-02T04:35:00+02:00", + "2023-06-02T04:40:00+02:00", + "2023-06-02T04:45:00+02:00", + "2023-06-02T04:50:00+02:00", + "2023-06-02T04:55:00+02:00", + "2023-06-02T05:00:00+02:00", + "2023-06-02T05:05:00+02:00", + "2023-06-02T05:10:00+02:00", + "2023-06-02T05:15:00+02:00", + "2023-06-02T05:20:00+02:00", + "2023-06-02T05:25:00+02:00", + "2023-06-02T05:30:00+02:00", + "2023-06-02T05:35:00+02:00", + "2023-06-02T05:40:00+02:00", + "2023-06-02T05:45:00+02:00", + "2023-06-02T05:50:00+02:00", + "2023-06-02T05:55:00+02:00", + "2023-06-02T06:00:00+02:00", + "2023-06-02T06:05:00+02:00", + "2023-06-02T06:10:00+02:00", + "2023-06-02T06:15:00+02:00", + "2023-06-02T06:20:00+02:00", + "2023-06-02T06:25:00+02:00", + "2023-06-02T06:30:00+02:00", + "2023-06-02T06:35:00+02:00", + "2023-06-02T06:40:00+02:00", + "2023-06-02T06:45:00+02:00", + "2023-06-02T06:50:00+02:00", + "2023-06-02T06:55:00+02:00", + "2023-06-02T07:00:00+02:00", + "2023-06-02T07:05:00+02:00", + "2023-06-02T07:10:00+02:00", + "2023-06-02T07:15:00+02:00", + "2023-06-02T07:20:00+02:00", + "2023-06-02T07:25:00+02:00", + "2023-06-02T07:30:00+02:00", + "2023-06-02T07:35:00+02:00", + "2023-06-02T07:40:00+02:00", + "2023-06-02T07:45:00+02:00", + "2023-06-02T07:50:00+02:00", + "2023-06-02T07:55:00+02:00", + "2023-06-02T08:00:00+02:00", + "2023-06-02T08:05:00+02:00", + "2023-06-02T08:10:00+02:00", + "2023-06-02T08:15:00+02:00", + "2023-06-02T08:20:00+02:00", + "2023-06-02T08:25:00+02:00", + "2023-06-02T08:30:00+02:00", + "2023-06-02T08:35:00+02:00", + "2023-06-02T08:40:00+02:00", + "2023-06-02T08:45:00+02:00", + "2023-06-02T08:50:00+02:00", + "2023-06-02T08:55:00+02:00", + "2023-06-02T09:00:00+02:00", + "2023-06-02T09:05:00+02:00", + "2023-06-02T09:10:00+02:00", + "2023-06-02T09:15:00+02:00", + "2023-06-02T09:20:00+02:00", + "2023-06-02T09:25:00+02:00", + "2023-06-02T09:30:00+02:00", + "2023-06-02T09:35:00+02:00", + "2023-06-02T09:40:00+02:00", + "2023-06-02T09:45:00+02:00", + "2023-06-02T09:50:00+02:00", + "2023-06-02T09:55:00+02:00", + "2023-06-02T10:00:00+02:00", + "2023-06-02T10:05:00+02:00", + "2023-06-02T10:10:00+02:00", + "2023-06-02T10:15:00+02:00", + "2023-06-02T10:20:00+02:00", + "2023-06-02T10:25:00+02:00", + "2023-06-02T10:30:00+02:00", + "2023-06-02T10:35:00+02:00", + "2023-06-02T10:40:00+02:00", + "2023-06-02T10:45:00+02:00", + "2023-06-02T10:50:00+02:00", + "2023-06-02T10:55:00+02:00", + "2023-06-02T11:00:00+02:00", + "2023-06-02T11:05:00+02:00", + "2023-06-02T11:10:00+02:00", + "2023-06-02T11:15:00+02:00", + "2023-06-02T11:20:00+02:00", + "2023-06-02T11:25:00+02:00", + "2023-06-02T11:30:00+02:00" + ] +} diff --git a/centreon/packages/ui/src/Home.mdx b/centreon/packages/ui/src/Home.mdx new file mode 100644 index 0000000000..4039f649f3 --- /dev/null +++ b/centreon/packages/ui/src/Home.mdx @@ -0,0 +1,41 @@ +{/* Home.mdx */} + +import { Meta } from '@storybook/addon-docs' +import { Typography, Link, Stack } from '@mui/material' + + + + +Welcome to Centreon UI +
+ +This project contains design system's component used in every Centreon projects using ReactJS +
+ +Discover older versions of the Centreon UI's storybook + + + Latest + + + 23.04 + + + 22.10 + + + 22.04 + + + 21.10 + + + 21.04 + + + 20.10 + + + 20.04 + + diff --git a/centreon/packages/ui/src/Home.stories.mdx b/centreon/packages/ui/src/Home.stories.mdx deleted file mode 100644 index bf765ffd77..0000000000 --- a/centreon/packages/ui/src/Home.stories.mdx +++ /dev/null @@ -1,39 +0,0 @@ -import { Meta } from '@storybook/addon-docs' -import { Typography, Link, Stack } from '@mui/material' - - - - -Welcome to Centreon UI -
- -This project contains design system's component used in every Centreon projects using ReactJS -
- -Discover older versions of the Centreon UI's storybook - - - Latest - - - 23.04 - - - 22.10 - - - 22.04 - - - 21.10 - - - 21.04 - - - 20.10 - - - 20.04 - - diff --git a/centreon/packages/ui/src/Icon/AcnowledgementIcon.tsx b/centreon/packages/ui/src/Icon/AcnowledgementIcon.tsx new file mode 100644 index 0000000000..65def135a5 --- /dev/null +++ b/centreon/packages/ui/src/Icon/AcnowledgementIcon.tsx @@ -0,0 +1,8 @@ +import { Person } from '@mui/icons-material'; +import { SvgIconProps } from '@mui/material'; + +import BaseIcon from './BaseIcon'; + +export const AcknowledgementIcon = (props: SvgIconProps): JSX.Element => ( + +); diff --git a/centreon/packages/ui/src/Icon/BaseIcon.tsx b/centreon/packages/ui/src/Icon/BaseIcon.tsx new file mode 100644 index 0000000000..0336153508 --- /dev/null +++ b/centreon/packages/ui/src/Icon/BaseIcon.tsx @@ -0,0 +1,32 @@ +import { has } from 'ramda'; + +import { SvgIcon, SvgIconProps, SvgIconTypeMap } from '@mui/material'; +import { OverridableComponent } from '@mui/material/OverridableComponent'; + +interface Props extends SvgIconProps { + Icon: JSX.Element | OverridableComponent; + dataTestId?: string; +} + +const BaseIcon = ({ Icon, dataTestId, ...props }: Props): JSX.Element => { + if (!has('key', Icon)) { + const Component = Icon as (props: SvgIconProps) => JSX.Element; + + return ( + JSX.Element).name} + {...props} + > + + + ); + } + + return ( + + {Icon as JSX.Element} + + ); +}; + +export default BaseIcon; diff --git a/centreon/packages/ui/src/Icon/DowntimeIcon.tsx b/centreon/packages/ui/src/Icon/DowntimeIcon.tsx new file mode 100644 index 0000000000..958f1323fb --- /dev/null +++ b/centreon/packages/ui/src/Icon/DowntimeIcon.tsx @@ -0,0 +1,14 @@ +import { SvgIconProps } from '@mui/material'; + +import BaseIcon from './BaseIcon'; + +const icon = ( + + + + +); + +export const DowntimeIcon = (props: SvgIconProps): JSX.Element => ( + +); diff --git a/centreon/packages/ui/src/Icon/HostIcon.tsx b/centreon/packages/ui/src/Icon/HostIcon.tsx new file mode 100644 index 0000000000..68f6b40200 --- /dev/null +++ b/centreon/packages/ui/src/Icon/HostIcon.tsx @@ -0,0 +1,8 @@ +import { Dns } from '@mui/icons-material'; +import { SvgIconProps } from '@mui/material'; + +import BaseIcon from './BaseIcon'; + +export const HostIcon = (props: SvgIconProps): JSX.Element => ( + +); diff --git a/centreon/packages/ui/src/Icon/IconAttach/index.tsx b/centreon/packages/ui/src/Icon/IconAttach/index.tsx index 46f3e516b0..bdc0b5097e 100644 --- a/centreon/packages/ui/src/Icon/IconAttach/index.tsx +++ b/centreon/packages/ui/src/Icon/IconAttach/index.tsx @@ -1,6 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ - import { makeStyles } from 'tss-react/mui'; const useStyles = makeStyles()((theme) => ({ @@ -45,13 +42,11 @@ interface Props { defaultImage: string; imgSource: string; labelNoIcon?: string; - onClick: () => void; title: string; uploadedImage: string; } const IconAttach = ({ - onClick, defaultImage, uploadedImage, imgSource, @@ -61,7 +56,7 @@ const IconAttach = ({ const { classes } = useStyles(); return ( - + {defaultImage && ( {labelNoIcon} )} diff --git a/centreon/packages/ui/src/Icon/ServiceIcon.tsx b/centreon/packages/ui/src/Icon/ServiceIcon.tsx new file mode 100644 index 0000000000..906597a660 --- /dev/null +++ b/centreon/packages/ui/src/Icon/ServiceIcon.tsx @@ -0,0 +1,8 @@ +import { Grain } from '@mui/icons-material'; +import { SvgIconProps } from '@mui/material'; + +import BaseIcon from './BaseIcon'; + +export const ServiceIcon = (props: SvgIconProps): JSX.Element => ( + +); diff --git a/centreon/packages/ui/src/Icon/index.ts b/centreon/packages/ui/src/Icon/index.ts new file mode 100644 index 0000000000..fbc4100295 --- /dev/null +++ b/centreon/packages/ui/src/Icon/index.ts @@ -0,0 +1,4 @@ +export { HostIcon } from './HostIcon'; +export { ServiceIcon } from './ServiceIcon'; +export { DowntimeIcon } from './DowntimeIcon'; +export { AcknowledgementIcon } from './AcnowledgementIcon'; diff --git a/centreon/packages/ui/src/Image/Image.tsx b/centreon/packages/ui/src/Image/Image.tsx index 994e814101..42db3ed4b4 100644 --- a/centreon/packages/ui/src/Image/Image.tsx +++ b/centreon/packages/ui/src/Image/Image.tsx @@ -1,75 +1,75 @@ -import { memo } from 'react'; - -import { makeStyles } from 'tss-react/mui'; -import { equals, isNil } from 'ramda'; - -import { useLoadImage } from './useLoadImage'; - -export enum ImageVariant { - Contain = 'contain', - Cover = 'cover' -} - -interface Props { - alt: string; - className?: string; - fallback: JSX.Element; - height?: number | string; - imagePath: string; - variant?: ImageVariant; - width?: number | string; -} - -const useStyles = makeStyles>()( - (_, { width, height, variant }) => ({ - fallbackContainer: { - height: '100%', - width: '100%' - }, - imageContent: { - height, - objectFit: variant, - width - } - }) -); - -const ImageContent = ({ - alt, - className, - height, - width, - imagePath, - variant = ImageVariant.Cover, - fallback -}: Props): JSX.Element => { - const { classes, cx } = useStyles({ height, variant, width }); - const isImageLoaded = useLoadImage({ alt, imageSrc: imagePath }); - - if (!isImageLoaded) { - return ( -
- {fallback} -
- ); - } - - return ( - {alt} - ); -}; - -const SuspendedImage = ({ imagePath, ...props }: Props): JSX.Element | null => { - if (isNil(imagePath)) { - return null; - } - - return ; -}; - -export default memo(SuspendedImage, equals); +import { memo } from 'react'; + +import { equals, isNil } from 'ramda'; +import { makeStyles } from 'tss-react/mui'; + +import { useLoadImage } from './useLoadImage'; + +export enum ImageVariant { + Contain = 'contain', + Cover = 'cover' +} + +interface Props { + alt: string; + className?: string; + fallback: JSX.Element; + height?: number | string; + imagePath: string; + variant?: ImageVariant; + width?: number | string; +} + +const useStyles = makeStyles>()( + (_, { width, height, variant }) => ({ + fallbackContainer: { + height: '100%', + width: '100%' + }, + imageContent: { + height, + objectFit: variant, + width + } + }) +); + +const ImageContent = ({ + alt, + className, + height, + width, + imagePath, + variant = ImageVariant.Cover, + fallback +}: Props): JSX.Element => { + const { classes, cx } = useStyles({ height, variant, width }); + const isImageLoaded = useLoadImage({ alt, imageSrc: imagePath }); + + if (!isImageLoaded) { + return ( +
+ {fallback} +
+ ); + } + + return ( + {alt} + ); +}; + +const SuspendedImage = ({ imagePath, ...props }: Props): JSX.Element | null => { + if (isNil(imagePath)) { + return null; + } + + return ; +}; + +export default memo(SuspendedImage, equals); diff --git a/centreon/packages/ui/src/Image/atoms.ts b/centreon/packages/ui/src/Image/atoms.ts index b7370a1364..8fa7ab0a9b 100644 --- a/centreon/packages/ui/src/Image/atoms.ts +++ b/centreon/packages/ui/src/Image/atoms.ts @@ -1,3 +1,3 @@ -import { atom } from 'jotai'; - -export const imagesAtom = atom>({}); +import { atom } from 'jotai'; + +export const imagesAtom = atom>({}); diff --git a/centreon/packages/ui/src/Image/index.stories.tsx b/centreon/packages/ui/src/Image/index.stories.tsx index d24759c0c2..d3052d4c27 100644 --- a/centreon/packages/ui/src/Image/index.stories.tsx +++ b/centreon/packages/ui/src/Image/index.stories.tsx @@ -1,101 +1,101 @@ -import { ComponentStory } from '@storybook/react'; - -import LoadingSkeleton from '../LoadingSkeleton'; -import CentreonLogoLight from '../@assets/brand/centreon-logo-one-line-light.svg'; -import NotAuthorized from '../@assets/images/not-authorized-template-background-light.svg'; - -import Image, { ImageVariant } from './Image'; - -export default { - argTypes: { - alt: { control: 'text' }, - height: { control: 'number' }, - width: { control: 'number' } - }, - component: Image, - - title: 'Image' -}; - -const Template: ComponentStory = (args) => ( - } - imagePath={CentreonLogoLight} - /> -); - -const size = 50; - -export const basic = Template.bind({}); -basic.args = { - alt: 'Centreon logo light' -}; - -export const multipleImages = (): JSX.Element => { - return ( -
- Centreon logo light} - height={size} - imagePath={CentreonLogoLight} - width={size} - /> - Not authorized} - height={size} - imagePath={NotAuthorized} - width={size} - /> - Centreon logo light} - height={size} - imagePath={CentreonLogoLight} - width={size} - /> - Not authorized} - height={size} - imagePath={NotAuthorized} - width={size} - /> -
- ); -}; - -export const withWidthAndHeight = Template.bind({}); -withWidthAndHeight.args = { - alt: 'Centreon logo light', - fallback: , - height: size, - imagePath: CentreonLogoLight, - width: size -}; - -export const imageNotFound = (): JSX.Element => ( - Not found alt text} - height={size} - imagePath="not-found" - width={size} - /> -); - -export const variantContain = Template.bind({}); -variantContain.args = { - alt: 'Centreon logo light', - height: size, - variant: ImageVariant.Contain, - width: size -}; +import { ComponentStory } from '@storybook/react'; + +import CentreonLogoLight from '../@assets/brand/centreon-logo-one-line-light.svg'; +import NotAuthorized from '../@assets/images/not-authorized-template-background-light.svg'; +import LoadingSkeleton from '../LoadingSkeleton'; + +import Image, { ImageVariant } from './Image'; + +export default { + argTypes: { + alt: { control: 'text' }, + height: { control: 'number' }, + width: { control: 'number' } + }, + component: Image, + + title: 'Image' +}; + +const Template: ComponentStory = (args) => ( + } + imagePath={CentreonLogoLight} + /> +); + +const size = 50; + +export const basic = Template.bind({}); +basic.args = { + alt: 'Centreon logo light' +}; + +export const multipleImages = (): JSX.Element => { + return ( +
+ Centreon logo light} + height={size} + imagePath={CentreonLogoLight} + width={size} + /> + Not authorized} + height={size} + imagePath={NotAuthorized} + width={size} + /> + Centreon logo light} + height={size} + imagePath={CentreonLogoLight} + width={size} + /> + Not authorized} + height={size} + imagePath={NotAuthorized} + width={size} + /> +
+ ); +}; + +export const withWidthAndHeight = Template.bind({}); +withWidthAndHeight.args = { + alt: 'Centreon logo light', + fallback: , + height: size, + imagePath: CentreonLogoLight, + width: size +}; + +export const imageNotFound = (): JSX.Element => ( + Not found alt text} + height={size} + imagePath="not-found" + width={size} + /> +); + +export const variantContain = Template.bind({}); +variantContain.args = { + alt: 'Centreon logo light', + height: size, + variant: ImageVariant.Contain, + width: size +}; diff --git a/centreon/packages/ui/src/Image/index.test.tsx b/centreon/packages/ui/src/Image/index.test.tsx index 70edfb048f..87a6501380 100644 --- a/centreon/packages/ui/src/Image/index.test.tsx +++ b/centreon/packages/ui/src/Image/index.test.tsx @@ -1,53 +1,53 @@ -import { RenderResult, screen, waitFor } from '@testing-library/react'; -import { Provider } from 'jotai'; - -import { render } from '../../test/testRenderer'; -import CentreonLogoLight from '../@assets/brand/centreon-logo-one-line-light.svg'; - -import Image from './Image'; - -jest.mock('../../@assets/centreon-logo-one-line-light.svg'); - -const renderImage = (): RenderResult => - render( - - testLoading...

} - imagePath={CentreonLogoLight} - /> -
- ); - -const renderNotFoundImage = (): RenderResult => - render( - - testLoading...

} - imagePath="another_image" - /> -
- ); - -describe('useLoadImage', () => { - it('displays the loaded image', async () => { - renderImage(); - - expect(screen.getByText('Loading...')).toBeInTheDocument(); - - await waitFor(() => { - expect(screen.getByAltText('test')).toBeInTheDocument(); - }); - }); - - it('displays a not found image', async () => { - renderNotFoundImage(); - - expect(screen.getByText('Loading...')).toBeInTheDocument(); - - await waitFor(() => { - expect(screen.getByAltText('test')).toBeInTheDocument(); - }); - }); -}); +import { RenderResult, screen, waitFor } from '@testing-library/react'; +import { Provider } from 'jotai'; + +import { render } from '../../test/testRenderer'; +import CentreonLogoLight from '../@assets/brand/centreon-logo-one-line-light.svg'; + +import Image from './Image'; + +jest.mock('../../@assets/centreon-logo-one-line-light.svg'); + +const renderImage = (): RenderResult => + render( + + testLoading...

} + imagePath={CentreonLogoLight} + /> +
+ ); + +const renderNotFoundImage = (): RenderResult => + render( + + testLoading...

} + imagePath="another_image" + /> +
+ ); + +describe('useLoadImage', () => { + it('displays the loaded image', async () => { + renderImage(); + + expect(screen.getByText('Loading...')).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByAltText('test')).toBeInTheDocument(); + }); + }); + + it('displays a not found image', async () => { + renderNotFoundImage(); + + expect(screen.getByText('Loading...')).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByAltText('test')).toBeInTheDocument(); + }); + }); +}); diff --git a/centreon/packages/ui/src/Image/models.ts b/centreon/packages/ui/src/Image/models.ts index 915a83ac52..9eb23f8061 100644 --- a/centreon/packages/ui/src/Image/models.ts +++ b/centreon/packages/ui/src/Image/models.ts @@ -1,3 +1,3 @@ -export interface Image { - read: () => string; -} +export interface Image { + read: () => string; +} diff --git a/centreon/packages/ui/src/Image/useLoadImage.ts b/centreon/packages/ui/src/Image/useLoadImage.ts index 85ef21aed9..d34d1938f2 100644 --- a/centreon/packages/ui/src/Image/useLoadImage.ts +++ b/centreon/packages/ui/src/Image/useLoadImage.ts @@ -1,49 +1,49 @@ -import { SetStateAction, useAtom } from 'jotai'; -import { isEmpty, isNil, prop } from 'ramda'; - -import { imagesAtom } from './atoms'; - -interface CreateImageProps { - alt: string; - image?: string; - imageSrc: string; - setImages: (update: SetStateAction>) => void; -} - -const createImage = ({ - setImages, - imageSrc, - image, - alt -}: CreateImageProps): void => { - const imageLoaderPromise = (): Promise => - new Promise((resolve, reject) => { - const img = new Image(); - img.src = imageSrc; - img.onload = (): void => resolve(imageSrc); - img.onerror = (): void => - reject(new Error(`Failed to load image ${imageSrc}`)); - }); - - if (!isNil(image) || isEmpty(image)) { - return; - } - - imageLoaderPromise() - .then((result: string): void => { - setImages((currentImages) => ({ ...currentImages, [alt]: result })); - }) - .catch(() => { - setImages((currentImages) => ({ ...currentImages, [alt]: '' })); - }); -}; - -export const useLoadImage = ({ imageSrc, alt }): boolean => { - const [images, setImages] = useAtom(imagesAtom); - - const image = prop(alt, images); - - createImage({ alt, image, imageSrc, setImages }); - - return !isNil(image) || isEmpty(image); -}; +import { SetStateAction, useAtom } from 'jotai'; +import { isEmpty, isNil, prop } from 'ramda'; + +import { imagesAtom } from './atoms'; + +interface CreateImageProps { + alt: string; + image?: string; + imageSrc: string; + setImages: (update: SetStateAction>) => void; +} + +const createImage = ({ + setImages, + imageSrc, + image, + alt +}: CreateImageProps): void => { + const imageLoaderPromise = (): Promise => + new Promise((resolve, reject) => { + const img = new Image(); + img.src = imageSrc; + img.onload = (): void => resolve(imageSrc); + img.onerror = (): void => + reject(new Error(`Failed to load image ${imageSrc}`)); + }); + + if (!isNil(image) || isEmpty(image)) { + return; + } + + imageLoaderPromise() + .then((result: string): void => { + setImages((currentImages) => ({ ...currentImages, [alt]: result })); + }) + .catch(() => { + setImages((currentImages) => ({ ...currentImages, [alt]: '' })); + }); +}; + +export const useLoadImage = ({ imageSrc, alt }): boolean => { + const [images, setImages] = useAtom(imagesAtom); + + const image = prop(alt, images); + + createImage({ alt, image, imageSrc, setImages }); + + return !isNil(image) || isEmpty(image); +}; diff --git a/centreon/packages/ui/src/InputField/Number/Number.tsx b/centreon/packages/ui/src/InputField/Number/Number.tsx index 38bba560dc..454beb4aa1 100644 --- a/centreon/packages/ui/src/InputField/Number/Number.tsx +++ b/centreon/packages/ui/src/InputField/Number/Number.tsx @@ -44,8 +44,8 @@ const NumberField = ({ T, always( clamp( - inputProps?.min || -Infinity, - inputProps?.max || Infinity, + inputProps?.min || Number.NEGATIVE_INFINITY, + inputProps?.max || Number.POSITIVE_INFINITY, number ) ) diff --git a/centreon/packages/ui/src/InputField/Search/PersistentTooltip.tsx b/centreon/packages/ui/src/InputField/Search/PersistentTooltip.tsx index 7535eb95d1..ba0783f66f 100644 --- a/centreon/packages/ui/src/InputField/Search/PersistentTooltip.tsx +++ b/centreon/packages/ui/src/InputField/Search/PersistentTooltip.tsx @@ -1,11 +1,11 @@ import { ReactElement, useState } from 'react'; -import { isNil, cond, T } from 'ramda'; +import { T, cond, isNil } from 'ramda'; import { makeStyles } from 'tss-react/mui'; -import { Tooltip, IconButton } from '@mui/material'; import IconHelp from '@mui/icons-material/HelpOutline'; import IconClose from '@mui/icons-material/HighlightOff'; +import { IconButton, Tooltip } from '@mui/material'; const useStyles = makeStyles()((theme) => ({ buttonClose: { diff --git a/centreon/packages/ui/src/InputField/Search/RegexpHelpTooltip.tsx b/centreon/packages/ui/src/InputField/Search/RegexpHelpTooltip.tsx index ee668c4858..963a0e6712 100644 --- a/centreon/packages/ui/src/InputField/Search/RegexpHelpTooltip.tsx +++ b/centreon/packages/ui/src/InputField/Search/RegexpHelpTooltip.tsx @@ -1,6 +1,6 @@ import { ReactElement } from 'react'; -import { ifElse, always, isNil } from 'ramda'; +import { always, ifElse, isNil } from 'ramda'; import { Box, Link } from '@mui/material'; diff --git a/centreon/packages/ui/src/InputField/Search/index.stories.tsx b/centreon/packages/ui/src/InputField/Search/index.stories.tsx index e74c9e20c8..a1419cb80d 100644 --- a/centreon/packages/ui/src/InputField/Search/index.stories.tsx +++ b/centreon/packages/ui/src/InputField/Search/index.stories.tsx @@ -1,5 +1,5 @@ -import RegexpHelpTooltip from './RegexpHelpTooltip'; import PersistentTooltip from './PersistentTooltip'; +import RegexpHelpTooltip from './RegexpHelpTooltip'; import SearchInput from '.'; diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/Multi/index.test.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/Multi/index.test.tsx index 39412b671d..dd269ed574 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/Multi/index.test.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/Multi/index.test.tsx @@ -1,9 +1,9 @@ import { + RenderResult, fireEvent, getFetchCall, mockResponse, render, - RenderResult, resetMocks, waitFor } from '../../../../../../test/testRenderer'; diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/Multi/index.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/Multi/index.tsx index acd4f25efc..54b7e9f667 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/Multi/index.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/Multi/index.tsx @@ -1,5 +1,5 @@ -import MultiAutocompleteField from '../../Multi'; import ConnectedAutocompleteField from '..'; +import MultiAutocompleteField from '../../Multi'; const MultiConnectedAutocompleteField = ConnectedAutocompleteField( MultiAutocompleteField, diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.stories.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.stories.tsx index e7b0fb0c82..a8f7055591 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.stories.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.stories.tsx @@ -1,9 +1,9 @@ -import { buildListingEndpoint } from '../../../..'; import { SelectEntry } from '../..'; +import { buildListingEndpoint } from '../../../..'; import { Listing } from '../../../../api/models'; -import SingleConnectedAutocompleteField from './Single'; import MultiConnectedAutocompleteField from './Multi'; +import SingleConnectedAutocompleteField from './Single'; export default { title: 'InputField/Autocomplete/Connected' @@ -41,7 +41,7 @@ const mockSearch = (page: number): object => ({ response: (request): Listing => { const { searchParams } = request; - return buildResult(parseInt(searchParams.page || '0', 10)); + return buildResult(Number.parseInt(searchParams.page || '0', 10)); }, status: 200, url: `/endpoint?page=${page}&search=` @@ -54,7 +54,7 @@ const getMockData = (): Array => [ response: (request): Listing => { const { searchParams } = request; - return buildResult(parseInt(searchParams.page || '0', 10)); + return buildResult(Number.parseInt(searchParams.page || '0', 10)); }, status: 200, url: '/endpoint?page=' diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.test.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.test.tsx index 09fdd45241..80faba4ba3 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.test.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.test.tsx @@ -1,16 +1,16 @@ import { - render, - fireEvent, - waitFor, RenderResult, act, - resetMocks, + fireEvent, + getFetchCall, mockResponse, - getFetchCall + render, + resetMocks, + waitFor } from '../../../../../test/testRenderer'; +import TestQueryProvider from '../../../../api/TestQueryProvider'; import buildListingEndpoint from '../../../../api/buildListingEndpoint'; import { ConditionsSearchParameter } from '../../../../api/buildListingEndpoint/models'; -import TestQueryProvider from '../../../../api/TestQueryProvider'; import SingleConnectedAutocompleteField from './Single'; diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.tsx index 38f24ea9ca..6c311cd06a 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Connected/index.tsx @@ -1,34 +1,34 @@ -import { useState, useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { equals, - prop, - last, + has, isEmpty, - map, isNil, - pipe, + last, + map, not, - has, omit, + pipe, + prop, uniqBy } from 'ramda'; import { CircularProgress, useTheme } from '@mui/material'; import { Props as AutocompleteFieldProps } from '..'; -import { - useDebounce, - useIntersectionObserver, - useDeepCompare -} from '../../../../utils'; import { ListingModel, SelectEntry } from '../../../..'; -import Option from '../../Option'; import { ConditionsSearchParameter, SearchParameter } from '../../../../api/buildListingEndpoint/models'; import useFetchQuery from '../../../../api/useFetchQuery'; +import { + useDebounce, + useDeepCompare, + useIntersectionObserver +} from '../../../../utils'; +import Option from '../../Option'; export interface ConnectedAutoCompleteFieldProps { allowUniqOption?: boolean; diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/MultiConnected.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/MultiConnected.tsx index 0eedb60705..002ab9cd05 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/MultiConnected.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/MultiConnected.tsx @@ -1,5 +1,5 @@ -import MultiAutocompleteField from '../Multi'; import ConnectedAutocompleteField from '../Connected'; +import MultiAutocompleteField from '../Multi'; import DraggableAutocompleteField from '.'; diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx index 1832fa64ae..be4dd6d6a8 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx @@ -1,6 +1,6 @@ -import { map, find, propEq } from 'ramda'; import { rectIntersection } from '@dnd-kit/core'; import { rectSortingStrategy } from '@dnd-kit/sortable'; +import { find, map, propEq } from 'ramda'; import { makeStyles } from 'tss-react/mui'; import { lighten } from '@mui/material'; diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx index efadea32c8..3e17d3db61 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx @@ -1,11 +1,10 @@ -import * as React from 'react'; - -import { findIndex, not, propEq } from 'ramda'; import { DraggableSyntheticListeners } from '@dnd-kit/core'; import clsx from 'clsx'; +import { findIndex, not, propEq } from 'ramda'; import { Chip, Typography, useTheme } from '@mui/material'; +import { RefObject, useRef } from 'react'; import { DraggableSelectEntry, SortableListProps } from './SortableList'; interface ContentProps @@ -14,7 +13,7 @@ interface ContentProps id: string; index: number; isDragging: boolean; - itemRef: React.RefObject; + itemRef: RefObject; listeners: DraggableSyntheticListeners; style; } @@ -42,9 +41,9 @@ const SortableListContent = ({ isDragging }: ContentProps): JSX.Element => { const theme = useTheme(); - const labelItemRef = React.useRef(null); + const labelItemRef = useRef(null); - const mouseUp = (event: React.MouseEvent): void => { + const mouseUp = (event: MouseEvent): void => { if (not(event.shiftKey)) { return; } diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/index.stories.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/index.stories.tsx index b7778b0315..7406d2e937 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/index.stories.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/index.stories.tsx @@ -8,8 +8,8 @@ import { SelectEntry } from '../..'; import { buildListingEndpoint } from '../../../..'; import { Listing } from '../../../../api/models'; -import MultiDraggableConnectedAutocompleteField from './MultiConnected'; import MultiDraggableAutocompleteField from './Multi'; +import MultiDraggableConnectedAutocompleteField from './MultiConnected'; import { ItemActionProps } from '.'; @@ -49,7 +49,7 @@ const mockSearch = (page: number): object => ({ response: (request): Listing => { const { searchParams } = request; - return buildResult(parseInt(searchParams.page || '0', 10)); + return buildResult(Number.parseInt(searchParams.page || '0', 10)); }, status: 200, url: `/endpoint?page=${page}&search=` @@ -62,7 +62,7 @@ const getMockData = (): Array => [ response: (request): Listing => { const { searchParams } = request; - return buildResult(parseInt(searchParams.page || '0', 10)); + return buildResult(Number.parseInt(searchParams.page || '0', 10)); }, status: 200, url: '/endpoint?page=' @@ -74,9 +74,9 @@ const getMockData = (): Array => [ ]; const options = [ - { id: `0`, name: 'First Entity' }, - { id: `1`, name: 'Second Entity' }, - { id: `2`, name: 'Third Entity' } + { id: '0', name: 'First Entity' }, + { id: '1', name: 'Second Entity' }, + { id: '2', name: 'Third Entity' } ]; const MultiDraggable = (): JSX.Element => ( diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/index.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/index.tsx index 52561827d7..07a7110c76 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/index.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Draggable/index.tsx @@ -1,28 +1,27 @@ -import * as React from 'react'; - import { - remove, + F, equals, - pipe, - type, - last, + findIndex, inc, - F, - length, isEmpty, isNil, + last, + length, not, - findIndex, + pipe, + pluck, propEq, - pluck + remove, + type } from 'ramda'; import { Typography } from '@mui/material'; -import { ConnectedAutoCompleteFieldProps } from '../Connected'; import { Props as SingleAutocompletefieldProps } from '..'; import TextField from '../../../Text'; +import { ConnectedAutoCompleteFieldProps } from '../Connected'; +import { ChangeEvent, useEffect, useState } from 'react'; import SortableList, { DraggableSelectEntry } from './SortableList'; export interface ItemActionProps { @@ -61,13 +60,13 @@ const DraggableAutocomplete = ( | ConnectedAutoCompleteFieldProps | SingleAutocompletefieldProps )): JSX.Element => { - const [selectedValues, setSelectedValues] = React.useState< + const [selectedValues, setSelectedValues] = useState< Array >(initialValues || []); - const [totalValues, setTotalValues] = React.useState( + const [totalValues, setTotalValues] = useState( length(initialValues || []) ); - const [inputText, setInputText] = React.useState(null); + const [inputText, setInputText] = useState(null); const onChangeSelectedValuesOrder = (newSelectedValues): void => { setSelectedValues(newSelectedValues); @@ -144,7 +143,7 @@ const DraggableAutocomplete = ( ); }; - const changeInput = (e: React.ChangeEvent): void => { + const changeInput = (e: ChangeEvent): void => { if (pipe(isNil, not)(e)) { setInputText(e.target.value); } @@ -193,7 +192,7 @@ const DraggableAutocomplete = ( /> ); - React.useEffect(() => { + useEffect(() => { if (isNil(initialValues)) { return; } diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Multi/index.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Multi/index.tsx index a0b19d497d..7adfc43fed 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Multi/index.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Multi/index.tsx @@ -1,4 +1,4 @@ -import { includes, map, prop, reject, sortBy, toLower, compose } from 'ramda'; +import { compose, includes, map, prop, reject, sortBy, toLower } from 'ramda'; import { makeStyles } from 'tss-react/mui'; import { Chip, ChipProps, Tooltip } from '@mui/material'; diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/Popover/index.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/Popover/index.tsx index e244a98a4f..6a66848155 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/Popover/index.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/Popover/index.tsx @@ -3,8 +3,8 @@ import { useState } from 'react'; import { equals, isEmpty } from 'ramda'; import { makeStyles } from 'tss-react/mui'; -import { UseAutocompleteProps } from '@mui/material/useAutocomplete'; import { Avatar, Chip, useTheme } from '@mui/material'; +import { UseAutocompleteProps } from '@mui/material/useAutocomplete'; import { ThemeMode } from '@centreon/ui-context'; diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/index.stories.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/index.stories.tsx index 3cec0f8135..a8cd79b963 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/index.stories.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/index.stories.tsx @@ -1,8 +1,7 @@ -import * as React from 'react'; - import EditIcon from '@mui/icons-material/Edit'; import { InputAdornment } from '@mui/material'; +import { useState } from 'react'; import AutocompleteField from '.'; export default { title: 'InputField/Autocomplete' }; @@ -85,7 +84,7 @@ const AutoSizeAutocompleteField = ({ endAdornment, customPadding }: AutoSizeAutocompleteFieldProps): JSX.Element => { - const [value, setValue] = React.useState(null); + const [value, setValue] = useState(null); const change = (_, newValue): void => { setValue(newValue); diff --git a/centreon/packages/ui/src/InputField/Select/Autocomplete/index.tsx b/centreon/packages/ui/src/InputField/Select/Autocomplete/index.tsx index adbe7815da..f75c4b21ac 100644 --- a/centreon/packages/ui/src/InputField/Select/Autocomplete/index.tsx +++ b/centreon/packages/ui/src/InputField/Select/Autocomplete/index.tsx @@ -1,14 +1,12 @@ -import * as React from 'react'; - import { equals, isEmpty, isNil, pick } from 'ramda'; import { useTranslation } from 'react-i18next'; import { makeStyles } from 'tss-react/mui'; import { - CircularProgress, - InputAdornment, Autocomplete, AutocompleteProps, + CircularProgress, + InputAdornment, useTheme } from '@mui/material'; import { autocompleteClasses } from '@mui/material/Autocomplete'; @@ -16,11 +14,12 @@ import { UseAutocompleteProps } from '@mui/material/useAutocomplete'; import { ThemeMode } from '@centreon/ui-context'; -import Option from '../Option'; -import TextField from '../../Text'; +import { ForwardedRef, HTMLAttributes, ReactElement, forwardRef } from 'react'; import { SelectEntry } from '..'; -import { searchLabel } from '../../translatedLabels'; import { getNormalizedId } from '../../../utils'; +import TextField from '../../Text'; +import { searchLabel } from '../../translatedLabels'; +import Option from '../Option'; export type Props = { autoFocus?: boolean; @@ -30,7 +29,7 @@ export type Props = { dataTestId?: string; displayOptionThumbnail?: boolean; displayPopupIcon?: boolean; - endAdornment?: React.ReactElement; + endAdornment?: ReactElement; error?: string; getOptionItemLabel?: (option) => string; hideInput?: boolean; @@ -141,7 +140,7 @@ type Multiple = boolean; type DisableClearable = boolean; type FreeSolo = boolean; -const AutocompleteField = React.forwardRef( +const AutocompleteField = forwardRef( ( { options, @@ -164,7 +163,7 @@ const AutocompleteField = React.forwardRef( getOptionItemLabel = (option) => option.name, ...autocompleteProps }: Props, - ref?: React.ForwardedRef + ref?: ForwardedRef ): JSX.Element => { const { classes, cx } = useStyles({ hideInput }); const { t } = useTranslation(); @@ -259,7 +258,7 @@ const AutocompleteField = React.forwardRef( return (
  • )} + {...(props as HTMLAttributes)} >