diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 000000000..4a34b2115 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,28 @@ +# Codespaces + +You can modifiy Uptime Kuma in your browser without setting up a local development. + +![image](https://github.com/louislam/uptime-kuma/assets/1336778/31d9f06d-dd0b-4405-8e0d-a96586ee4595) + +1. Click `Code` -> `Create codespace on master` +2. Wait a few minutes until you see there are two exposed ports +3. Go to the `3000` url, see if it is working + +![image](https://github.com/louislam/uptime-kuma/assets/1336778/909b2eb4-4c5e-44e4-ac26-6d20ed856e7f) + +## Frontend + +Since the frontend is using [Vite.js](https://vitejs.dev/), all changes in this area will be hot-reloaded. +You don't need to restart the frontend, unless you try to add a new frontend dependency. + +## Backend + +The backend does not automatically hot-reload. +You will need to restart the backend after changing something using these steps: + +1. Click `Terminal` +2. Click `Codespaces: server-dev` in the right panel +3. Press `Ctrl + C` to stop the server +4. Press `Up` to run `npm run start-server-dev` + +![image](https://github.com/louislam/uptime-kuma/assets/1336778/e0c0a350-fe46-4588-9f37-e053c85834d1) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..5b3ceabc8 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,22 @@ +{ + "image": "mcr.microsoft.com/devcontainers/javascript-node:dev-18-bookworm", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + "updateContentCommand": "npm ci", + "postCreateCommand": "", + "postAttachCommand": { + "frontend-dev": "npm run start-frontend-devcontainer", + "server-dev": "npm run start-server-dev", + "open-port": "gh codespace ports visibility 3001:public -c $CODESPACE_NAME" + }, + "customizations": { + "vscode": { + "extensions": [ + "streetsidesoftware.code-spell-checker", + "dbaeumer.vscode-eslint" + ] + } + }, + "forwardPorts": [3000, 3001] +} diff --git a/.dockerignore b/.dockerignore index babc429a2..0bc56885c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,6 @@ /.idea /node_modules -/data +/data* /cypress /out /test @@ -18,6 +18,7 @@ README.md .vscode .eslint* .stylelint* +/.devcontainer /.github yarn.lock app.json @@ -31,6 +32,10 @@ tsconfig.json /tmp /babel.config.js /ecosystem.config.js +/extra/healthcheck.exe +/extra/healthcheck +extra/exe-builder + ### .gitignore content (commented rules are duplicated) @@ -45,6 +50,4 @@ dist-ssr #!/data/.gitkeep #.vscode - - ### End of .gitignore content diff --git a/.editorconfig b/.editorconfig index 3b2721931..47bf47687 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,3 +19,6 @@ indent_size = 2 [*.vue] trim_trailing_whitespace = false + +[*.go] +indent_style = tab diff --git a/.eslintrc.js b/.eslintrc.js index 4713799d7..0f19793aa 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,7 @@ module.exports = { ignorePatterns: [ - "test/*", + "test/*.js", + "test/cypress", "server/modules/apicache/*", "src/util.js" ], @@ -14,6 +15,7 @@ module.exports = { extends: [ "eslint:recommended", "plugin:vue/vue3-recommended", + "plugin:jsdoc/recommended-error", ], parser: "vue-eslint-parser", parserOptions: { @@ -21,6 +23,9 @@ module.exports = { sourceType: "module", requireConfigFile: false, }, + plugins: [ + "jsdoc" + ], rules: { "yoda": "error", eqeqeq: [ "warn", "smart" ], @@ -97,7 +102,43 @@ module.exports = { }], "no-control-regex": "off", "one-var": [ "error", "never" ], - "max-statements-per-line": [ "error", { "max": 1 }] + "max-statements-per-line": [ "error", { "max": 1 }], + "jsdoc/check-tag-names": [ + "error", + { + "definedTags": [ "link" ] + } + ], + "jsdoc/no-undefined-types": "off", + "jsdoc/no-defaults": [ + "error", + { "noOptionalParamNames": true } + ], + "jsdoc/require-throws": "warn", + "jsdoc/require-jsdoc": [ + "error", + { + "require": { + "FunctionDeclaration": true, + "MethodDefinition": true, + } + } + ], + "jsdoc/no-blank-block-descriptions": "error", + "jsdoc/require-returns-description": "warn", + "jsdoc/require-returns-check": [ + "error", + { "reportMissingReturnForUndefinedTypes": false } + ], + "jsdoc/require-returns": [ + "warn", + { + "forceRequireReturn": true, + "forceReturnsWithAsync": true + } + ], + "jsdoc/require-param-type": "warn", + "jsdoc/require-param-description": "warn" }, "overrides": [ { diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml index 3442e8b73..c082b2e34 100644 --- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml +++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml @@ -26,6 +26,12 @@ body: label: "📝 Describe your problem" description: "Please walk us through it step by step." placeholder: "Describe what are you asking for..." + - type: textarea + id: error-msg + validations: + required: false + attributes: + label: "📝 Error Message(s) or Log" - type: input id: uptime-kuma-version attributes: @@ -38,7 +44,7 @@ body: id: operating-system attributes: label: "💻 Operating System and Arch" - description: "Which OS is your server/device running on?" + description: "Which OS is your server/device running on? (For Replit, please do not report this bug)" placeholder: "Ex. Ubuntu 20.04 x86" validations: required: true @@ -46,7 +52,7 @@ body: id: browser-vendor attributes: label: "🌐 Browser" - description: "Which browser are you running on?" + description: "Which browser are you running on? (For Replit, please do not report this bug)" placeholder: "Ex. Google Chrome 95.0.4638.69" validations: required: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 2dca1556a..072444205 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -61,8 +61,8 @@ body: id: operating-system attributes: label: "💻 Operating System and Arch" - description: "Which OS is your server/device running on?" - placeholder: "Ex. Ubuntu 20.04 x86" + description: "Which OS is your server/device running on? (For Replit, please do not report this bug)" + placeholder: "Ex. Ubuntu 20.04 x64 " validations: required: true - type: input diff --git a/.github/ISSUE_TEMPLATE/security.md b/.github/ISSUE_TEMPLATE/security.md new file mode 100644 index 000000000..26450ed3a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security.md @@ -0,0 +1,19 @@ +--- + +name: "Security Issue" +about: "Just for alerting @louislam, do not provide any details here" +title: "Security Issue" +ref: "main" +labels: + +- security + +--- + +DO NOT PROVIDE ANY DETAILS HERE. Please privately report to https://github.com/louislam/uptime-kuma/security/advisories/new. + + +Why need this issue? It is because GitHub Advisory do not send a notification to @louislam, it is a workaround to do so. + +Your GitHub Advisory URL: + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4d2105d49..87e7f5ff7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -16,7 +16,6 @@ Please delete any options that are not relevant. - User interface (UI) - New feature (non-breaking change which adds functionality) - Breaking change (fix or feature that would cause existing functionality to not work as expected) -- Translation update - Other - This change requires a documentation update diff --git a/.github/config/exclude.txt b/.github/config/exclude.txt new file mode 100644 index 000000000..253258856 --- /dev/null +++ b/.github/config/exclude.txt @@ -0,0 +1 @@ +# This is a .gitignore style file for 'GrantBirki/json-yaml-validate' Action workflow diff --git a/.github/workflows/auto-test.yml b/.github/workflows/auto-test.yml index b49a253c3..7570a7f2a 100644 --- a/.github/workflows/auto-test.yml +++ b/.github/workflows/auto-test.yml @@ -1,4 +1,4 @@ -# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: Auto Test @@ -6,8 +6,12 @@ name: Auto Test on: push: branches: [ master ] + paths-ignore: + - '*.md' pull_request: - branches: [ master ] + branches: [ master, 2.0.X ] + paths-ignore: + - '*.md' jobs: auto-test: @@ -17,8 +21,8 @@ jobs: strategy: matrix: - os: [macos-latest, ubuntu-latest, windows-latest] - node: [ 14, 16, 17, 18 ] + os: [macos-latest, ubuntu-latest, windows-latest, ARM64] + node: [ 14, 20 ] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: @@ -29,13 +33,37 @@ jobs: uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: 'npm' + - run: npm install npm@9 -g - run: npm install - run: npm run build - run: npm test env: HEADLESS_TEST: 1 JUST_FOR_TEST: ${{ secrets.JUST_FOR_TEST }} + + # As a lot of dev dependencies are not supported on ARMv7, we have to test it separately and just test if `npm ci --production` works + armv7-simple-test: + needs: [ check-linters ] + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + + strategy: + matrix: + os: [ ARMv7 ] + node: [ 14, 20 ] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - run: git config --global core.autocrlf false # Mainly for Windows + - uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + - run: npm install npm@9 -g + - run: npm ci --production + check-linters: runs-on: ubuntu-latest @@ -43,15 +71,30 @@ jobs: - run: git config --global core.autocrlf false # Mainly for Windows - uses: actions/checkout@v3 - - name: Use Node.js 14 + - name: Use Node.js 20 uses: actions/setup-node@v3 with: - node-version: 14 - cache: 'npm' + node-version: 20 - run: npm install - run: npm run lint - e2e-tests: +# TODO: Temporarily disable, as it cannot pass the test in 2.0.0 yet +# e2e-tests: +# needs: [ check-linters ] +# runs-on: ubuntu-latest +# steps: +# - run: git config --global core.autocrlf false # Mainly for Windows +# - uses: actions/checkout@v3 +# +# - name: Use Node.js 14 +# uses: actions/setup-node@v3 +# with: +# node-version: 14 +# - run: npm install +# - run: npm run build +# - run: npm run cy:test + + frontend-unit-tests: needs: [ check-linters ] runs-on: ubuntu-latest steps: @@ -62,7 +105,6 @@ jobs: uses: actions/setup-node@v3 with: node-version: 14 - cache: 'npm' - run: npm install - run: npm run build - - run: npm run cy:test + - run: npm run cy:run:unit diff --git a/.github/workflows/close-incorrect-issue.yml b/.github/workflows/close-incorrect-issue.yml index 026022dfa..762bc9688 100644 --- a/.github/workflows/close-incorrect-issue.yml +++ b/.github/workflows/close-incorrect-issue.yml @@ -1,4 +1,3 @@ - name: Close Incorrect Issue on: @@ -12,13 +11,13 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node-version: [16.x] + node-version: [16] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} cache: 'npm' diff --git a/.github/workflows/json-yaml-validate.yml b/.github/workflows/json-yaml-validate.yml new file mode 100644 index 000000000..104e37a17 --- /dev/null +++ b/.github/workflows/json-yaml-validate.yml @@ -0,0 +1,27 @@ +name: json-yaml-validate +on: + push: + branches: + - master + pull_request: + branches: + - master + - 2.0.X + workflow_dispatch: + +permissions: + contents: read + pull-requests: write # enable write permissions for pull request comments + +jobs: + json-yaml-validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: json-yaml-validate + id: json-yaml-validate + uses: GrantBirki/json-yaml-validate@v1.3.0 + with: + comment: "true" # enable comment mode + exclude_file: ".github/config/exclude.txt" # gitignore style file for exclusions diff --git a/.github/workflows/stale-bot.yml b/.github/workflows/stale-bot.yml index ae9177afe..b39f68fc1 100644 --- a/.github/workflows/stale-bot.yml +++ b/.github/workflows/stale-bot.yml @@ -3,22 +3,20 @@ on: workflow_dispatch: schedule: - cron: '0 */6 * * *' -#Run every 6 hours +#Run every 6 hours jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v5 + - uses: actions/stale@v7 with: stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.' - stale-pr-message: 'We are clearing up our old Pull Requests and yours has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.' close-issue-message: 'This issue was closed because it has been stalled for 2 days with no activity.' - close-pr-message: 'This PR was closed because it has been stalled for 2 days with no activity.' days-before-stale: 90 days-before-close: 2 + days-before-pr-stale: 999999999 + days-before-pr-close: 1 exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,feature-request' - exempt-pr-labels: 'awaiting-approval,work-in-progress,enhancement,feature-request' exempt-issue-assignees: 'louislam' - exempt-pr-assignees: 'louislam' operations-per-run: 200 diff --git a/.gitignore b/.gitignore index 8eb05867b..169b58204 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ dist-ssr /data !/data/.gitkeep +/data* .vscode /private @@ -16,3 +17,13 @@ dist-ssr cypress/videos cypress/screenshots + +/extra/healthcheck.exe +/extra/healthcheck +/extra/healthcheck-armv7 + +extra/exe-builder/bin +extra/exe-builder/obj + +.vs +.vscode diff --git a/.stylelintrc b/.stylelintrc index e590c98ca..0bcdb7c27 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -10,5 +10,7 @@ "color-function-notation": "legacy", "shorthand-property-no-redundant-values": null, "color-hex-length": null, + "declaration-block-no-redundant-longhand-properties": null, + "at-rule-no-unknown": null } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9829c96f..d94eb71db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,14 +1,14 @@ # Project Info -First of all, thank you everyone who made pull requests for Uptime Kuma, I never thought GitHub Community can be that nice! And also because of this, I also never thought other people actually read my code and edit my code. It is not structured and commented so well, lol. Sorry about that. +First of all, I want to thank everyone who made pull requests for Uptime Kuma. I never thought the GitHub Community would be so nice! Because of this, I also never thought that other people would actually read and edit my code. It is not very well structured or commented, sorry about that. -The project was created with vite.js (vue3). Then I created a subdirectory called "server" for server part. Both frontend and backend share the same package.json. +The project was created with vite.js (vue3). Then I created a subdirectory called "server" for the server part. Both frontend and backend share the same package.json. -The frontend code build into "dist" directory. The server (express.js) exposes the "dist" directory as root of the endpoint. This is how production is working. +The frontend code builds into "dist" directory. The server (express.js) exposes the "dist" directory as the root of the endpoint. This is how production is working. ## Key Technical Skills -- Node.js (You should know what are promise, async/await and arrow function etc.) +- Node.js (You should know about promise, async/await and arrow function etc.) - Socket.io - SCSS - Vue.js @@ -17,8 +17,11 @@ The frontend code build into "dist" directory. The server (express.js) exposes t ## Directories +- config (dev config files) - data (App data) +- db (Base database and migration scripts) - dist (Frontend build) +- docker (Dockerfiles) - extra (Extra useful scripts) - public (Frontend resources for dev only) - server (Server source code) @@ -27,32 +30,40 @@ The frontend code build into "dist" directory. The server (express.js) exposes t ## Can I create a pull request for Uptime Kuma? -Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create empty draft pull request or open an issue, so we can discuss first**. Especially for a large pull request or you don't know it will be merged or not. +Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create an empty draft pull request or open an issue, so we can have a discussion first**. Especially for a large pull request or you don't know if it will be merged or not. Here are some references: -✅ Usually Accept: -- Bug/Security fix -- Translations +### ✅ Usually accepted: +- Bug fix +- Security fix - Adding notification providers +- Adding new language files (see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md)) +- Adding new language keys: `$t("...")` -⚠️ Discussion First +### ⚠️ Discussion required: - Large pull requests - New features -❌ Won't Merge -- Do not pass auto test +### ❌ Won't be merged: +- A dedicated PR for translating existing languages (see [these instructions](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md)) +- Do not pass the auto-test - Any breaking changes -- Duplicated pull request +- Duplicated pull requests - Buggy - UI/UX is not close to Uptime Kuma -- Existing logic is completely modified or deleted for no reason -- A function that is completely out of scope -- Unnesscary large code changes (Hard to review, casuse code conflicts to other pull requests) +- Modifications or deletions of existing logic without a valid reason. +- Adding functions that is completely out of scope +- Converting existing code into other programming languages +- Unnecessarily large code changes that are hard to review and cause conflicts with other PRs. -I will mark your pull request in the [milestones](https://github.com/louislam/uptime-kuma/milestones), if I am plan to review and merge it. +The above cases may not cover all possible situations. -Also, please don't rush or ask for ETA, because I have to understand the pull request, make sure it is no breaking changes and stick to my vision of this project, especially for large pull requests. +I (@louislam) have the final say. If your pull request does not meet my expectations, I will reject it, no matter how much time you spend on it. Therefore, it is essential to have a discussion beforehand. + +I will assign your pull request to a [milestone](https://github.com/louislam/uptime-kuma/milestones), if I plan to review and merge it. + +Also, please don't rush or ask for an ETA, because I have to understand the pull request, make sure it is no breaking changes and stick to my vision of this project, especially for large pull requests. ### Recommended Pull Request Guideline @@ -72,13 +83,13 @@ Before deep into coding, discussion first is preferred. Creating an empty pull r ## Project Styles -I personally do not like something need to learn so much and need to config so much before you can finally start the app. +I personally do not like something that requires so many configurations before you can finally start the app. I hope Uptime Kuma installation will be as easy as like installing a mobile app. -- Easy to install for non-Docker users, no native build dependency is needed (at least for x86_64), no extra config, no extra effort to get it run +- Easy to install for non-Docker users, no native build dependency is needed (for x86_64/armv7/arm64), no extra config, and no extra effort required to get it running - Single container for Docker users, no very complex docker-compose file. Just map the volume and expose the port, then good to go -- Settings should be configurable in the frontend. Environment variable is not encouraged, unless it is related to startup such as `DATA_DIR`. +- Settings should be configurable in the frontend. Environment variables are discouraged, unless it is related to startup such as `DATA_DIR` - Easy to use -- The web UI styling should be consistent and nice. +- The web UI styling should be consistent and nice ## Coding Styles @@ -87,7 +98,7 @@ I personally do not like something need to learn so much and need to config so m - Follow ESLint - Methods and functions should be documented with JSDoc -## Name convention +## Name Conventions - Javascript/Typescript: camelCaseType - SQLite: snake_case (Underscore) @@ -95,13 +106,13 @@ I personally do not like something need to learn so much and need to config so m ## Tools -- Node.js >= 14 -- NPM >= 8.5 -- Git -- IDE that supports ESLint and EditorConfig (I am using IntelliJ IDEA) -- A SQLite GUI tool (SQLite Expert Personal is suggested) +- [`Node.js`](https://nodejs.org/) >= 14 +- [`npm`](https://www.npmjs.com/) >= 8.5 +- [`git`](https://git-scm.com/) +- IDE that supports [`ESLint`](https://eslint.org/) and EditorConfig (I am using [`IntelliJ IDEA`](https://www.jetbrains.com/idea/)) +- A SQLite GUI tool (f.ex. [`SQLite Expert Personal`](https://www.sqliteexpert.com/download.html) or [`DBeaver Community`](https://dbeaver.io/download/)) -## Install dependencies +## Install Dependencies for Development ```bash npm ci @@ -119,6 +130,12 @@ Port `3000` and port `3001` will be used. npm run dev ``` +But sometimes, you would like to restart the server, but not the frontend, you can run these commands in two terminals: +``` +npm run start-frontend-dev +npm run start-server-dev +``` + ## Backend Server It binds to `0.0.0.0:3001` by default. @@ -129,21 +146,24 @@ It is mainly a socket.io app + express.js. express.js is used for: - entry point such as redirecting to a status page or the dashboard - serving the frontend built files (index.html, .js and .css etc.) -- serving internal APIs of status page +- serving internal APIs of the status page ### Structure in /server/ -- model/ (Object model, auto mapping to the database table name) +- jobs/ (Jobs that are running in another process) +- model/ (Object model, auto-mapping to the database table name) - modules/ (Modified 3rd-party modules) +- monitor_types (Monitor Types) - notification-providers/ (individual notification logic) - routers/ (Express Routers) - socket-handler (Socket.io Handlers) -- server.js (Server entry point and main logic) +- server.js (Server entry point) +- uptime-kuma-server.js (UptimeKumaServer class, main logic should be here, but some still in `server.js`) ## Frontend Dev Server -It binds to `0.0.0.0:3000` by default. Frontend dev server is used for development only. +It binds to `0.0.0.0:3000` by default. The frontend dev server is used for development only. For production, it is not used. It will be compiled to `dist` directory instead. @@ -161,7 +181,7 @@ Uptime Kuma Frontend is a single page application (SPA). Most paths are handled The router is in `src/router.js` -As you can see, most data in frontend is stored in root level, even though you changed the current router to any other pages. +As you can see, most data in the frontend is stored at the root level, even though you changed the current router to any other pages. The data and socket logic are in `src/mixins/socket.js`. @@ -172,18 +192,14 @@ The data and socket logic are in `src/mixins/socket.js`. ## Unit Test -It is an end-to-end testing. It is using Jest and Puppeteer. - ```bash npm run build npm test ``` -By default, the Chromium window will be shown up during the test. Specifying `HEADLESS_TEST=1` for terminal environments. - ## Dependencies -Both frontend and backend share the same package.json. However, the frontend dependencies are eventually not be used in production environment, because it is usually also baked into dist files. So: +Both frontend and backend share the same package.json. However, the frontend dependencies are eventually not used in the production environment, because it is usually also baked into dist files. So: - Frontend dependencies = "devDependencies" - Examples: vue, chart.js @@ -194,21 +210,25 @@ Both frontend and backend share the same package.json. However, the frontend dep ### Update Dependencies -Install `ncu` -https://github.com/raineorshine/npm-check-updates - -```bash -ncu -u -t patch -npm install -``` - -Since previously updating Vite 2.5.10 to 2.6.0 broke the application completely, from now on, it should update patch release version only. +Since previously updating Vite 2.5.10 to 2.6.0 broke the application completely, from now on, it should update the patch release version only. Patch release = the third digit ([Semantic Versioning](https://semver.org/)) +If for security / bug / other reasons, a library must be updated, breaking changes need to be checked by the person proposing the change. + ## Translations -Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages +Please add **all** the strings which are translatable to `src/lang/en.json` (If translation keys are omitted, they can not be translated). + +**Don't include any other languages in your initial Pull-Request** (even if this is your mother tongue), to avoid merge-conflicts between weblate and `master`. +The translations can then (after merging a PR into `master`) be translated by awesome people donating their language skills. + +If you want to help by translating Uptime Kuma into your language, please visit the [instructions on how to translate using weblate](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md). + +## Spelling & Grammar + +Feel free to correct the grammar in the documentation or code. +My mother language is not English and my grammar is not that great. ## Wiki @@ -225,12 +245,13 @@ https://github.com/louislam/uptime-kuma/issues?q=sort%3Aupdated-desc 1. Draft a release note 2. Make sure the repo is cleared +3. If the healthcheck is updated, remember to re-compile it: `npm run build-docker-builder-go` 3. `npm run release-final with env vars: `VERSION` and `GITHUB_TOKEN` 4. Wait until the `Press any key to continue` 5. `git push` 6. Publish the release note as 1.X.X 7. Press any key to continue -8. SSH to demo site server and update to 1.X.X +8. Deploy to the demo server: `npm run deploy-demo-server` Checking: diff --git a/README.md b/README.md index b81c0be2b..75b284bb8 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,39 @@ -# Uptime Kuma - - -[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam) -
-It is a self-hosted monitoring tool like "Uptime Robot". +# Uptime Kuma - +Uptime Kuma is an easy-to-use self-hosted monitoring tool. + + +[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam) +Translation status + + + ## 🥔 Live Demo Try it! -https://demo.uptime.kuma.pet +- Tokyo Demo Server: https://demo.uptime.kuma.pet (Sponsored by [Uptime Kuma Sponsors](https://github.com/louislam/uptime-kuma#%EF%B8%8F-sponsors)) -It is a temporary live demo, all data will be deleted after 10 minutes. The server is located in Tokyo, so if you live far from there, it may affect your experience. I suggest that you should install and try it out for the best demo experience. - -VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollective.com/uptime-kuma)! Thank you so much! +It is a temporary live demo, all data will be deleted after 10 minutes. Use the one that is closer to you, but I suggest that you should install and try it out for the best demo experience. ## ⭐ Features -* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server / Docker Containers. -* Fancy, Reactive, Fast UI/UX. -* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [90+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications). -* 20 second intervals. -* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/languages) -* Multiple Status Pages -* Map Status Page to Domain -* Ping Chart -* Certificate Info -* Proxy Support -* 2FA available +* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / HTTP(s) Json Query / Ping / DNS Record / Push / Steam Game Server / Docker Containers +* Fancy, Reactive, Fast UI/UX +* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [90+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications) +* 20-second intervals +* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/lang) +* Multiple status pages +* Map status pages to specific domains +* Ping chart +* Certificate info +* Proxy support +* 2FA support ## 🔧 How to Install @@ -45,18 +45,23 @@ docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name upti ⚠️ Please use a **local volume** only. Other types such as NFS are not supported. -Browse to http://localhost:3001 after starting. +Uptime Kuma is now running on http://localhost:3001 ### 💪🏻 Non-Docker -Required Tools: -- [Node.js](https://nodejs.org/en/download/) >= 14 -- [Git](https://git-scm.com/downloads) -- [pm2](https://pm2.keymetrics.io/) - For run in background +Requirements: +- Platform + - ✅ Major Linux distros such as Debian, Ubuntu, CentOS, Fedora and ArchLinux etc. + - ✅ Windows 10 (x64), Windows Server 2012 R2 (x64) or higher + - ❌ Replit / Heroku +- [Node.js](https://nodejs.org/en/download/) 14 / 16 / 18 / 20.4 +- [npm](https://docs.npmjs.com/cli/) >= 7 +- [Git](https://git-scm.com/downloads) +- [pm2](https://pm2.keymetrics.io/) - For running Uptime Kuma in the background ```bash -# Update your npm to the latest version -npm install npm -g +# Update your npm +npm install npm@9 -g git clone https://github.com/louislam/uptime-kuma.git cd uptime-kuma @@ -65,8 +70,8 @@ npm run setup # Option 1. Try it node server/server.js -# (Recommended) Option 2. Run in background using PM2 -# Install PM2 if you don't have it: +# (Recommended) Option 2. Run in the background using PM2 +# Install PM2 if you don't have it: npm install pm2 -g && pm2 install pm2-logrotate # Start Server @@ -74,7 +79,7 @@ pm2 start server/server.js --name uptime-kuma ``` -Browse to http://localhost:3001 after starting. +Uptime Kuma is now running on http://localhost:3001 More useful PM2 Commands @@ -86,6 +91,10 @@ pm2 monit pm2 save && pm2 startup ``` +### Windows Portable (x64) + +https://github.com/louislam/uptime-kuma/releases/download/1.23.1/uptime-kuma-windows-x64-portable-1.23.1.zip + ### Advanced Installation If you need more options or need to browse via a reverse proxy, please read: @@ -100,7 +109,7 @@ https://github.com/louislam/uptime-kuma/wiki/%F0%9F%86%99-How-to-Update ## 🆕 What's Next? -I will mark requests/issues to the next milestone. +I will assign requests/issues to the next milestone. https://github.com/louislam/uptime-kuma/milestones @@ -143,17 +152,18 @@ Telegram Notification Sample: If you love this project, please consider giving me a ⭐. -## 🗣️ Discussion +## 🗣️ Discussion / Ask for Help -### Issues Page +⚠️ For any general or technical questions, please don't send me an email, as I am unable to provide support in that manner. I will not response if you asked such questions. -You can discuss or ask for help in [issues](https://github.com/louislam/uptime-kuma/issues). +I recommend using Google, GitHub Issues, or Uptime Kuma's Subreddit for finding answers to your question. If you cannot find the information you need, feel free to ask: -### Subreddit +- [GitHub Issues](https://github.com/louislam/uptime-kuma/issues) +- [Subreddit r/Uptime kuma](https://www.reddit.com/r/UptimeKuma/) My Reddit account: [u/louislamlam](https://reddit.com/u/louislamlam). You can mention me if you ask a question on Reddit. -[r/Uptime kuma](https://www.reddit.com/r/UptimeKuma/) + ## Contribute @@ -172,9 +182,12 @@ Check out the latest beta release here: https://github.com/louislam/uptime-kuma/ If you want to report a bug or request a new feature, feel free to open a [new issue](https://github.com/louislam/uptime-kuma/issues). ### Translations -If you want to translate Uptime Kuma into your language, please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages +If you want to translate Uptime Kuma into your language, please visit [Weblate Readme](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md). -Feel free to correct my grammar in this README, source code, or wiki, as my mother language is not English and my grammar is not that great. +## Spelling & Grammar + +Feel free to correct the grammar in the documentation or code. +My mother language is not english and my grammar is not that great. ### Create Pull Requests If you want to modify Uptime Kuma, please read this guide and follow the rules here: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md diff --git a/SECURITY.md b/SECURITY.md index d5941a97d..db4bc138f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,15 +2,20 @@ ## Reporting a Vulnerability -Please report security issues to uptime@kuma.pet. +1. Please report security issues to https://github.com/louislam/uptime-kuma/security/advisories/new. +1. Please also create an empty security issue to alert me, as GitHub Advisories do not send a notification, I probably will miss it without this. https://github.com/louislam/uptime-kuma/issues/new?assignees=&labels=help&template=security.md -Do not use the issue tracker or discuss it in the public as it will cause more damage. +Do not use the public issue tracker or discuss it in public as it will cause more damage. + +## Do you accept other 3rd-party bug bounty platforms? + +At this moment, I DO NOT accept other bug bounty platforms, because I am not familiar with these platforms and someone has tried to send a phishing link to me by doing this already. To minimize my own risk, please report through GitHub Advisories only. I will ignore all 3rd-party bug bounty platforms emails. ## Supported Versions ### Uptime Kuma Versions -You should use or upgrade to the latest version of Uptime Kuma. All `1.X.X` versions are upgradable to the lastest version. +You should use or upgrade to the latest version of Uptime Kuma. All `1.X.X` versions are upgradable to the latest version. ### Upgradable Docker Tags diff --git a/babel.config.js b/babel.config.js index 6bb8a01a5..d4c895475 100644 --- a/babel.config.js +++ b/babel.config.js @@ -4,8 +4,4 @@ if (process.env.TEST_FRONTEND) { config.presets = [ "@babel/preset-env" ]; } -if (process.env.TEST_BACKEND) { - config.plugins = [ "babel-plugin-rewire" ]; -} - module.exports = config; diff --git a/config/cypress.config.js b/config/cypress.config.js new file mode 100644 index 000000000..26784e882 --- /dev/null +++ b/config/cypress.config.js @@ -0,0 +1,28 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + projectId: "vyjuem", + e2e: { + experimentalStudio: true, + setupNodeEvents(on, config) { + + }, + fixturesFolder: "test/cypress/fixtures", + screenshotsFolder: "test/cypress/screenshots", + videosFolder: "test/cypress/videos", + downloadsFolder: "test/cypress/downloads", + supportFile: "test/cypress/support/e2e.js", + baseUrl: "http://localhost:3002", + defaultCommandTimeout: 10000, + pageLoadTimeout: 60000, + viewportWidth: 1920, + viewportHeight: 1080, + specPattern: [ + "test/cypress/e2e/setup.cy.js", + "test/cypress/e2e/**/*.js" + ], + }, + env: { + baseUrl: "http://localhost:3002", + }, +}); diff --git a/config/cypress.frontend.config.js b/config/cypress.frontend.config.js new file mode 100644 index 000000000..eecdcb8dd --- /dev/null +++ b/config/cypress.frontend.config.js @@ -0,0 +1,10 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + e2e: { + supportFile: false, + specPattern: [ + "test/cypress/unit/**/*.js" + ], + } +}); diff --git a/config/jest-debug-env.js b/config/jest-debug-env.js deleted file mode 100644 index 74f6d7835..000000000 --- a/config/jest-debug-env.js +++ /dev/null @@ -1,33 +0,0 @@ -const PuppeteerEnvironment = require("jest-environment-puppeteer"); -const util = require("util"); - -class DebugEnv extends PuppeteerEnvironment { - async handleTestEvent(event, state) { - const ignoredEvents = [ - "setup", - "add_hook", - "start_describe_definition", - "add_test", - "finish_describe_definition", - "run_start", - "run_describe_start", - "test_start", - "hook_start", - "hook_success", - "test_fn_start", - "test_fn_success", - "test_done", - "run_describe_finish", - "run_finish", - "teardown", - "test_fn_failure", - ]; - if (!ignoredEvents.includes(event.name)) { - console.log( - new Date().toString() + ` Unhandled event [${event.name}] ` + util.inspect(event) - ); - } - } -} - -module.exports = DebugEnv; diff --git a/config/jest-frontend.config.js b/config/jest-frontend.config.js deleted file mode 100644 index ab6af7f1e..000000000 --- a/config/jest-frontend.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - "rootDir": "..", - "testRegex": "./test/frontend.spec.js", -}; - diff --git a/config/jest-puppeteer.config.js b/config/jest-puppeteer.config.js deleted file mode 100644 index dc4f7b344..000000000 --- a/config/jest-puppeteer.config.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - "launch": { - "dumpio": true, - "slowMo": 500, - "headless": process.env.HEADLESS_TEST || false, - "userDataDir": "./data/test-chrome-profile", - args: [ - "--disable-setuid-sandbox", - "--disable-gpu", - "--disable-dev-shm-usage", - "--no-default-browser-check", - "--no-experiments", - "--no-first-run", - "--no-pings", - "--no-sandbox", - "--no-zygote", - "--single-process", - ], - } -}; diff --git a/config/jest.config.js b/config/jest.config.js deleted file mode 100644 index 2d3f585ef..000000000 --- a/config/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - "verbose": true, - "preset": "jest-puppeteer", - "globals": { - "__DEV__": true - }, - "testRegex": "./test/e2e.spec.js", - "testEnvironment": "./config/jest-debug-env.js", - "rootDir": "..", - "testTimeout": 30000, -}; - diff --git a/config/vite.config.js b/config/vite.config.js index 4e642f018..5b2dec2eb 100644 --- a/config/vite.config.js +++ b/config/vite.config.js @@ -3,6 +3,7 @@ import vue from "@vitejs/plugin-vue"; import { defineConfig } from "vite"; import visualizer from "rollup-plugin-visualizer"; import viteCompression from "vite-plugin-compression"; +import commonjs from "vite-plugin-commonjs"; const postCssScss = require("postcss-scss"); const postcssRTLCSS = require("postcss-rtlcss"); @@ -17,8 +18,12 @@ export default defineConfig({ }, define: { "FRONTEND_VERSION": JSON.stringify(process.env.npm_package_version), + "DEVCONTAINER": JSON.stringify(process.env.DEVCONTAINER), + "GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN": JSON.stringify(process.env.GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN), + "CODESPACE_NAME": JSON.stringify(process.env.CODESPACE_NAME), }, plugins: [ + commonjs(), vue(), legacy({ targets: [ "since 2015" ], @@ -43,6 +48,9 @@ export default defineConfig({ } }, build: { + commonjsOptions: { + include: [ /.js$/ ], + }, rollupOptions: { output: { manualChunks(id, { getModuleInfo, getModuleIds }) { diff --git a/cypress.config.ts b/cypress.config.ts deleted file mode 100644 index d97e08758..000000000 --- a/cypress.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from "cypress"; - -export default defineConfig({ - e2e: { - baseUrl: "http://localhost:3002", - defaultCommandTimeout: 10000, - pageLoadTimeout: 60000, - viewportWidth: 1920, - viewportHeight: 1080, - specPattern: ["cypress/e2e/setup.cy.ts", "cypress/e2e/**/*.ts"], - }, - env: { - baseUrl: "http://localhost:3002", - }, -}); diff --git a/cypress/e2e/setup.cy.ts b/cypress/e2e/setup.cy.ts deleted file mode 100644 index 94e18edef..000000000 --- a/cypress/e2e/setup.cy.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { actor } from "../support/actors/actor"; -import { DEFAULT_USER_DATA } from "../support/const/user-data"; -import { DashboardPage } from "../support/pages/dasboard-page"; -import { SetupPage } from "../support/pages/setup-page"; - -describe("user can create a new account on setup page", () => { - before(() => { - cy.visit("/setup"); - }); - - it("user can create new account", () => { - cy.url().should("be.equal", SetupPage.url); - actor.setupTask.fillAndSubmitSetupForm( - DEFAULT_USER_DATA.username, - DEFAULT_USER_DATA.password, - DEFAULT_USER_DATA.password - ); - - cy.url().should("be.equal", DashboardPage.url); - cy.get('[role="alert"]') - .should("be.visible") - .and("contain.text", "Added Successfully."); - }); -}); diff --git a/cypress/support/actors/actor.ts b/cypress/support/actors/actor.ts deleted file mode 100644 index 680c26ce7..000000000 --- a/cypress/support/actors/actor.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SetupTask } from "../tasks/setup-task"; - -class Actor { - setupTask: SetupTask = new SetupTask(); -} - -const actor = new Actor(); -export { actor }; diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts deleted file mode 100644 index f887c29ae..000000000 --- a/cypress/support/e2e.ts +++ /dev/null @@ -1 +0,0 @@ -import "./commands"; diff --git a/cypress/support/tasks/setup-task.ts b/cypress/support/tasks/setup-task.ts deleted file mode 100644 index 866e3ca5c..000000000 --- a/cypress/support/tasks/setup-task.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { SetupPage } from "../pages/setup-page"; - -export class SetupTask { - fillAndSubmitSetupForm( - username: string, - password: string, - passwordRepeat: string - ) { - cy.get(SetupPage.usernameInput).type(username); - cy.get(SetupPage.passWordInput).type(password); - cy.get(SetupPage.passwordRepeatInput).type(passwordRepeat); - - cy.get(SetupPage.submitSetupForm).click(); - } -} diff --git a/db/knex_init_db.js b/db/knex_init_db.js new file mode 100644 index 000000000..2a27fa1d7 --- /dev/null +++ b/db/knex_init_db.js @@ -0,0 +1,559 @@ +const { R } = require("redbean-node"); +const { log } = require("../src/util"); + +/** + * ⚠️⚠️⚠️⚠️⚠️⚠️ DO NOT ADD ANYTHING HERE! + * IF YOU NEED TO ADD FIELDS, ADD IT TO ./db/knex_migrations + * See ./db/knex_migrations/README.md for more information + * @returns {Promise} + */ +async function createTables() { + log.info("mariadb", "Creating basic tables for MariaDB"); + const knex = R.knex; + + // TODO: Should check later if it is really the final patch sql file. + + // docker_host + await knex.schema.createTable("docker_host", (table) => { + table.increments("id"); + table.integer("user_id").unsigned().notNullable(); + table.string("docker_daemon", 255); + table.string("docker_type", 255); + table.string("name", 255); + }); + + // group + await knex.schema.createTable("group", (table) => { + table.increments("id"); + table.string("name", 255).notNullable(); + table.datetime("created_date").notNullable().defaultTo(knex.fn.now()); + table.boolean("public").notNullable().defaultTo(false); + table.boolean("active").notNullable().defaultTo(true); + table.integer("weight").notNullable().defaultTo(1000); + table.integer("status_page_id").unsigned(); + }); + + // proxy + await knex.schema.createTable("proxy", (table) => { + table.increments("id"); + table.integer("user_id").unsigned().notNullable(); + table.string("protocol", 10).notNullable(); + table.string("host", 255).notNullable(); + table.smallint("port").notNullable(); // TODO: Maybe a issue with MariaDB, need migration to int + table.boolean("auth").notNullable(); + table.string("username", 255).nullable(); + table.string("password", 255).nullable(); + table.boolean("active").notNullable().defaultTo(true); + table.boolean("default").notNullable().defaultTo(false); + table.datetime("created_date").notNullable().defaultTo(knex.fn.now()); + + table.index("user_id", "proxy_user_id"); + }); + + // user + await knex.schema.createTable("user", (table) => { + table.increments("id"); + table.string("username", 255).notNullable().unique().collate("utf8_general_ci"); + table.string("password", 255); + table.boolean("active").notNullable().defaultTo(true); + table.string("timezone", 150); + table.string("twofa_secret", 64); + table.boolean("twofa_status").notNullable().defaultTo(false); + table.string("twofa_last_token", 6); + }); + + // monitor + await knex.schema.createTable("monitor", (table) => { + table.increments("id"); + table.string("name", 150); + table.boolean("active").notNullable().defaultTo(true); + table.integer("user_id").unsigned() + .references("id").inTable("user") + .onDelete("SET NULL") + .onUpdate("CASCADE"); + table.integer("interval").notNullable().defaultTo(20); + table.text("url"); + table.string("type", 20); + table.integer("weight").defaultTo(2000); + table.string("hostname", 255); + table.integer("port"); + table.datetime("created_date").notNullable().defaultTo(knex.fn.now()); + table.string("keyword", 255); + table.integer("maxretries").notNullable().defaultTo(0); + table.boolean("ignore_tls").notNullable().defaultTo(false); + table.boolean("upside_down").notNullable().defaultTo(false); + table.integer("maxredirects").notNullable().defaultTo(10); + table.text("accepted_statuscodes_json").notNullable().defaultTo("[\"200-299\"]"); + table.string("dns_resolve_type", 5); + table.string("dns_resolve_server", 255); + table.string("dns_last_result", 255); + table.integer("retry_interval").notNullable().defaultTo(0); + table.string("push_token", 20).defaultTo(null); + table.text("method").notNullable().defaultTo("GET"); + table.text("body").defaultTo(null); + table.text("headers").defaultTo(null); + table.text("basic_auth_user").defaultTo(null); + table.text("basic_auth_pass").defaultTo(null); + table.integer("docker_host").unsigned() + .references("id").inTable("docker_host"); + table.string("docker_container", 255); + table.integer("proxy_id").unsigned() + .references("id").inTable("proxy"); + table.boolean("expiry_notification").defaultTo(true); + table.text("mqtt_topic"); + table.string("mqtt_success_message", 255); + table.string("mqtt_username", 255); + table.string("mqtt_password", 255); + table.string("database_connection_string", 2000); + table.text("database_query"); + table.string("auth_method", 250); + table.text("auth_domain"); + table.text("auth_workstation"); + table.string("grpc_url", 255).defaultTo(null); + table.text("grpc_protobuf").defaultTo(null); + table.text("grpc_body").defaultTo(null); + table.text("grpc_metadata").defaultTo(null); + table.text("grpc_method").defaultTo(null); + table.text("grpc_service_name").defaultTo(null); + table.boolean("grpc_enable_tls").notNullable().defaultTo(false); + table.string("radius_username", 255); + table.string("radius_password", 255); + table.string("radius_calling_station_id", 50); + table.string("radius_called_station_id", 50); + table.string("radius_secret", 255); + table.integer("resend_interval").notNullable().defaultTo(0); + table.integer("packet_size").notNullable().defaultTo(56); + table.string("game", 255); + }); + + // heartbeat + await knex.schema.createTable("heartbeat", (table) => { + table.increments("id"); + table.boolean("important").notNullable().defaultTo(false); + table.integer("monitor_id").unsigned().notNullable() + .references("id").inTable("monitor") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.smallint("status").notNullable(); + + table.text("msg"); + table.datetime("time").notNullable(); + table.integer("ping"); + table.integer("duration").notNullable().defaultTo(0); + table.integer("down_count").notNullable().defaultTo(0); + + table.index("important"); + table.index([ "monitor_id", "time" ], "monitor_time_index"); + table.index("monitor_id"); + table.index([ "monitor_id", "important", "time" ], "monitor_important_time_index"); + }); + + // incident + await knex.schema.createTable("incident", (table) => { + table.increments("id"); + table.string("title", 255).notNullable(); + table.text("content", 255).notNullable(); + table.string("style", 30).notNullable().defaultTo("warning"); + table.datetime("created_date").notNullable().defaultTo(knex.fn.now()); + table.datetime("last_updated_date"); + table.boolean("pin").notNullable().defaultTo(true); + table.boolean("active").notNullable().defaultTo(true); + table.integer("status_page_id").unsigned(); + }); + + // maintenance + await knex.schema.createTable("maintenance", (table) => { + table.increments("id"); + table.string("title", 150).notNullable(); + table.text("description").notNullable(); + table.integer("user_id").unsigned() + .references("id").inTable("user") + .onDelete("SET NULL") + .onUpdate("CASCADE"); + table.boolean("active").notNullable().defaultTo(true); + table.string("strategy", 50).notNullable().defaultTo("single"); + table.datetime("start_date"); + table.datetime("end_date"); + table.time("start_time"); + table.time("end_time"); + table.string("weekdays", 250).defaultTo("[]"); + table.text("days_of_month").defaultTo("[]"); + table.integer("interval_day"); + + table.index("active"); + table.index([ "strategy", "active" ], "manual_active"); + table.index("user_id", "maintenance_user_id"); + }); + + // status_page + await knex.schema.createTable("status_page", (table) => { + table.increments("id"); + table.string("slug", 255).notNullable().unique().collate("utf8_general_ci"); + table.string("title", 255).notNullable(); + table.text("description"); + table.string("icon", 255).notNullable(); + table.string("theme", 30).notNullable(); + table.boolean("published").notNullable().defaultTo(true); + table.boolean("search_engine_index").notNullable().defaultTo(true); + table.boolean("show_tags").notNullable().defaultTo(false); + table.string("password"); + table.datetime("created_date").notNullable().defaultTo(knex.fn.now()); + table.datetime("modified_date").notNullable().defaultTo(knex.fn.now()); + table.text("footer_text"); + table.text("custom_css"); + table.boolean("show_powered_by").notNullable().defaultTo(true); + table.string("google_analytics_tag_id"); + }); + + // maintenance_status_page + await knex.schema.createTable("maintenance_status_page", (table) => { + table.increments("id"); + + table.integer("status_page_id").unsigned().notNullable() + .references("id").inTable("status_page") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + + table.integer("maintenance_id").unsigned().notNullable() + .references("id").inTable("maintenance") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + }); + + // maintenance_timeslot + await knex.schema.createTable("maintenance_timeslot", (table) => { + table.increments("id"); + table.integer("maintenance_id").unsigned().notNullable() + .references("id").inTable("maintenance") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.datetime("start_date").notNullable(); + table.datetime("end_date"); + table.boolean("generated_next").defaultTo(false); + + table.index("maintenance_id"); + table.index([ "maintenance_id", "start_date", "end_date" ], "active_timeslot_index"); + table.index("generated_next", "generated_next_index"); + }); + + // monitor_group + await knex.schema.createTable("monitor_group", (table) => { + table.increments("id"); + table.integer("monitor_id").unsigned().notNullable() + .references("id").inTable("monitor") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.integer("group_id").unsigned().notNullable() + .references("id").inTable("group") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.integer("weight").notNullable().defaultTo(1000); + table.boolean("send_url").notNullable().defaultTo(false); + + table.index([ "monitor_id", "group_id" ], "fk"); + }); + // monitor_maintenance + await knex.schema.createTable("monitor_maintenance", (table) => { + table.increments("id"); + table.integer("monitor_id").unsigned().notNullable() + .references("id").inTable("monitor") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.integer("maintenance_id").unsigned().notNullable() + .references("id").inTable("maintenance") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + + table.index("maintenance_id", "maintenance_id_index2"); + table.index("monitor_id", "monitor_id_index"); + }); + + // notification + await knex.schema.createTable("notification", (table) => { + table.increments("id"); + table.string("name", 255); + table.string("config", 255); // TODO: should use TEXT! + table.boolean("active").notNullable().defaultTo(true); + table.integer("user_id").unsigned(); + table.boolean("is_default").notNullable().defaultTo(false); + }); + + // monitor_notification + await knex.schema.createTable("monitor_notification", (table) => { + table.increments("id").unsigned(); // TODO: no auto increment???? + table.integer("monitor_id").unsigned().notNullable() + .references("id").inTable("monitor") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.integer("notification_id").unsigned().notNullable() + .references("id").inTable("notification") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + + table.index([ "monitor_id", "notification_id" ], "monitor_notification_index"); + }); + + // tag + await knex.schema.createTable("tag", (table) => { + table.increments("id"); + table.string("name", 255).notNullable(); + table.string("color", 255).notNullable(); + table.datetime("created_date").notNullable().defaultTo(knex.fn.now()); + }); + + // monitor_tag + await knex.schema.createTable("monitor_tag", (table) => { + table.increments("id"); + table.integer("monitor_id").unsigned().notNullable() + .references("id").inTable("monitor") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.integer("tag_id").unsigned().notNullable() + .references("id").inTable("tag") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.text("value"); + }); + + // monitor_tls_info + await knex.schema.createTable("monitor_tls_info", (table) => { + table.increments("id"); + table.integer("monitor_id").unsigned().notNullable(); //TODO: no fk ? + table.text("info_json"); + }); + + // notification_sent_history + await knex.schema.createTable("notification_sent_history", (table) => { + table.increments("id"); + table.string("type", 50).notNullable(); + table.integer("monitor_id").unsigned().notNullable(); + table.integer("days").notNullable(); + table.unique([ "type", "monitor_id", "days" ]); + table.index([ "type", "monitor_id", "days" ], "good_index"); + }); + + // setting + await knex.schema.createTable("setting", (table) => { + table.increments("id"); + table.string("key", 200).notNullable().unique().collate("utf8_general_ci"); + table.text("value"); + table.string("type", 20); + }); + + // status_page_cname + await knex.schema.createTable("status_page_cname", (table) => { + table.increments("id"); + table.integer("status_page_id").unsigned() + .references("id").inTable("status_page") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.string("domain").notNullable().unique().collate("utf8_general_ci"); + }); + + /********************* + * Converted Patch here + *********************/ + + // 2023-06-30-1348-http-body-encoding.js + // ALTER TABLE monitor ADD http_body_encoding VARCHAR(25); + // UPDATE monitor SET http_body_encoding = 'json' WHERE (type = 'http' or type = 'keyword') AND http_body_encoding IS NULL; + await knex.schema.table("monitor", function (table) { + table.string("http_body_encoding", 25); + }); + + await knex("monitor") + .where(function () { + this.where("type", "http").orWhere("type", "keyword"); + }) + .whereNull("http_body_encoding") + .update({ + http_body_encoding: "json", + }); + + // 2023-06-30-1354-add-description-monitor.js + // ALTER TABLE monitor ADD description TEXT default null; + await knex.schema.table("monitor", function (table) { + table.text("description").defaultTo(null); + }); + + // 2023-06-30-1357-api-key-table.js + /* + CREATE TABLE [api_key] ( + [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + [key] VARCHAR(255) NOT NULL, + [name] VARCHAR(255) NOT NULL, + [user_id] INTEGER NOT NULL, + [created_date] DATETIME DEFAULT (DATETIME('now')) NOT NULL, + [active] BOOLEAN DEFAULT 1 NOT NULL, + [expires] DATETIME DEFAULT NULL, + CONSTRAINT FK_user FOREIGN KEY ([user_id]) REFERENCES [user]([id]) ON DELETE CASCADE ON UPDATE CASCADE + ); + */ + await knex.schema.createTable("api_key", function (table) { + table.increments("id").primary(); + table.string("key", 255).notNullable(); + table.string("name", 255).notNullable(); + table.integer("user_id").unsigned().notNullable() + .references("id").inTable("user") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.dateTime("created_date").defaultTo(knex.fn.now()).notNullable(); + table.boolean("active").defaultTo(1).notNullable(); + table.dateTime("expires").defaultTo(null); + }); + + // 2023-06-30-1400-monitor-tls.js + /* + ALTER TABLE monitor + ADD tls_ca TEXT default null; + + ALTER TABLE monitor + ADD tls_cert TEXT default null; + + ALTER TABLE monitor + ADD tls_key TEXT default null; + */ + await knex.schema.table("monitor", function (table) { + table.text("tls_ca").defaultTo(null); + table.text("tls_cert").defaultTo(null); + table.text("tls_key").defaultTo(null); + }); + + // 2023-06-30-1401-maintenance-cron.js + /* + -- 999 characters. https://stackoverflow.com/questions/46134830/maximum-length-for-cron-job + DROP TABLE maintenance_timeslot; + ALTER TABLE maintenance ADD cron TEXT; + ALTER TABLE maintenance ADD timezone VARCHAR(255); + ALTER TABLE maintenance ADD duration INTEGER; + */ + await knex.schema + .dropTableIfExists("maintenance_timeslot") + .table("maintenance", function (table) { + table.text("cron"); + table.string("timezone", 255); + table.integer("duration"); + }); + + // 2023-06-30-1413-add-parent-monitor.js. + /* + ALTER TABLE monitor + ADD parent INTEGER REFERENCES [monitor] ([id]) ON DELETE SET NULL ON UPDATE CASCADE; + */ + await knex.schema.table("monitor", function (table) { + table.integer("parent").unsigned() + .references("id").inTable("monitor") + .onDelete("SET NULL") + .onUpdate("CASCADE"); + }); + + /* + patch-add-invert-keyword.sql + ALTER TABLE monitor + ADD invert_keyword BOOLEAN default 0 not null; + */ + await knex.schema.table("monitor", function (table) { + table.boolean("invert_keyword").defaultTo(0).notNullable(); + }); + + /* + patch-added-json-query.sql + ALTER TABLE monitor + ADD json_path TEXT; + + ALTER TABLE monitor + ADD expected_value VARCHAR(255); + */ + await knex.schema.table("monitor", function (table) { + table.text("json_path"); + table.string("expected_value", 255); + }); + + /* + patch-added-kafka-producer.sql + + ALTER TABLE monitor + ADD kafka_producer_topic VARCHAR(255); + +ALTER TABLE monitor + ADD kafka_producer_brokers TEXT; + +ALTER TABLE monitor + ADD kafka_producer_ssl INTEGER; + +ALTER TABLE monitor + ADD kafka_producer_allow_auto_topic_creation VARCHAR(255); + +ALTER TABLE monitor + ADD kafka_producer_sasl_options TEXT; + +ALTER TABLE monitor + ADD kafka_producer_message TEXT; + */ + await knex.schema.table("monitor", function (table) { + table.string("kafka_producer_topic", 255); + table.text("kafka_producer_brokers"); + table.integer("kafka_producer_ssl"); + table.string("kafka_producer_allow_auto_topic_creation", 255); + table.text("kafka_producer_sasl_options"); + table.text("kafka_producer_message"); + }); + + /* + patch-add-certificate-expiry-status-page.sql + ALTER TABLE status_page + ADD show_certificate_expiry BOOLEAN default 0 NOT NULL; + */ + await knex.schema.table("status_page", function (table) { + table.boolean("show_certificate_expiry").defaultTo(0).notNullable(); + }); + + /* + patch-monitor-oauth-cc.sql + ALTER TABLE monitor + ADD oauth_client_id TEXT default null; + +ALTER TABLE monitor + ADD oauth_client_secret TEXT default null; + +ALTER TABLE monitor + ADD oauth_token_url TEXT default null; + +ALTER TABLE monitor + ADD oauth_scopes TEXT default null; + +ALTER TABLE monitor + ADD oauth_auth_method TEXT default null; + */ + await knex.schema.table("monitor", function (table) { + table.text("oauth_client_id").defaultTo(null); + table.text("oauth_client_secret").defaultTo(null); + table.text("oauth_token_url").defaultTo(null); + table.text("oauth_scopes").defaultTo(null); + table.text("oauth_auth_method").defaultTo(null); + }); + + /* + patch-add-timeout-monitor.sql + ALTER TABLE monitor + ADD timeout DOUBLE default 0 not null; + */ + await knex.schema.table("monitor", function (table) { + table.double("timeout").defaultTo(0).notNullable(); + }); + + /* + patch-add-gamedig-given-port.sql + ALTER TABLE monitor + ADD gamedig_given_port_only BOOLEAN default 1 not null; + */ + await knex.schema.table("monitor", function (table) { + table.boolean("gamedig_given_port_only").defaultTo(1).notNullable(); + }); + + log.info("mariadb", "Created basic tables for MariaDB"); +} + +module.exports = { + createTables, +}; diff --git a/db/knex_migrations/2023-08-16-0000-create-uptime.js b/db/knex_migrations/2023-08-16-0000-create-uptime.js new file mode 100644 index 000000000..ab899311c --- /dev/null +++ b/db/knex_migrations/2023-08-16-0000-create-uptime.js @@ -0,0 +1,41 @@ +exports.up = function (knex) { + return knex.schema + .createTable("stat_minutely", function (table) { + table.increments("id"); + table.comment("This table contains the minutely aggregate statistics for each monitor"); + table.integer("monitor_id").unsigned().notNullable() + .references("id").inTable("monitor") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.integer("timestamp") + .notNullable() + .comment("Unix timestamp rounded down to the nearest minute"); + table.float("ping").notNullable().comment("Average ping in milliseconds"); + table.smallint("up").notNullable(); + table.smallint("down").notNullable(); + + table.unique([ "monitor_id", "timestamp" ]); + }) + .createTable("stat_daily", function (table) { + table.increments("id"); + table.comment("This table contains the daily aggregate statistics for each monitor"); + table.integer("monitor_id").unsigned().notNullable() + .references("id").inTable("monitor") + .onDelete("CASCADE") + .onUpdate("CASCADE"); + table.integer("timestamp") + .notNullable() + .comment("Unix timestamp rounded down to the nearest day"); + table.float("ping").notNullable().comment("Average ping in milliseconds"); + table.smallint("up").notNullable(); + table.smallint("down").notNullable(); + + table.unique([ "monitor_id", "timestamp" ]); + }); +}; + +exports.down = function (knex) { + return knex.schema + .dropTable("stat_minutely") + .dropTable("stat_daily"); +}; diff --git a/db/knex_migrations/2023-08-18-0301-heartbeat.js b/db/knex_migrations/2023-08-18-0301-heartbeat.js new file mode 100644 index 000000000..fe4152b48 --- /dev/null +++ b/db/knex_migrations/2023-08-18-0301-heartbeat.js @@ -0,0 +1,16 @@ +exports.up = function (knex) { + // Add new column heartbeat.end_time + return knex.schema + .alterTable("heartbeat", function (table) { + table.datetime("end_time").nullable().defaultTo(null); + }); + +}; + +exports.down = function (knex) { + // Rename heartbeat.start_time to heartbeat.time + return knex.schema + .alterTable("heartbeat", function (table) { + table.dropColumn("end_time"); + }); +}; diff --git a/db/knex_migrations/README.md b/db/knex_migrations/README.md new file mode 100644 index 000000000..4bebe3482 --- /dev/null +++ b/db/knex_migrations/README.md @@ -0,0 +1,55 @@ +## Info + +https://knexjs.org/guide/migrations.html#knexfile-in-other-languages + +## Basic rules +- All tables must have a primary key named `id` +- Filename format: `YYYY-MM-DD-HHMM-patch-name.js` +- Avoid native SQL syntax, use knex methods, because Uptime Kuma supports SQLite and MariaDB. + +## Template + +```js +exports.up = function(knex) { + +}; + +exports.down = function(knex) { + +}; + +// exports.config = { transaction: false }; +``` + +## Example + +Filename: 2023-06-30-1348-create-user-and-product.js + +```js +exports.up = function(knex) { + return knex.schema + .createTable('user', function (table) { + table.increments('id'); + table.string('first_name', 255).notNullable(); + table.string('last_name', 255).notNullable(); + }) + .createTable('product', function (table) { + table.increments('id'); + table.decimal('price').notNullable(); + table.string('name', 1000).notNullable(); + }).then(() => { + knex("products").insert([ + { price: 10, name: "Apple" }, + { price: 20, name: "Orange" }, + ]); + }); +}; + +exports.down = function(knex) { + return knex.schema + .dropTable("product") + .dropTable("user"); +}; +``` + +https://knexjs.org/guide/migrations.html#transactions-in-migrations diff --git a/db/old_migrations/README.md b/db/old_migrations/README.md new file mode 100644 index 000000000..3b2bd9640 --- /dev/null +++ b/db/old_migrations/README.md @@ -0,0 +1,3 @@ +# Don't create a new migration file here + +Please go to ./db/knex_migrations/README.md diff --git a/db/patch-2fa-invalidate-used-token.sql b/db/old_migrations/patch-2fa-invalidate-used-token.sql similarity index 100% rename from db/patch-2fa-invalidate-used-token.sql rename to db/old_migrations/patch-2fa-invalidate-used-token.sql diff --git a/db/patch-2fa.sql b/db/old_migrations/patch-2fa.sql similarity index 100% rename from db/patch-2fa.sql rename to db/old_migrations/patch-2fa.sql diff --git a/db/old_migrations/patch-add-certificate-expiry-status-page.sql b/db/old_migrations/patch-add-certificate-expiry-status-page.sql new file mode 100644 index 000000000..63a20105b --- /dev/null +++ b/db/old_migrations/patch-add-certificate-expiry-status-page.sql @@ -0,0 +1,7 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE status_page + ADD show_certificate_expiry BOOLEAN default 0 NOT NULL; + +COMMIT; diff --git a/db/patch-add-clickable-status-page-link.sql b/db/old_migrations/patch-add-clickable-status-page-link.sql similarity index 100% rename from db/patch-add-clickable-status-page-link.sql rename to db/old_migrations/patch-add-clickable-status-page-link.sql diff --git a/db/old_migrations/patch-add-description-monitor.sql b/db/old_migrations/patch-add-description-monitor.sql new file mode 100644 index 000000000..da1aa55bc --- /dev/null +++ b/db/old_migrations/patch-add-description-monitor.sql @@ -0,0 +1,7 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD description TEXT default null; + +COMMIT; diff --git a/db/patch-add-docker-columns.sql b/db/old_migrations/patch-add-docker-columns.sql similarity index 100% rename from db/patch-add-docker-columns.sql rename to db/old_migrations/patch-add-docker-columns.sql diff --git a/db/old_migrations/patch-add-gamedig-given-port.sql b/db/old_migrations/patch-add-gamedig-given-port.sql new file mode 100644 index 000000000..897a9c72f --- /dev/null +++ b/db/old_migrations/patch-add-gamedig-given-port.sql @@ -0,0 +1,7 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD gamedig_given_port_only BOOLEAN default 1 not null; + +COMMIT; diff --git a/db/old_migrations/patch-add-gamedig-monitor.sql b/db/old_migrations/patch-add-gamedig-monitor.sql new file mode 100644 index 000000000..061bed302 --- /dev/null +++ b/db/old_migrations/patch-add-gamedig-monitor.sql @@ -0,0 +1,5 @@ +BEGIN TRANSACTION; + + ALTER TABLE monitor + ADD game VARCHAR(255); + COMMIT diff --git a/db/old_migrations/patch-add-google-analytics-status-page-tag.sql b/db/old_migrations/patch-add-google-analytics-status-page-tag.sql new file mode 100644 index 000000000..5de6ff37b --- /dev/null +++ b/db/old_migrations/patch-add-google-analytics-status-page-tag.sql @@ -0,0 +1,4 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; +ALTER TABLE status_page ADD google_analytics_tag_id VARCHAR; +COMMIT; diff --git a/db/old_migrations/patch-add-invert-keyword.sql b/db/old_migrations/patch-add-invert-keyword.sql new file mode 100644 index 000000000..8ca199eed --- /dev/null +++ b/db/old_migrations/patch-add-invert-keyword.sql @@ -0,0 +1,7 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD invert_keyword BOOLEAN default 0 not null; + +COMMIT; diff --git a/db/patch-add-other-auth.sql b/db/old_migrations/patch-add-other-auth.sql similarity index 100% rename from db/patch-add-other-auth.sql rename to db/old_migrations/patch-add-other-auth.sql diff --git a/db/old_migrations/patch-add-parent-monitor.sql b/db/old_migrations/patch-add-parent-monitor.sql new file mode 100644 index 000000000..756ac5be2 --- /dev/null +++ b/db/old_migrations/patch-add-parent-monitor.sql @@ -0,0 +1,6 @@ +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD parent INTEGER REFERENCES [monitor] ([id]) ON DELETE SET NULL ON UPDATE CASCADE; + +COMMIT diff --git a/db/patch-add-radius-monitor.sql b/db/old_migrations/patch-add-radius-monitor.sql similarity index 100% rename from db/patch-add-radius-monitor.sql rename to db/old_migrations/patch-add-radius-monitor.sql diff --git a/db/patch-add-retry-interval-monitor.sql b/db/old_migrations/patch-add-retry-interval-monitor.sql similarity index 100% rename from db/patch-add-retry-interval-monitor.sql rename to db/old_migrations/patch-add-retry-interval-monitor.sql diff --git a/db/patch-add-sqlserver-monitor.sql b/db/old_migrations/patch-add-sqlserver-monitor.sql similarity index 100% rename from db/patch-add-sqlserver-monitor.sql rename to db/old_migrations/patch-add-sqlserver-monitor.sql diff --git a/db/old_migrations/patch-add-timeout-monitor.sql b/db/old_migrations/patch-add-timeout-monitor.sql new file mode 100644 index 000000000..32d49d1e2 --- /dev/null +++ b/db/old_migrations/patch-add-timeout-monitor.sql @@ -0,0 +1,6 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD timeout DOUBLE default 0 not null; +COMMIT; \ No newline at end of file diff --git a/db/old_migrations/patch-added-json-query.sql b/db/old_migrations/patch-added-json-query.sql new file mode 100644 index 000000000..d5b7f1a8f --- /dev/null +++ b/db/old_migrations/patch-added-json-query.sql @@ -0,0 +1,10 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD json_path TEXT; + +ALTER TABLE monitor + ADD expected_value VARCHAR(255); + +COMMIT; diff --git a/db/old_migrations/patch-added-kafka-producer.sql b/db/old_migrations/patch-added-kafka-producer.sql new file mode 100644 index 000000000..933d30b8f --- /dev/null +++ b/db/old_migrations/patch-added-kafka-producer.sql @@ -0,0 +1,22 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD kafka_producer_topic VARCHAR(255); + +ALTER TABLE monitor + ADD kafka_producer_brokers TEXT; + +ALTER TABLE monitor + ADD kafka_producer_ssl INTEGER; + +ALTER TABLE monitor + ADD kafka_producer_allow_auto_topic_creation VARCHAR(255); + +ALTER TABLE monitor + ADD kafka_producer_sasl_options TEXT; + +ALTER TABLE monitor + ADD kafka_producer_message TEXT; + +COMMIT; diff --git a/db/patch-added-mqtt-monitor.sql b/db/old_migrations/patch-added-mqtt-monitor.sql similarity index 100% rename from db/patch-added-mqtt-monitor.sql rename to db/old_migrations/patch-added-mqtt-monitor.sql diff --git a/db/old_migrations/patch-api-key-table.sql b/db/old_migrations/patch-api-key-table.sql new file mode 100644 index 000000000..fc3a405bf --- /dev/null +++ b/db/old_migrations/patch-api-key-table.sql @@ -0,0 +1,13 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; +CREATE TABLE [api_key] ( + [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + [key] VARCHAR(255) NOT NULL, + [name] VARCHAR(255) NOT NULL, + [user_id] INTEGER NOT NULL, + [created_date] DATETIME DEFAULT (DATETIME('now')) NOT NULL, + [active] BOOLEAN DEFAULT 1 NOT NULL, + [expires] DATETIME DEFAULT NULL, + CONSTRAINT FK_user FOREIGN KEY ([user_id]) REFERENCES [user]([id]) ON DELETE CASCADE ON UPDATE CASCADE +); +COMMIT; diff --git a/db/patch-group-table.sql b/db/old_migrations/patch-group-table.sql similarity index 100% rename from db/patch-group-table.sql rename to db/old_migrations/patch-group-table.sql diff --git a/db/old_migrations/patch-grpc-monitor.sql b/db/old_migrations/patch-grpc-monitor.sql new file mode 100644 index 000000000..bac024e8a --- /dev/null +++ b/db/old_migrations/patch-grpc-monitor.sql @@ -0,0 +1,25 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD grpc_url VARCHAR(255) default null; + +ALTER TABLE monitor + ADD grpc_protobuf TEXT default null; + +ALTER TABLE monitor + ADD grpc_body TEXT default null; + +ALTER TABLE monitor + ADD grpc_metadata TEXT default null; + +ALTER TABLE monitor + ADD grpc_method VARCHAR(255) default null; + +ALTER TABLE monitor + ADD grpc_service_name VARCHAR(255) default null; + +ALTER TABLE monitor + ADD grpc_enable_tls BOOLEAN default 0 not null; + +COMMIT; diff --git a/db/old_migrations/patch-http-body-encoding.sql b/db/old_migrations/patch-http-body-encoding.sql new file mode 100644 index 000000000..322c8b893 --- /dev/null +++ b/db/old_migrations/patch-http-body-encoding.sql @@ -0,0 +1,12 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor ADD http_body_encoding VARCHAR(25); + +COMMIT; + +BEGIN TRANSACTION; + +UPDATE monitor SET http_body_encoding = 'json' WHERE (type = 'http' or type = 'keyword') AND http_body_encoding IS NULL; + +COMMIT; diff --git a/db/patch-http-monitor-method-body-and-headers.sql b/db/old_migrations/patch-http-monitor-method-body-and-headers.sql similarity index 100% rename from db/patch-http-monitor-method-body-and-headers.sql rename to db/old_migrations/patch-http-monitor-method-body-and-headers.sql diff --git a/db/patch-improve-performance.sql b/db/old_migrations/patch-improve-performance.sql similarity index 100% rename from db/patch-improve-performance.sql rename to db/old_migrations/patch-improve-performance.sql diff --git a/db/patch-incident-table.sql b/db/old_migrations/patch-incident-table.sql similarity index 100% rename from db/patch-incident-table.sql rename to db/old_migrations/patch-incident-table.sql diff --git a/db/old_migrations/patch-maintenance-cron.sql b/db/old_migrations/patch-maintenance-cron.sql new file mode 100644 index 000000000..bc51b881b --- /dev/null +++ b/db/old_migrations/patch-maintenance-cron.sql @@ -0,0 +1,11 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +DROP TABLE maintenance_timeslot; + +-- 999 characters. https://stackoverflow.com/questions/46134830/maximum-length-for-cron-job +ALTER TABLE maintenance ADD cron TEXT; +ALTER TABLE maintenance ADD timezone VARCHAR(255); +ALTER TABLE maintenance ADD duration INTEGER; + +COMMIT; diff --git a/db/old_migrations/patch-maintenance-table2.sql b/db/old_migrations/patch-maintenance-table2.sql new file mode 100644 index 000000000..96b2ebde0 --- /dev/null +++ b/db/old_migrations/patch-maintenance-table2.sql @@ -0,0 +1,83 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +-- Just for someone who tested maintenance before (patch-maintenance-table.sql) +DROP TABLE IF EXISTS maintenance_status_page; +DROP TABLE IF EXISTS monitor_maintenance; +DROP TABLE IF EXISTS maintenance; +DROP TABLE IF EXISTS maintenance_timeslot; + +-- maintenance +CREATE TABLE [maintenance] ( + [id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + [title] VARCHAR(150) NOT NULL, + [description] TEXT NOT NULL, + [user_id] INTEGER REFERENCES [user]([id]) ON DELETE SET NULL ON UPDATE CASCADE, + [active] BOOLEAN NOT NULL DEFAULT 1, + [strategy] VARCHAR(50) NOT NULL DEFAULT 'single', + [start_date] DATETIME, + [end_date] DATETIME, + [start_time] TIME, + [end_time] TIME, + [weekdays] VARCHAR2(250) DEFAULT '[]', + [days_of_month] TEXT DEFAULT '[]', + [interval_day] INTEGER +); + +CREATE INDEX [manual_active] ON [maintenance] ( + [strategy], + [active] +); + +CREATE INDEX [active] ON [maintenance] ([active]); + +CREATE INDEX [maintenance_user_id] ON [maintenance] ([user_id]); + +-- maintenance_status_page +CREATE TABLE maintenance_status_page ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + status_page_id INTEGER NOT NULL, + maintenance_id INTEGER NOT NULL, + CONSTRAINT FK_maintenance FOREIGN KEY (maintenance_id) REFERENCES maintenance (id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_status_page FOREIGN KEY (status_page_id) REFERENCES status_page (id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX [status_page_id_index] + ON [maintenance_status_page]([status_page_id]); + +CREATE INDEX [maintenance_id_index] + ON [maintenance_status_page]([maintenance_id]); + +-- maintenance_timeslot +CREATE TABLE [maintenance_timeslot] ( + [id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + [maintenance_id] INTEGER NOT NULL CONSTRAINT [FK_maintenance] REFERENCES [maintenance]([id]) ON DELETE CASCADE ON UPDATE CASCADE, + [start_date] DATETIME NOT NULL, + [end_date] DATETIME, + [generated_next] BOOLEAN DEFAULT 0 +); + +CREATE INDEX [maintenance_id] ON [maintenance_timeslot] ([maintenance_id] DESC); + +CREATE INDEX [active_timeslot_index] ON [maintenance_timeslot] ( + [maintenance_id] DESC, + [start_date] DESC, + [end_date] DESC +); + +CREATE INDEX [generated_next_index] ON [maintenance_timeslot] ([generated_next]); + +-- monitor_maintenance +CREATE TABLE monitor_maintenance ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + monitor_id INTEGER NOT NULL, + maintenance_id INTEGER NOT NULL, + CONSTRAINT FK_maintenance FOREIGN KEY (maintenance_id) REFERENCES maintenance (id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_monitor FOREIGN KEY (monitor_id) REFERENCES monitor (id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX [maintenance_id_index2] ON [monitor_maintenance]([maintenance_id]); + +CREATE INDEX [monitor_id_index] ON [monitor_maintenance]([monitor_id]); + +COMMIT; diff --git a/db/patch-monitor-add-resend-interval.sql b/db/old_migrations/patch-monitor-add-resend-interval.sql similarity index 100% rename from db/patch-monitor-add-resend-interval.sql rename to db/old_migrations/patch-monitor-add-resend-interval.sql diff --git a/db/patch-monitor-basic-auth.sql b/db/old_migrations/patch-monitor-basic-auth.sql similarity index 100% rename from db/patch-monitor-basic-auth.sql rename to db/old_migrations/patch-monitor-basic-auth.sql diff --git a/db/patch-monitor-expiry-notification.sql b/db/old_migrations/patch-monitor-expiry-notification.sql similarity index 100% rename from db/patch-monitor-expiry-notification.sql rename to db/old_migrations/patch-monitor-expiry-notification.sql diff --git a/db/old_migrations/patch-monitor-oauth-cc.sql b/db/old_migrations/patch-monitor-oauth-cc.sql new file mode 100644 index 000000000..f33e95298 --- /dev/null +++ b/db/old_migrations/patch-monitor-oauth-cc.sql @@ -0,0 +1,19 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD oauth_client_id TEXT default null; + +ALTER TABLE monitor + ADD oauth_client_secret TEXT default null; + +ALTER TABLE monitor + ADD oauth_token_url TEXT default null; + +ALTER TABLE monitor + ADD oauth_scopes TEXT default null; + +ALTER TABLE monitor + ADD oauth_auth_method TEXT default null; + +COMMIT; diff --git a/db/patch-monitor-push_token.sql b/db/old_migrations/patch-monitor-push_token.sql similarity index 100% rename from db/patch-monitor-push_token.sql rename to db/old_migrations/patch-monitor-push_token.sql diff --git a/db/old_migrations/patch-monitor-tls.sql b/db/old_migrations/patch-monitor-tls.sql new file mode 100644 index 000000000..ac4edb798 --- /dev/null +++ b/db/old_migrations/patch-monitor-tls.sql @@ -0,0 +1,13 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD tls_ca TEXT default null; + +ALTER TABLE monitor + ADD tls_cert TEXT default null; + +ALTER TABLE monitor + ADD tls_key TEXT default null; + +COMMIT; diff --git a/db/patch-notification_sent_history.sql b/db/old_migrations/patch-notification_sent_history.sql similarity index 100% rename from db/patch-notification_sent_history.sql rename to db/old_migrations/patch-notification_sent_history.sql diff --git a/db/old_migrations/patch-ping-packet-size.sql b/db/old_migrations/patch-ping-packet-size.sql new file mode 100644 index 000000000..d65ec8ed8 --- /dev/null +++ b/db/old_migrations/patch-ping-packet-size.sql @@ -0,0 +1,5 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; +ALTER TABLE monitor + ADD packet_size INTEGER DEFAULT 56 NOT NULL; +COMMIT; diff --git a/db/patch-proxy.sql b/db/old_migrations/patch-proxy.sql similarity index 100% rename from db/patch-proxy.sql rename to db/old_migrations/patch-proxy.sql diff --git a/db/patch-setting-value-type.sql b/db/old_migrations/patch-setting-value-type.sql similarity index 100% rename from db/patch-setting-value-type.sql rename to db/old_migrations/patch-setting-value-type.sql diff --git a/db/patch-status-page-footer-css.sql b/db/old_migrations/patch-status-page-footer-css.sql similarity index 100% rename from db/patch-status-page-footer-css.sql rename to db/old_migrations/patch-status-page-footer-css.sql diff --git a/db/patch-status-page.sql b/db/old_migrations/patch-status-page.sql similarity index 100% rename from db/patch-status-page.sql rename to db/old_migrations/patch-status-page.sql diff --git a/db/patch1.sql b/db/old_migrations/patch1.sql similarity index 100% rename from db/patch1.sql rename to db/old_migrations/patch1.sql diff --git a/db/patch10.sql b/db/old_migrations/patch10.sql similarity index 100% rename from db/patch10.sql rename to db/old_migrations/patch10.sql diff --git a/db/patch2.sql b/db/old_migrations/patch2.sql similarity index 100% rename from db/patch2.sql rename to db/old_migrations/patch2.sql diff --git a/db/patch3.sql b/db/old_migrations/patch3.sql similarity index 100% rename from db/patch3.sql rename to db/old_migrations/patch3.sql diff --git a/db/patch4.sql b/db/old_migrations/patch4.sql similarity index 100% rename from db/patch4.sql rename to db/old_migrations/patch4.sql diff --git a/db/patch5.sql b/db/old_migrations/patch5.sql similarity index 100% rename from db/patch5.sql rename to db/old_migrations/patch5.sql diff --git a/db/patch6.sql b/db/old_migrations/patch6.sql similarity index 100% rename from db/patch6.sql rename to db/old_migrations/patch6.sql diff --git a/db/patch7.sql b/db/old_migrations/patch7.sql similarity index 100% rename from db/patch7.sql rename to db/old_migrations/patch7.sql diff --git a/db/patch8.sql b/db/old_migrations/patch8.sql similarity index 100% rename from db/patch8.sql rename to db/old_migrations/patch8.sql diff --git a/db/patch9.sql b/db/old_migrations/patch9.sql similarity index 100% rename from db/patch9.sql rename to db/old_migrations/patch9.sql diff --git a/docker/alpine-base.dockerfile b/docker/alpine-base.dockerfile deleted file mode 100644 index 1d74de05d..000000000 --- a/docker/alpine-base.dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -# DON'T UPDATE TO alpine3.13, 1.14, see #41. -FROM node:16-alpine3.12 -WORKDIR /app - -# Install apprise, iputils for non-root ping, setpriv -RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \ - pip3 --no-cache-dir install apprise==1.0.0 && \ - rm -rf /root/.cache diff --git a/docker/builder-go.dockerfile b/docker/builder-go.dockerfile new file mode 100644 index 000000000..1d25843bc --- /dev/null +++ b/docker/builder-go.dockerfile @@ -0,0 +1,16 @@ +############################################ +# Build in Golang +# Run npm run build-healthcheck-armv7 in the host first, another it will be super slow where it is building the armv7 healthcheck +############################################ +FROM golang:1.19-buster +WORKDIR /app +ARG TARGETPLATFORM +COPY ./extra/ ./extra/ + +# Compile healthcheck.go +RUN apt update && \ + apt --yes --no-install-recommends install curl && \ + curl -sL https://deb.nodesource.com/setup_18.x | bash && \ + apt --yes --no-install-recommends install nodejs && \ + node ./extra/build-healthcheck.js $TARGETPLATFORM && \ + apt --yes remove nodejs diff --git a/docker/debian-base.dockerfile b/docker/debian-base.dockerfile index 20bef3dd4..77b7d37fe 100644 --- a/docker/debian-base.dockerfile +++ b/docker/debian-base.dockerfile @@ -1,28 +1,51 @@ -# DON'T UPDATE TO node:14-bullseye-slim, see #372. # If the image changed, the second stage image should be changed too -FROM node:16-buster-slim +FROM node:20-bookworm-slim AS base2-slim ARG TARGETPLATFORM -WORKDIR /app - -# Install Curl -# Install Apprise, add sqlite3 cli for debugging in the future, iputils-ping for ping, util-linux for setpriv -# Stupid python3 and python3-pip actually install a lot of useless things into Debian, specify --no-install-recommends to skip them, make the base even smaller than alpine! -RUN apt update && \ - apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \ - sqlite3 iputils-ping util-linux dumb-init && \ - pip3 --no-cache-dir install apprise==1.0.0 && \ +# Specify --no-install-recommends to skip unused dependencies, make the base much smaller! +# apprise = for notifications (From testing repo) +# sqlite3 = for debugging +# iputils-ping = for ping +# util-linux = for setpriv (Should be dropped in 2.0.0?) +# dumb-init = avoid zombie processes (#480) +# curl = for debugging +# ca-certificates = keep the cert up-to-date +# sudo = for start service nscd with non-root user +# nscd = for better DNS caching +RUN echo "deb http://deb.debian.org/debian testing main" >> /etc/apt/sources.list && \ + apt update && \ + apt --yes --no-install-recommends -t testing install apprise sqlite3 ca-certificates && \ + apt --yes --no-install-recommends -t stable install \ + iputils-ping \ + util-linux \ + dumb-init \ + curl \ + sudo \ + nscd && \ rm -rf /var/lib/apt/lists/* && \ apt --yes autoremove + # Install cloudflared -# dpkg --add-architecture arm: cloudflared do not provide armhf, this is workaround. Read more: https://github.com/cloudflare/cloudflared/issues/583 -COPY extra/download-cloudflared.js ./extra/download-cloudflared.js -RUN node ./extra/download-cloudflared.js $TARGETPLATFORM && \ - dpkg --add-architecture arm && \ +RUN curl https://pkg.cloudflare.com/cloudflare-main.gpg --output /usr/share/keyrings/cloudflare-main.gpg && \ + echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared bullseye main' | tee /etc/apt/sources.list.d/cloudflared.list && \ apt update && \ - apt --yes --no-install-recommends install ./cloudflared.deb && \ + apt install --yes --no-install-recommends -t stable cloudflared && \ + cloudflared version && \ rm -rf /var/lib/apt/lists/* && \ - rm -f cloudflared.deb && \ apt --yes autoremove +# For nscd +COPY ./docker/etc/nscd.conf /etc/nscd.conf +COPY ./docker/etc/sudoers /etc/sudoers + + +# Full Base Image +# MariaDB, Chromium and fonts +FROM base2-slim AS base2 +ENV UPTIME_KUMA_ENABLE_EMBEDDED_MARIADB=1 +RUN apt update && \ + apt --yes --no-install-recommends install chromium fonts-indic fonts-noto fonts-noto-cjk mariadb-server && \ + rm -rf /var/lib/apt/lists/* && \ + apt --yes autoremove && \ + chown -R node:node /var/lib/mysql diff --git a/docker/docker-compose-dev.yml b/docker/docker-compose-dev.yml new file mode 100644 index 000000000..c66b24b58 --- /dev/null +++ b/docker/docker-compose-dev.yml @@ -0,0 +1,14 @@ +version: '3.8' + +services: + uptime-kuma: + container_name: uptime-kuma-dev + image: louislam/uptime-kuma:nightly2 + volumes: + #- ./data:/app/data + - ../server:/app/server + - ../db:/app/db + ports: + - "3001:3001" # : + - "3307:3306" + diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index f5c8f3661..20e373292 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,14 +1,15 @@ -# Simple docker-compose.yml -# You can change your port or volume location - -version: '3.3' +version: '3.8' services: uptime-kuma: - image: louislam/uptime-kuma:1 + image: louislam/uptime-kuma:2 container_name: uptime-kuma volumes: - - ./uptime-kuma-data:/app/data + - uptime-kuma:/app/data ports: - - 3001:3001 # : + - "3001:3001" # : restart: always + +volumes: + uptime-kuma: + diff --git a/docker/dockerfile b/docker/dockerfile index eea6ba33d..719cba5c5 100644 --- a/docker/dockerfile +++ b/docker/dockerfile @@ -1,34 +1,57 @@ -FROM louislam/uptime-kuma:base-debian AS build +ARG BASE_IMAGE=louislam/uptime-kuma:base2 + +############################################ +# Build in Golang +# Run npm run build-healthcheck-armv7 in the host first, otherwise it will be super slow where it is building the armv7 healthcheck +# Check file: builder-go.dockerfile +############################################ +FROM louislam/uptime-kuma:builder-go AS build_healthcheck + +############################################ +# Build in Node.js +############################################ +FROM louislam/uptime-kuma:base2 AS build +USER node WORKDIR /app ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 - +COPY --chown=node:node .npmrc .npmrc +COPY --chown=node:node package.json package.json +COPY --chown=node:node package-lock.json package-lock.json +RUN npm ci --omit=dev COPY . . -RUN npm ci --production && \ - chmod +x /app/extra/entrypoint.sh +COPY --chown=node:node --from=build_healthcheck /app/extra/healthcheck /app/extra/healthcheck +RUN mkdir ./data - -FROM louislam/uptime-kuma:base-debian AS release +############################################ +# ⭐ Main Image +############################################ +FROM $BASE_IMAGE AS release +USER node WORKDIR /app +ENV UPTIME_KUMA_IS_CONTAINER=1 + # Copy app files from build layer -COPY --from=build /app /app +COPY --chown=node:node --from=build /app /app EXPOSE 3001 -VOLUME ["/app/data"] -HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js -ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"] +HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD extra/healthcheck +ENTRYPOINT ["/usr/bin/dumb-init", "--"] CMD ["node", "server/server.js"] - +############################################ +# Mark as Nightly +############################################ FROM release AS nightly +USER node RUN npm run mark-as-nightly +############################################ # Build an image for testing pr -FROM louislam/uptime-kuma:base-debian AS pr-test - +############################################ +FROM louislam/uptime-kuma:base2 AS pr-test2 WORKDIR /app - ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 ## Install Git @@ -50,13 +73,13 @@ RUN git clone https://github.com/louislam/uptime-kuma.git . RUN npm ci EXPOSE 3000 3001 -VOLUME ["/app/data"] -HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js +HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD extra/healthcheck CMD ["npm", "run", "start-pr-test"] - +############################################ # Upload the artifact to Github -FROM louislam/uptime-kuma:base-debian AS upload-artifact +############################################ +FROM louislam/uptime-kuma:base2 AS upload-artifact WORKDIR / RUN apt update && \ apt --yes install curl file diff --git a/docker/dockerfile-alpine b/docker/dockerfile-alpine deleted file mode 100644 index ab9255f95..000000000 --- a/docker/dockerfile-alpine +++ /dev/null @@ -1,25 +0,0 @@ -FROM louislam/uptime-kuma:base-alpine AS build -WORKDIR /app - -ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 - -COPY . . -RUN npm ci --production && \ - chmod +x /app/extra/entrypoint.sh - - -FROM louislam/uptime-kuma:base-alpine AS release -WORKDIR /app - -# Copy app files from build layer -COPY --from=build /app /app - -EXPOSE 3001 -VOLUME ["/app/data"] -HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js -ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"] -CMD ["node", "server/server.js"] - - -FROM release AS nightly -RUN npm run mark-as-nightly diff --git a/docker/etc/nscd.conf b/docker/etc/nscd.conf new file mode 100644 index 000000000..18b92bfee --- /dev/null +++ b/docker/etc/nscd.conf @@ -0,0 +1,90 @@ +# +# /etc/nscd.conf +# +# An example Name Service Cache config file. This file is needed by nscd. +# +# Legal entries are: +# +# logfile +# debug-level +# threads +# max-threads +# server-user +# server-user is ignored if nscd is started with -S parameters +# stat-user +# reload-count unlimited| +# paranoia +# restart-interval