From 928730b7b95d93d659e04fef2dcfc36dbe67d28e Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Tue, 17 Dec 2024 12:53:31 +0100 Subject: [PATCH 1/4] Update tag-from-version.yml (#44) --- .github/workflows/tag-from-version.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tag-from-version.yml b/.github/workflows/tag-from-version.yml index e2dfea8..444be2d 100644 --- a/.github/workflows/tag-from-version.yml +++ b/.github/workflows/tag-from-version.yml @@ -30,13 +30,18 @@ jobs: version=$(cat .version | tr -d '[:space:]') echo "version=$version" >> $GITHUB_ENV + - name: Configure git + run: | + # Set up Git with an identifiable user + git config --global user.name cisco-service + git config --global user.email 111539563+cisco-service@users.noreply.github.com + # Create a tag with the version - name: Create and push tag - env: GH_TOKEN: ${{ secrets.CISCO_SERVICE_GITHUB_AUTOMATION_TOKEN }} run: | - git config user.name cisco-service - git config user.email 111539563+cisco-service@users.noreply.github.com - git tag $version + # Add a custom tag message + tag_message="Tag created by ${{ github.actor }} via GitHub Actions." + git tag -a "$version" -m "$tag_message" git push origin $version From cfcd8205a746cd4946398add60f006ce85909af5 Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Tue, 17 Dec 2024 12:53:43 +0100 Subject: [PATCH 2/4] Update tag-from-version.yml (#44) From be39c4591b46652686bcfd82f11587e95a25b14f Mon Sep 17 00:00:00 2001 From: Alexander Stoklasa Date: Tue, 17 Dec 2024 14:24:59 +0100 Subject: [PATCH 3/4] initial commit mysql service (#33) * initial commit mysql service * moved mysql service to it's own section in /src * moved mysql folder to src/databases/mysql * updated reusable workflow --- .github/workflows/build-images-on-commit.yml | 1 + .github/workflows/build-images-on-pr.yml | 1 + .../reusable-build-container-images.yml | 2 ++ scripts/build.sh | 10 ++++++ src/databases/mysql/Dockerfile | 9 +++++ src/databases/mysql/setup.php | 33 +++++++++++++++++++ src/databases/mysql/setup.sh | 3 ++ 7 files changed, 59 insertions(+) create mode 100644 src/databases/mysql/Dockerfile create mode 100644 src/databases/mysql/setup.php create mode 100644 src/databases/mysql/setup.sh diff --git a/.github/workflows/build-images-on-commit.yml b/.github/workflows/build-images-on-commit.yml index 65f9c40..a7105a2 100644 --- a/.github/workflows/build-images-on-commit.yml +++ b/.github/workflows/build-images-on-commit.yml @@ -6,6 +6,7 @@ on: paths: - "src/loaders/**" - "src/services/**" + - "src/databases/**" - ".version" - ".github/workflows/reusable-build-container-images.yml" - ".github/workflows/build-images-on-commit.yml" diff --git a/.github/workflows/build-images-on-pr.yml b/.github/workflows/build-images-on-pr.yml index 2d98f30..1dc62ba 100644 --- a/.github/workflows/build-images-on-pr.yml +++ b/.github/workflows/build-images-on-pr.yml @@ -6,6 +6,7 @@ on: paths: - "src/loaders/**" - "src/services/**" + - "src/databases/**" - ".version" - ".github/workflows/reusable-build-container-images.yml" - ".github/workflows/check.yml" diff --git a/.github/workflows/reusable-build-container-images.yml b/.github/workflows/reusable-build-container-images.yml index 65716f6..0e1858c 100644 --- a/.github/workflows/reusable-build-container-images.yml +++ b/.github/workflows/reusable-build-container-images.yml @@ -22,6 +22,8 @@ jobs: name: loaders-curl - context: ./src/services/java name: services-java + - context: ./src/databases/mysql + name: databases-mysql steps: - name: Checkout uses: actions/checkout@v4.2.2 diff --git a/scripts/build.sh b/scripts/build.sh index 06ae215..d81b1ac 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -56,6 +56,15 @@ for DIR in "${REPO_DIR}/src/services"/*; do fi done +for DIR in "${REPO_DIR}/src/databases"/*; do + if [ -d "$DIR" ]; then + IMAGE_TAG="${REPO_PREFIX}/${IMAGE_PREFIX}-databases-$(basename "$DIR"):$VERSION" + echo "Building $IMAGE_TAG..." + echo "Running 'docker buildx build --platform $PLATFORM -t $IMAGE_TAG $DIR $PUSH'" + docker buildx build --platform "$PLATFORM" -t "$IMAGE_TAG" $PUSH "$DIR" $PUSH + fi +done + for DIR in "${REPO_DIR}/src/loaders"/*; do if [ -d "$DIR" ]; then IMAGE_TAG="${REPO_PREFIX}/${IMAGE_PREFIX}-loaders-$(basename "$DIR"):$VERSION" @@ -64,3 +73,4 @@ for DIR in "${REPO_DIR}/src/loaders"/*; do docker buildx build --platform "$PLATFORM" -t "$IMAGE_TAG" $PUSH "$DIR" $PUSH fi done + diff --git a/src/databases/mysql/Dockerfile b/src/databases/mysql/Dockerfile new file mode 100644 index 0000000..5760d1e --- /dev/null +++ b/src/databases/mysql/Dockerfile @@ -0,0 +1,9 @@ +FROM mysql:5.7 + +LABEL org.opencontainers.image.source=https://github.com/cisco-open/app-simulator +LABEL org.opencontainers.image.description="mysql database for app-simulator" +LABEL org.opencontainers.image.licenses=BSD-3-Clause + +RUN yum install -y php-cli && yum clean all +COPY setup.php /tmp/ +COPY setup.sh /docker-entrypoint-initdb.d/ diff --git a/src/databases/mysql/setup.php b/src/databases/mysql/setup.php new file mode 100644 index 0000000..d53ccd7 --- /dev/null +++ b/src/databases/mysql/setup.php @@ -0,0 +1,33 @@ +databases as $database => $tables) { + $result .= "CREATE DATABASE ".$database.";".PHP_EOL; + $result .= "USE ".$database.";".PHP_EOL; + foreach($tables as $table => $columns) { + $result .="CREATE TABLE ".$table." (".PHP_EOL; + foreach($columns as $column) { + if($column === 'id') { + $result .= " ".$column." INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,".PHP_EOL; + } else { + $result .= " ".$column. " VARCHAR(255),".PHP_EOL; + } + } + + $result = substr($result,0,-2).PHP_EOL; + + $result .=') ENGINE=InnoDB;'.PHP_EOL; + } +} + +echo '=====.PHP_EOL'; + +echo $result; + +echo '=====.PHP_EOL'; + +file_put_contents("/tmp/create.sql",$result); diff --git a/src/databases/mysql/setup.sh b/src/databases/mysql/setup.sh new file mode 100644 index 0000000..abd0cda --- /dev/null +++ b/src/databases/mysql/setup.sh @@ -0,0 +1,3 @@ +#!/bin/bash +APP_CONFIG="$( Date: Tue, 17 Dec 2024 14:40:42 +0100 Subject: [PATCH 4/4] initial commit cleand up nodejs service (#36) --- .../reusable-build-container-images.yml | 2 + .gitignore | 7 +- src/loaders/curl/Dockerfile | 2 +- src/services/java/Dockerfile | 2 +- src/services/nodejs/.dockerignore | 4 + src/services/nodejs/.gitignore | 4 + src/services/nodejs/Dockerfile | 13 + src/services/nodejs/entrypoint.sh | 4 + src/services/nodejs/index.js | 327 ++++++++++++++++++ src/services/nodejs/package.json | 21 ++ src/services/nodejs/run.sh | 2 + src/services/nodejs/scripts/.gitkeep | 0 12 files changed, 380 insertions(+), 8 deletions(-) create mode 100644 src/services/nodejs/.dockerignore create mode 100644 src/services/nodejs/.gitignore create mode 100644 src/services/nodejs/Dockerfile create mode 100644 src/services/nodejs/entrypoint.sh create mode 100644 src/services/nodejs/index.js create mode 100644 src/services/nodejs/package.json create mode 100755 src/services/nodejs/run.sh create mode 100644 src/services/nodejs/scripts/.gitkeep diff --git a/.github/workflows/reusable-build-container-images.yml b/.github/workflows/reusable-build-container-images.yml index 0e1858c..8462d5d 100644 --- a/.github/workflows/reusable-build-container-images.yml +++ b/.github/workflows/reusable-build-container-images.yml @@ -22,6 +22,8 @@ jobs: name: loaders-curl - context: ./src/services/java name: services-java + - context: ./src/services/nodejs + name: services-nodejs - context: ./src/databases/mysql name: databases-mysql steps: diff --git a/.gitignore b/.gitignore index 110f54d..3ab9b5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,4 @@ -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -!.vscode/*.code-snippets +.vscode/ # Local History for Visual Studio Code .history/ diff --git a/src/loaders/curl/Dockerfile b/src/loaders/curl/Dockerfile index d249c05..fe02ae1 100644 --- a/src/loaders/curl/Dockerfile +++ b/src/loaders/curl/Dockerfile @@ -1,6 +1,6 @@ FROM alpine:3.20.3 -LABEL org.opencontainers.image.source https://github.com/cisco-open/app-simulator +LABEL org.opencontainers.image.source=https://github.com/cisco-open/app-simulator LABEL org.opencontainers.image.description="curl loader for app-simulator" LABEL org.opencontainers.image.licenses=BSD-3-Clause diff --git a/src/services/java/Dockerfile b/src/services/java/Dockerfile index 9716c7e..b2abcf2 100644 --- a/src/services/java/Dockerfile +++ b/src/services/java/Dockerfile @@ -6,7 +6,7 @@ RUN mvn -f /home/app/pom.xml clean package FROM openjdk:11-jre -LABEL org.opencontainers.image.source https://github.com/cisco-open/app-simulator +LABEL org.opencontainers.image.source=https://github.com/cisco-open/app-simulator LABEL org.opencontainers.image.description="java service for app-simulator" LABEL org.opencontainers.image.licenses=BSD-3-Clause diff --git a/src/services/nodejs/.dockerignore b/src/services/nodejs/.dockerignore new file mode 100644 index 0000000..11afbc7 --- /dev/null +++ b/src/services/nodejs/.dockerignore @@ -0,0 +1,4 @@ +node_modules +npm-debug.log +package-lock.json +run.sh diff --git a/src/services/nodejs/.gitignore b/src/services/nodejs/.gitignore new file mode 100644 index 0000000..cf9dc1e --- /dev/null +++ b/src/services/nodejs/.gitignore @@ -0,0 +1,4 @@ +node_modules +npm-debug.log +package-lock.json +node.log \ No newline at end of file diff --git a/src/services/nodejs/Dockerfile b/src/services/nodejs/Dockerfile new file mode 100644 index 0000000..4ac565f --- /dev/null +++ b/src/services/nodejs/Dockerfile @@ -0,0 +1,13 @@ +FROM node:18 + +LABEL org.opencontainers.image.source=https://github.com/cisco-open/app-simulator +LABEL org.opencontainers.image.description="nodejs service for app-simulator" +LABEL org.opencontainers.image.licenses=BSD-3-Clause + +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . +RUN chmod +x /app/entrypoint.sh +EXPOSE 80 +CMD ["/app/entrypoint.sh"] diff --git a/src/services/nodejs/entrypoint.sh b/src/services/nodejs/entrypoint.sh new file mode 100644 index 0000000..1343653 --- /dev/null +++ b/src/services/nodejs/entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/bash +echo "Running server on :8080" +APP_CONFIG="$( { var [k, v] = a.split(':'); c[k] = isNaN(parseInt(v)) ? v : parseInt(v); return c }, {}) + data.value = chance[fn](attributes) + } + + if (!data.value) { + reject('Data not processed: No value provided') + } + + var value = data.value + var id = data.id + + if (Array.isArray(value)) { + value = value[Math.floor(Math.random() * value.length)] + } + reject('No data added: Transaction not found.') +} + +function logMessage(level, message) { + if (['trace', 'debug', 'info', 'warn', 'error', 'fatal'].includes(level)) { + logger[level](message) + } else { + logger.info(message) + } + return 'Logged (' + level + '): ' + message +} + +function executeCustomScript(script, req, resolve, reject) { + var r = require(path.join(customCodeDir, script))({ + logger: logger, + req: req, + cronmatch: cronmatch, + sleep: sleep.msleep, + chance: chance + }) + if (r === false) { + reject(`Script ${script} was not executed successfully`) + } else if (typeof r === "object" && r.hasOwnProperty('code') && r.hasOwnProperty('code')) { + reject({ code: r.code, message: r.message }) + } else if (typeof r === 'string') { + resolve(r) + } else { + resolve(`Script ${script} was executed successfully`) + } +} + +function callRemoteService(call, useRp, catchExceptions, remoteTimeout, req, resolve, reject) { + if (useRp) { + rp.get({ + uri: url.parse(call), + json: true, + timeout: remoteTimeout + }).then(function (body) { + resolve(body) + }).catch(function (err) { + if (catchExceptions) { + resolve(err) + } else { + reject(err) + } + }) + } else { + var headers = { + 'Content-Type': 'application/json' + } + // removed logic to decide what happens w/ w/o agent + headers = req.headers + var opts = Object.assign(url.parse(call), { + headers: headers + }) + const r = http.get(opts, function (res, req) { + const body = [] + res.on('data', (chunk) => body.push(chunk)) + res.on('end', () => resolve(body.join(''))) + }).on('error', function (err) { + if (catchExceptions) { + resolve(err) + } else { + reject(err) + } + }) + r.setTimeout(remoteTimeout, function () { + reject({ code: 500, message: 'Read timed out' }) + }) + } +} + +function processCall(call, req) { + return new Promise(function (resolve, reject) { + console.log(call) + var remoteTimeout = 1073741824 + + var catchExceptions = true + + // If call is an array, select one element as call + if (Array.isArray(call)) { + call = call[Math.floor(Math.random() * call.length)] + } + // If call is an object, check for probability + if (typeof call === 'object') { + if (call.hasOwnProperty('probability') && call.probability <= Math.random()) { + resolve(`${call.call} was not probable`) + return + } + if (call.hasOwnProperty('schedule') && !cronmatch.match(call.schedule, new Date())) { + resolve(`${call.call} was not scheduled`) + return + } + if (call.hasOwnProperty('remoteTimeout')) { + remoteTimeout = call.remoteTimeout + } + if (call.hasOwnProperty('catchExceptions')) { + catchExceptions = call.catchExceptions + } + if (call.hasOwnProperty('call') && call.call === 'data') { + return processData(resolve, reject, req, call) + } + call = call.call + } + if (call.startsWith('error')) { + const [_, code, message] = call.split(',') + reject({ code, message }) + } else if (call.startsWith('sleep')) { + const [_, timeout] = call.split(',') + setTimeout(function () { + resolve(`Slept for ${timeout}`) + }, timeout) + } else if (call.startsWith('slow')) { + const [_, timeout] = call.split(',') + resolve(buildResponse(timeout)) + } else if (call.startsWith('http://')) { + callRemoteService(call, useRp, catchExceptions, remoteTimeout, req, resolve, reject) + } else if (call.startsWith('image')) { + const [_, src] = call.split(',') + resolve(``) + } else if (call.startsWith('script')) { + const [_, src] = call.split(',') + resolve(``) + } else if (call.startsWith('ajax')) { + const [_, src] = call.split(',') + resolve(``) + } else if (call.startsWith('cache')) { + const [_, timeout] = call.split(',') + resolve(loadFromCache(timeout, txn)) + } else if (call.startsWith('log')) { + const logging = call.split(',') + if (logging.length > 2) { + resolve(logMessage(logging[1], logging[2])) + } else { + resolve(logMessage('info', logging[1])) + } + } else if (call.startsWith('code')) { + const [_, script] = call.split(',') + executeCustomScript(script, req, resolve, reject) + } else { + // No other methods are currently implemented + resolve(`${call} is not supported`) + } + }) +} + +async function processRequest(req, res, params) { + const path = url.parse(req.url).pathname + logger.info("Request Headers:", req.headers) + if (endpoints.hasOwnProperty(path)) { + try { + const results = [] + for (let i = 0; i < endpoints[path].length; i++) { + const call = endpoints[path][i] + results.push(await processCall(call, req)) + } + var contype = req.headers['content-type'] + + if (req.query.output && req.query.output === 'javascript') { + res.send(results) + } else { + res.send(results) + } + } catch (reason) { + logger.error(reason.message) + res.status(typeof reason.code === 'number' ? reason.code : 500).send(reason.message) + } + } else { + res.status(404).send('404') + } +} + +app.get('/**', function (req, res) { + processRequest(req, res, req.query) +}) + +app.post('/**', function (req, res) { + processRequest(req, res, req.body) +}) + +var server = app.listen(port, () => console.log( + `Running ${config.name} (type: ${config.type}) on port ${port}`)) +console.log(`Configuration:`) +console.log(JSON.stringify(config)) +console.log(`Endpoints:`) +console.log(JSON.stringify(endpoints)) + +if (config.hasOwnProperty('options')) { + server.on('connection', (socket) => { + if (config.options.hasOwnProperty('connectionDelay')) { + sleep.msleep(config.options.connectionDelay) + } + if (config.options.hasOwnProperty('lossRate') && parseFloat(config.options.lossRate) >= Math.random()) { + socket.end() + throw new Error('An error occurred') + } + }) +} \ No newline at end of file diff --git a/src/services/nodejs/package.json b/src/services/nodejs/package.json new file mode 100644 index 0000000..036bb1d --- /dev/null +++ b/src/services/nodejs/package.json @@ -0,0 +1,21 @@ +{ + "dependencies": { + "chance": "^1.1.3", + "cronmatch": "^0.1.1", + "express": "^4.17.1", + "log4js": "^3.0.6", + "morgan": "^1.9.1", + "request": "^2.88.2", + "request-promise": "^4.2.4", + "sleep": "^6.3.0" + }, + "devDependencies": { + "eslint": "^6.2.1", + "eslint-config-standard": "^14.0.0", + "eslint-plugin-import": "^2.18.2", + "eslint-plugin-json": "^1.4.0", + "eslint-plugin-node": "^9.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1" + } +} diff --git a/src/services/nodejs/run.sh b/src/services/nodejs/run.sh new file mode 100755 index 0000000..f87865e --- /dev/null +++ b/src/services/nodejs/run.sh @@ -0,0 +1,2 @@ +#!/bin/bash +env CUSTOM_CODE_DIR="./scripts" APP_CONFIG="$(<../examples/frontend.json)" nodemon index.js 8080 diff --git a/src/services/nodejs/scripts/.gitkeep b/src/services/nodejs/scripts/.gitkeep new file mode 100644 index 0000000..e69de29