diff --git a/examples/nodeproj/.eslintrc.json b/examples/nodeproj/.eslintrc.json new file mode 100644 index 0000000..b8358c7 --- /dev/null +++ b/examples/nodeproj/.eslintrc.json @@ -0,0 +1,71 @@ +{ + "env": { + "node": true, + "es6": true + }, + "settings": { + "import/resolver": { + "node": { + "extensions": [".js", ".mjs", ".ts", ".cjs"] + } + } + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", + "allowImportExportEverywhere": true + }, + "extends": [ + "eslint:recommended", + "plugin:import/errors", + "plugin:import/warnings", + "plugin:import/typescript", + "plugin:promise/recommended", + "google", + "plugin:security/recommended" + ], + "plugins": ["promise", "security", "import"], + "overrides": [ + { + "files": "public/**/*.min.js", + "env": { + "browser": true, + "node": false, + "es6": false + }, + "parserOptions": { + "sourceType": "script" + }, + "extends": ["plugin:compat/recommended"], + "plugins": [], + "rules": { + "no-var": ["off"] + } + } + ], + "rules": { + "security/detect-non-literal-fs-filename":["off"], + "security/detect-object-injection":["off"], + "camelcase": ["off"], + "no-console": ["off"], + "require-jsdoc": ["off"], + "one-var": ["off"], + "guard-for-in": ["off"], + "max-len": [ + "warn", + { + "ignoreComments": true, + "ignoreTrailingComments": true, + "ignoreUrls": true, + "code": 200 + } + ], + "indent": ["warn", 4], + "no-unused-vars": ["warn"], + "no-extra-semi": ["warn"], + "linebreak-style": ["error", "unix"], + "quotes": ["warn", "double"], + "semi": ["error", "always"] + } +} diff --git a/examples/nodeproj/.gitignore b/examples/nodeproj/.gitignore new file mode 100644 index 0000000..97caa7e --- /dev/null +++ b/examples/nodeproj/.gitignore @@ -0,0 +1,7 @@ +charmander-local.rc +.DS_Store +*~ +*.seed +*.log +*.pid +node_modules diff --git a/examples/nodeproj/.home/.gitignore b/examples/nodeproj/.home/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/examples/nodeproj/.home/.gitignore @@ -0,0 +1 @@ +* diff --git a/examples/nodeproj/README.md b/examples/nodeproj/README.md new file mode 100644 index 0000000..55878ae --- /dev/null +++ b/examples/nodeproj/README.md @@ -0,0 +1,11 @@ +# How to run example + + + +``` +cp example.env local.env +podman-compose build +podman-compose run --rm --no-deps init +podman-compose up +``` + diff --git a/examples/nodeproj/containers/node16-runtime/Dockerfile b/examples/nodeproj/containers/node16-runtime/Dockerfile new file mode 100644 index 0000000..f6fe16b --- /dev/null +++ b/examples/nodeproj/containers/node16-runtime/Dockerfile @@ -0,0 +1,12 @@ +FROM registry.fedoraproject.org/fedora-minimal:35 +ARG NODE_VER=16 +# microdnf -y module enable nodejs:${NODE_VER} +RUN \ + echo -e "[nodejs]\nname=nodejs\nstream=${NODE_VER}\nprofiles=\nstate=enabled\n" > /etc/dnf/modules.d/nodejs.module && \ + microdnf -y install shadow-utils nodejs zopfli findutils busybox && \ + microdnf clean all +RUN adduser -d /app app && mkdir -p /app/code/.home && chown app:app -R /app/code && chmod 711 /app /app/code/.home && usermod -d /app/code/.home app +ENV XDG_CONFIG_HOME=/app/code/.home +ENV HOME=/app/code/.home +WORKDIR /app/code + diff --git a/examples/nodeproj/docker-compose.yml b/examples/nodeproj/docker-compose.yml new file mode 100644 index 0000000..b7efa02 --- /dev/null +++ b/examples/nodeproj/docker-compose.yml @@ -0,0 +1,47 @@ +version: '3' +volumes: + redis: +services: + redis: + read_only: true + image: docker.io/redis:alpine + command: ["redis-server", "--appendonly", "yes", "--notify-keyspace-events", "Ex"] + volumes: + - redis:/data + tmpfs: + - /tmp + - /var/run + - /run + init: + read_only: true + userns_mode: keep-id + build: + context: ./containers/${NODE_IMG:-node16-runtime} + image: ${NODE_IMG:-node16-runtime} + env_file: + - local.env + volumes: + - .:/app/code + command: ["/bin/sh", "-c", "mkdir -p ~/; [ -d ./node_modules ] && echo '** node_modules exists' || npm install"] + tmpfs: + - /tmp + - /run + task: + extends: + service: init + command: ["npm", "run", "cli", "--", "task"] + links: + - redis + depends_on: + - redis + web: + extends: + service: init + command: ["npm", "run", "cli", "--", "web"] + ports: + - ${WEB_LISTEN_PORT:-3000}:3000 + depends_on: + - redis + links: + - mongo + diff --git a/examples/nodeproj/example.env b/examples/nodeproj/example.env new file mode 100644 index 0000000..64703d0 --- /dev/null +++ b/examples/nodeproj/example.env @@ -0,0 +1,2 @@ +REDIS_HOST=redis + diff --git a/examples/nodeproj/index.js b/examples/nodeproj/index.js new file mode 100644 index 0000000..47ab777 --- /dev/null +++ b/examples/nodeproj/index.js @@ -0,0 +1,6 @@ +#! /usr/bin/env node +"use strict"; +import {start} from "./lib"; + +start(); + diff --git a/examples/nodeproj/jsconfig.json b/examples/nodeproj/jsconfig.json new file mode 100644 index 0000000..2a82f36 --- /dev/null +++ b/examples/nodeproj/jsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "es2020", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true + }, + "files": [ + "index.js" + ], + "include": [ + "lib/**/*.js" + ] +} \ No newline at end of file diff --git a/examples/nodeproj/lib/commands/task.js b/examples/nodeproj/lib/commands/task.js new file mode 100644 index 0000000..d3abe45 --- /dev/null +++ b/examples/nodeproj/lib/commands/task.js @@ -0,0 +1,31 @@ +"use strict"; +import {proj} from "../proj"; + +async function loop() { + const poped = await proj.predis.blpop("queue", 5); + const task_desc_s = poped[1]; + let task_desc; + try { + task_desc = JSON.parse(task_desc_s); + } catch (e) { + proj.logger.exception(e); + } + proj.logger.info("got task "+task_desc.func); + const func = task_desc.func; + const args = task_desc.args; + if (typeof(proj.tasks[func])!="function") { + console.log(`task ${func} not found`); + process.exit(-1) + } + try { + await ((this.tasks[func])(...args)); + } catch (e) { + console.exception(e); + } +} + +export async function start() { + while(true) { + loop(); + } +} diff --git a/examples/nodeproj/lib/commands/web.js b/examples/nodeproj/lib/commands/web.js new file mode 100644 index 0000000..b05dabd --- /dev/null +++ b/examples/nodeproj/lib/commands/web.js @@ -0,0 +1,22 @@ +"use strict"; +import {proj} from "../proj"; + +import http from "http"; +import express from "express"; + + +export async function start() { + const app = express(); + app.use(proj.logger.express_logger); + const server = http.createServer(app); + + // Routing + app.use(express.static(proj.config.basedir + "/public")); + app.get("/healthz", function(req, res) { + res.send("ok@"+Date.now()); + }); + + server.listen(proj.config.LISTEN_PORT, proj.config.LISTEN_HOST, function() { + proj.logger.warn(`listening at port ${proj.config.LISTEN_PORT}`); + }); +} diff --git a/examples/nodeproj/package.json b/examples/nodeproj/package.json new file mode 100644 index 0000000..5e11d5b --- /dev/null +++ b/examples/nodeproj/package.json @@ -0,0 +1,24 @@ +{ + "name": "nodeproj", + "version": "0.0.1", + "description": "nodejs example project", + "exports": { + ".": "./index.js", + "./lib": "./lib" + }, + "main": "index.js", + "type": "module", + "scripts": { + "cli": "nodemon -w lib -w index.js --es-module-specifier-resolution=node ./index.mjs" + }, + "dependencies": { + "express": "~4.16.4", + "redis": "^3.1.2" + }, + "private": true, + "author": "", + "license": "proprietary", + "devDependencies": { + "nodemon": "^2.0.14" + } +} diff --git a/examples/nodeproj/public/index.html b/examples/nodeproj/public/index.html new file mode 100644 index 0000000..1b2ec9d --- /dev/null +++ b/examples/nodeproj/public/index.html @@ -0,0 +1,18 @@ + + +
+This is a paragraph.
+ + + + diff --git a/podman_compose.py b/podman_compose.py index 3e9a97b..618e3c3 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -863,6 +863,10 @@ def container_to_args(compose, cnt, detached=True): raise TypeError("port should be either string or dict") podman_args.extend(["-p", port]) + userns_mode = cnt.get("userns_mode", None) + if userns_mode is not None: + podman_args.extend(["--userns", userns_mode]) + user = cnt.get("user", None) if user is not None: podman_args.extend(["-u", user])