diff --git a/nodejs-helloworld/package.json b/nodejs-helloworld/package.json index c9768b5e49..9e864dfbd0 100644 --- a/nodejs-helloworld/package.json +++ b/nodejs-helloworld/package.json @@ -3,9 +3,12 @@ "version": "1.0.0", "description": "Hello World!", "main": "app.js", + "scripts": { + "start": "node app.js" + }, "author": "Red Hat Training", "license": "ASL", "dependencies": { - "express": "~4.14.2" + "express": "^4.18.2" } } diff --git a/todoapp/nodejs_api/README.md b/todoapp/nodejs_api/README.md index f7f0fd4e3d..cdbba7c02d 100644 --- a/todoapp/nodejs_api/README.md +++ b/todoapp/nodejs_api/README.md @@ -1,18 +1,2 @@ -# DO276 JavaScript/Node.js To Do List App - -Based on Restify 4.0 and Sequelize 3.14. Tested on Node.js 0.10 from SCL with Mariadb 5.5. - -Do `npm install` do download dependencies. - -Run as `node app.js` - -* Don't do pagination yet. - -* Database connection parameters hardcoded (as a novice developer would usually do). - -* There is a lot of boiler plate code in the controller and the model. There should be a way to have more centralized error handling. - -* Have mysql database initialized and running, and front end deployed to apache and running - -* Access as http://localhost:30000/todo - +# TodoApp OpenShift +Aplicación TodoApp con Node.js y MySQL lista para desplegar en OpenShift. diff --git a/todoapp/nodejs_api/app.js b/todoapp/nodejs_api/app.js index 11ce178e09..e630001f34 100644 --- a/todoapp/nodejs_api/app.js +++ b/todoapp/nodejs_api/app.js @@ -1,35 +1,21 @@ -var restify = require('restify'); +const express = require('express'); +const bodyParser = require('body-parser'); +const app = express(); +const db = require('./models/db'); +const itemsController = require('./controllers/items'); +const serverInfoController = require('./controllers/serverinfo'); -var controller = require('./controllers/items'); -var serverinfo = require('./controllers/serverinfo'); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); -var db = require('./models/db'); -var model = require('./models/items'); +itemsController(app); +serverInfoController(app); -model.connect(db.params, function(err) { - if (err) throw err; +const port = process.env.PORT || 8080; +db.sequelize.sync().then(() => { + app.listen(port, () => { + console.log(`TodoApp listening on port ${port}`); + }); +}).catch(err => { + console.error('Database sync failed:', err); }); - -var server = restify.createServer() - .use(restify.fullResponse()) - .use(restify.queryParser()) - .use(restify.bodyParser()) - .use(restify.CORS()); - -controller.context(server, '/todo/api', model); -serverinfo.context(server, '/todo/api'); - -var port = process.env.PORT || 30080; -server.listen(port, function (err) { - if (err) - console.error(err); - else - console.log('App is ready at : ' + port); -}); - -if (process.env.environment == 'production') - process.on('uncaughtException', function (err) { - console.error(JSON.parse(JSON.stringify(err, ['stack', 'message', 'inner'], 2))) - }); - - diff --git a/todoapp/nodejs_api/compile.sh b/todoapp/nodejs_api/compile.sh index 1544bb24d7..3add1127d4 100644 --- a/todoapp/nodejs_api/compile.sh +++ b/todoapp/nodejs_api/compile.sh @@ -1,6 +1,2 @@ #!/bin/bash - -source /opt/rh/nodejs010/enable - npm install - diff --git a/todoapp/nodejs_api/controllers/items.js b/todoapp/nodejs_api/controllers/items.js index fc6993404a..a5aa6bb07d 100644 --- a/todoapp/nodejs_api/controllers/items.js +++ b/todoapp/nodejs_api/controllers/items.js @@ -1,118 +1,19 @@ - -var model = undefined; - -exports.context = function(server, path, itemsModel) { - if (!server) - done('has to provide a restify server object'); - - var context = "/items"; - if (path) - context = path + context; - - server.get(context + '/', this.list); - server.get(context + '/:id', this.read); - server.post(context + '/', this.save); - server.del(context + '/:id', this.destroy); - - model = itemsModel; -}; - -exports.list = function(req, res, next) { - var page_no = req.query.page || 1; - var sortField = req.query.sortFields || "id"; - var sortDirection = req.query.sortDirections || "asc"; - - model.listAll(page_no, sortField, sortDirection, function(err, items) { - if (err) { - next(err); - } - else { - if (items) { - model.countAll(function(err, n) { - if (err) { - next(err); - } - else { - if (n) { - var page = { - "currentPage" : page_no, - "list" : items, - "pageSize" : 10, - "sortDirections" : sortDirection, - "sortFields" : sortField, - "totalResults" : n - }; - res.json(page); - next(); - } - else { - next(new Error("Can't count items")); - } - } - }); - } - else { - next(new Error("Can't retrieve items")); - } - } - }) -}; - -exports.read = function(req, res, next) { - var key = req.params.id; - model.read(key, function(err, item) { - if (err) { - next(err); - } - else { - if (item) { - res.json(item); - next(); - } - else { - next(new Error("Can't retrieve items")); - } - } - }) -}; - - -exports.save = function(req, res, next) { - if (req.params.id) { - model.update(req.params.id, req.params.description, req.params.done, function(err, item) { - if (err) { - next(err); - } - else { - res.json(item); - next(); - } - }); - } - else { - model.create(req.params.description, req.params.done, function(err, item) { - if (err) { - next(err); - } - else { - res.json(item); - next(); - } - }); - } +module.exports = function(app) { + const db = require('../models/db'); + const Item = db.Item; + + app.get('/items', async (req, res) => { + const items = await Item.findAll(); + res.json(items); + }); + + app.post('/items', async (req, res) => { + const newItem = await Item.create(req.body); + res.json(newItem); + }); + + app.delete('/items/:id', async (req, res) => { + await Item.destroy({ where: { id: req.params.id }}); + res.json({ message: 'Item deleted' }); + }); }; - - -exports.destroy = function(req, res, next) { - if (req.params.id) { - model.destroy(req.params.id, function(err, item) { - if (err) { - next(err); - } - else { - //XXX jee_api does NOT return item on delete - res.json(item); - } - }); - } -} diff --git a/todoapp/nodejs_api/controllers/serverinfo.js b/todoapp/nodejs_api/controllers/serverinfo.js index 00f4b58d71..cca4c078ec 100644 --- a/todoapp/nodejs_api/controllers/serverinfo.js +++ b/todoapp/nodejs_api/controllers/serverinfo.js @@ -1,29 +1,9 @@ -var os = require('os'); - -exports.context = function(server, path) { - if (!server) - done('has to provide a restify server object'); - - server.get(path + '/host', this.serverInfo); +module.exports = function(app) { + app.get('/info', (req, res) => { + res.json({ + uptime: process.uptime(), + message: 'OK', + timestamp: Date.now() + }); + }); }; - -exports.serverInfo = function(req, res, next) { - var address; - var ifaces = os.networkInterfaces(); - - for (var dev in ifaces) { - var iface = ifaces[dev].filter(function(details) { - return details.family === 'IPv4' && details.internal === false; - }); - if (iface.length > 0) - address = iface[0].address; - } - - var reply = { - ip: address, - hostname: os.hostname() - }; - res.json(reply); - next(); -}; - diff --git a/todoapp/nodejs_api/models/db.js b/todoapp/nodejs_api/models/db.js index 4e9b393a88..16d90d9dfb 100644 --- a/todoapp/nodejs_api/models/db.js +++ b/todoapp/nodejs_api/models/db.js @@ -1,12 +1,25 @@ +const { Sequelize, DataTypes } = require('sequelize'); -module.exports.params = { - dbname: process.env.MYSQL_ENV_MYSQL_DATABASE, - username: process.env.MYSQL_ENV_MYSQL_USER, - password: process.env.MYSQL_ENV_MYSQL_PASSWORD, - params: { - host: "mysql", - port: "3306", - dialect: 'mysql' - } -}; +const sequelize = new Sequelize( + process.env.DB_NAME || 'todoapp', + process.env.DB_USER || 'root', + process.env.DB_PASSWORD || 'password', + { + host: process.env.DB_HOST || 'localhost', + port: process.env.DB_PORT || 3306, + dialect: 'mysql' + } +); +const Item = sequelize.define('Item', { + description: { + type: DataTypes.STRING, + allowNull: false + }, + done: { + type: DataTypes.BOOLEAN, + defaultValue: false + } +}); + +module.exports = { sequelize, Item }; diff --git a/todoapp/nodejs_api/models/items.js b/todoapp/nodejs_api/models/items.js index 5301bbb379..bef9e36704 100644 --- a/todoapp/nodejs_api/models/items.js +++ b/todoapp/nodejs_api/models/items.js @@ -1,126 +1,22 @@ -var Sequelize = require("sequelize"); - -var Item = undefined; - -module.exports.connect = function(params, callback) { - var sequlz = new Sequelize( - params.dbname, params.username, params.password, - params.params); - Item = sequlz.define('Item', { - id: { type: Sequelize.BIGINT, - primaryKey: true, unique: true, allowNull: false, - autoIncrement: true }, - description: { type: Sequelize.STRING, - allowNull: true }, - done: { type: Sequelize.BOOLEAN, - allowNull: true } - }, { - timestamps: false, - freezeTableName: true - }); - // drop and create tables, better done globally - /* - Item.sync({ force: true }).then(function() { - callback(); - }).error(function(err) { - callback(err); - }); - */ -} - -exports.disconnect = function(callback) { - //XXX shouln'd to something to close or release the db connection? - callback(); -} - -exports.create = function(description, done, callback) { - Item.create({ - //id: id, - description: description, - done: (done) ? true : false - }).then(function(item) { - callback(null, item); - }).error(function(err) { - callback(err); - }); -} - -exports.update = function(key, description, done, callback) { - Item.find({ where:{ id: key } }).then(function(item) { - if (!item) { - callback(new Error("Nothing found for key " + key)); - } - else { - item.updateAttributes({ - description: description, - done: (done) ? true : false - }).then(function() { - callback(null, item); - }).error(function(err) { - callback(err); - }); - } - }).error(function(err) { - callback(err); - }); -} - - -exports.read = function(key, callback) { - Item.find({ where:{ id: key } }).then(function(item) { - if (!item) { - callback(new Error("Nothing found for key " + key)); - } - else { - //XXX why recreating the item object? - callback(null, { - id: item.id, - description: item.description, - done: item.done - }); - } - }).error(function(err) { - callback(err); - }); -} - -exports.destroy = function(key, callback) { - Item.find({ where:{ id: key } }).then(function(item) { - if (!item) { - callback(new Error("Nothing found for " + key)); - } - else { - item.destroy().then(function() { - callback(null, item); - }).error(function(err) { - callback(err); - }); - } - }).error(function(err) { - callback(err); - }); -} - -exports.countAll = function(callback) { - Item.findAll({ attributes: [[Sequelize.fn('COUNT', Sequelize.col('id')), 'no_items']] } ).then(function(n) { - callback(null, n[0].get('no_items')); - }).error(function(err) { - callback(err); - }); - //callback(null, 100); -} - -exports.listAll = function(page, sortField, sortDirection, callback) { - Item.findAll({ offset: 10 * (page - 1), limit: 10, order: [[sortField, sortDirection]] }).then(function(items) { - var theitems = []; - items.forEach(function(item) { - //XXX why recreating the item objects for theitems? - theitems.push({ - id: item.id, description: item.description, done: item.done }); - }); - callback(null, theitems); - }).error(function(err) { - callback(err); - }); -} - +const { DataTypes } = require('sequelize'); +const sequelize = require('./db'); + +const Item = sequelize.define('Item', { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true + }, + description: { + type: DataTypes.STRING, + allowNull: false + }, + done: { + type: DataTypes.BOOLEAN, + defaultValue: false + } +}, { + timestamps: false +}); + +module.exports = Item; \ No newline at end of file diff --git a/todoapp/nodejs_api/openshift/deployment.yaml b/todoapp/nodejs_api/openshift/deployment.yaml new file mode 100644 index 0000000000..d0f270804e --- /dev/null +++ b/todoapp/nodejs_api/openshift/deployment.yaml @@ -0,0 +1,120 @@ +apiVersion: v1 +kind: Secret +metadata: + name: mysql-secret +type: Opaque +data: + MYSQL_ROOT_PASSWORD: cGFzc3dvcmQ= # "password" base64 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql +spec: + replicas: 1 + selector: + matchLabels: + app: mysql + template: + metadata: + labels: + app: mysql + spec: + containers: + - name: mysql + image: mysql:5.7 + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-secret + key: MYSQL_ROOT_PASSWORD + - name: MYSQL_DATABASE + value: todoapp + ports: + - containerPort: 3306 + volumeMounts: + - name: mysql-data + mountPath: /var/lib/mysql + volumes: + - name: mysql-data + emptyDir: {} + +--- +apiVersion: v1 +kind: Service +metadata: + name: mysql +spec: + ports: + - port: 3306 + targetPort: 3306 + selector: + app: mysql + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: todoapp +spec: + replicas: 1 + selector: + matchLabels: + app: todoapp + template: + metadata: + labels: + app: todoapp + spec: + containers: + - name: todoapp + image: /todoapp:latest + ports: + - containerPort: 8080 + env: + - name: DB_HOST + value: mysql + - name: DB_PORT + value: "3306" + - name: DB_USER + value: root + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-secret + key: MYSQL_ROOT_PASSWORD + - name: DB_NAME + value: todoapp + resources: + limits: + memory: "512Mi" + requests: + memory: "256Mi" + +--- +apiVersion: v1 +kind: Service +metadata: + name: todoapp +spec: + selector: + app: todoapp + ports: + - port: 80 + targetPort: 8080 + +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: todoapp +spec: + to: + kind: Service + name: todoapp + port: + targetPort: 8080 + tls: + termination: edge diff --git a/todoapp/nodejs_api/package.json b/todoapp/nodejs_api/package.json index 4b898030a1..6efad75e58 100644 --- a/todoapp/nodejs_api/package.json +++ b/todoapp/nodejs_api/package.json @@ -1,10 +1,15 @@ { - "name": "todo", - "version": "0.0.1", - "private": true, + "name": "todoapp", + "version": "1.0.0", + "description": "Todo application with Node.js and MySQL for OpenShift", + "main": "app.js", + "scripts": { + "start": "node app.js" + }, "dependencies": { - "restify": "4.0.3", - "sequelize": "3.14.2", - "mysql": "2.9.0" + "express": "^4.18.2", + "mysql2": "^3.9.4", + "sequelize": "^6.35.1", + "body-parser": "^1.20.2" } } diff --git a/todoapp/nodejs_api/run.sh b/todoapp/nodejs_api/run.sh index 34949eb0c7..9b12715ba0 100644 --- a/todoapp/nodejs_api/run.sh +++ b/todoapp/nodejs_api/run.sh @@ -1,6 +1,2 @@ #!/bin/bash - -source /opt/rh/nodejs010/enable - -node app.js - +npm start diff --git a/todoapp/todoapp-openshift.zip b/todoapp/todoapp-openshift.zip new file mode 100644 index 0000000000..4be1be1187 Binary files /dev/null and b/todoapp/todoapp-openshift.zip differ diff --git a/todoapp/todoapp_openshift/Dockerfile b/todoapp/todoapp_openshift/Dockerfile new file mode 100644 index 0000000000..72a49b44d7 --- /dev/null +++ b/todoapp/todoapp_openshift/Dockerfile @@ -0,0 +1,20 @@ +# Imagen base oficial de Node.js +FROM node:20-alpine + +# Crear directorio de la app +WORKDIR /usr/src/app + +# Copiar archivos de dependencias +COPY package*.json ./ + +# Instalar dependencias de producción +RUN npm install --production + +# Copiar el resto del código fuente +COPY . . + +# Exponer el puerto de la aplicación +EXPOSE 8080 + +# Comando para arrancar la aplicación +CMD ["node", "app.js"] diff --git a/todoapp/todoapp_openshift/README.md b/todoapp/todoapp_openshift/README.md new file mode 100644 index 0000000000..20fc883753 --- /dev/null +++ b/todoapp/todoapp_openshift/README.md @@ -0,0 +1,115 @@ +# TodoApp (OpenShift + Node.js + MySQL) + +Aplicación simple para gestionar tareas (To-Do) desarrollada con **Node.js**, **Express** y **MySQL**, desplegada en **OpenShift**. + +--- + +## 📅 Características +- Rutas RESTful para CRUD de tareas +- Persistencia con Sequelize ORM y MySQL +- Despliegue automatizado con OpenShift + +--- + +## 🚀 Despliegue en OpenShift + +### 1. Clonar el repositorio +```bash +git clone https://github.com/superlinuxex/DO180-apps.git +cd DO180-apps/todoapp/todoapp_openshift +``` + +### 2. Aplicar los recursos YAML +```bash +oc apply -f openshift-deploy.yaml -n TU_PROYECTO +``` + +### 3. Lanzar el build de la app +```bash +oc start-build todoapp -n TU_PROYECTO --wait --follow +``` + +### 4. Verificar despliegue +```bash +oc get pods -n TU_PROYECTO +oc get route todoapp -n TU_PROYECTO +``` +Accede vía navegador a la URL de la **route**. + +--- + +## 🔄 API Endpoints + +| Método | Ruta | Descripción | +|---------|-------------------|---------------------------------| +| GET | `/api/items` | Listar todas las tareas | +| POST | `/api/items` | Crear nueva tarea | +| PUT | `/api/items/:id` | Actualizar tarea por ID | +| DELETE | `/api/items/:id` | Eliminar tarea por ID | +| GET | `/info` | Info del servidor (uptime etc.) | + +--- + +## 📦 Ejemplos de uso con `curl` + +### Crear una nueva tarea +```bash +curl -X POST http://URL_ROUTE/api/items \ + -H "Content-Type: application/json" \ + -d '{"description": "Aprender OpenShift"}' +``` + +### Listar tareas +```bash +curl http://URL_ROUTE/api/items +``` + +### Marcar tarea como realizada +```bash +curl -X PUT http://URL_ROUTE/api/items/1 \ + -H "Content-Type: application/json" \ + -d '{"done": true}' +``` + +### Eliminar tarea +```bash +curl -X DELETE http://URL_ROUTE/api/items/1 +``` + +### Ver info del servidor +```bash +curl http://URL_ROUTE/info +``` + +> 🔄 Reemplaza `URL_ROUTE` por la URL obtenida con `oc get route`. + +--- + +## 💪 Requisitos +- OpenShift 4+ +- Node.js 20 (ya incluido en la imagen base `node:20-alpine`) +- MySQL 5.7 (provisionado por el despliegue YAML) + +--- + +## 📒 Estructura del Proyecto +``` +todoapp_openshift/ +├── controladores/ +│ ├── items.js +│ └── serverinfo.js +├── modelos/ +│ └── db.js +├── Dockerfile +├── openshift-deploy.yaml +├── aplicación.js +├── package.json +``` + +--- + +## 🚜 Contacto +Superlinuxec ✨ +Email: superlinuxec@gmail.com +GitHub: [superlinuxex](https://github.com/superlinuxex) + diff --git a/todoapp/todoapp_openshift/app.js b/todoapp/todoapp_openshift/app.js new file mode 100644 index 0000000000..5c239d1166 --- /dev/null +++ b/todoapp/todoapp_openshift/app.js @@ -0,0 +1,31 @@ +const express = require('express'); +const bodyParser = require('body-parser'); +const app = express(); +const db = require('./models/db'); +const itemsController = require('./controllers/items'); +const serverInfoController = require('./controllers/serverinfo'); + +// Middleware para parsear JSON y datos de formularios +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +// Controladores +itemsController(app); +serverInfoController(app); + +// Ruta principal para verificar que el servidor responde +app.get('/', (req, res) => { + res.send('✅ TodoApp está corriendo correctamente.'); +}); + +// Puerto de escucha +const port = process.env.PORT || 8080; + +// Sincronización con la base de datos y arranque del servidor +db.sequelize.sync().then(() => { + app.listen(port, () => { + console.log(`✅ TodoApp escuchando en el puerto ${port}`); + }); +}).catch(err => { + console.error('❌ Fallo al sincronizar con la base de datos:', err); +}); diff --git a/todoapp/todoapp_openshift/compile.sh b/todoapp/todoapp_openshift/compile.sh new file mode 100644 index 0000000000..3add1127d4 --- /dev/null +++ b/todoapp/todoapp_openshift/compile.sh @@ -0,0 +1,2 @@ +#!/bin/bash +npm install diff --git a/todoapp/todoapp_openshift/controllers/items.js b/todoapp/todoapp_openshift/controllers/items.js new file mode 100644 index 0000000000..a744acf36b --- /dev/null +++ b/todoapp/todoapp_openshift/controllers/items.js @@ -0,0 +1,52 @@ +const { Item } = require('../models/db'); + +module.exports = function(app) { + app.get('/api/items', async (req, res) => { + try { + const items = await Item.findAll(); + res.json(items); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + app.post('/api/items', async (req, res) => { + try { + const newItem = await Item.create({ + description: req.body.description, + done: req.body.done || false + }); + res.status(201).json(newItem); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + app.put('/api/items/:id', async (req, res) => { + try { + const item = await Item.findByPk(req.params.id); + if (!item) return res.status(404).json({ error: 'Item not found' }); + + item.description = req.body.description ?? item.description; + item.done = req.body.done ?? item.done; + await item.save(); + + res.json(item); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + app.delete('/api/items/:id', async (req, res) => { + try { + const deleted = await Item.destroy({ where: { id: req.params.id } }); + if (deleted) { + res.json({ message: 'Item deleted' }); + } else { + res.status(404).json({ error: 'Item not found' }); + } + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); +}; diff --git a/todoapp/todoapp_openshift/controllers/serverinfo.js b/todoapp/todoapp_openshift/controllers/serverinfo.js new file mode 100644 index 0000000000..4d5a50c926 --- /dev/null +++ b/todoapp/todoapp_openshift/controllers/serverinfo.js @@ -0,0 +1,9 @@ +module.exports = function(app) { + app.get('/api/serverinfo', (req, res) => { + res.json({ + uptime: process.uptime(), + message: 'OK', + timestamp: Date.now() + }); + }); +}; diff --git a/todoapp/todoapp_openshift/models/db.js b/todoapp/todoapp_openshift/models/db.js new file mode 100644 index 0000000000..cbb1143980 --- /dev/null +++ b/todoapp/todoapp_openshift/models/db.js @@ -0,0 +1,26 @@ +const { Sequelize, DataTypes } = require('sequelize'); + +const sequelize = new Sequelize( + process.env.DB_NAME, + process.env.DB_USER, + process.env.DB_PASSWORD, + { + host: process.env.DB_HOST, + port: process.env.DB_PORT, + dialect: 'mysql', + logging: false + } +); + +const Item = sequelize.define('Item', { + description: { + type: DataTypes.STRING, + allowNull: false + }, + done: { + type: DataTypes.BOOLEAN, + defaultValue: false + } +}); + +module.exports = { sequelize, Item }; diff --git a/todoapp/todoapp_openshift/openshift-deploy.yaml b/todoapp/todoapp_openshift/openshift-deploy.yaml new file mode 100644 index 0000000000..2035badf04 --- /dev/null +++ b/todoapp/todoapp_openshift/openshift-deploy.yaml @@ -0,0 +1,160 @@ +apiVersion: v1 +kind: Secret +metadata: + name: todoapp-db-secret + namespace: leonardokrk-dev +stringData: + DB_PASSWORD: password123 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql + namespace: leonardokrk-dev + labels: + app: mysql +spec: + replicas: 1 + selector: + matchLabels: + app: mysql + template: + metadata: + labels: + app: mysql + spec: + containers: + - name: mysql + image: mysql:5.7 + ports: + - containerPort: 3306 + env: + - name: MYSQL_DATABASE + value: todoapp + - name: MYSQL_USER + value: todo + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: todoapp-db-secret + key: DB_PASSWORD + - name: MYSQL_ROOT_PASSWORD + value: rootpassword + volumeMounts: + - name: mysql-persistent-storage + mountPath: /var/lib/mysql + volumes: + - name: mysql-persistent-storage + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: mysql + namespace: leonardokrk-dev +spec: + ports: + - port: 3306 + targetPort: 3306 + selector: + app: mysql +--- +apiVersion: build.openshift.io/v1 +kind: BuildConfig +metadata: + name: todoapp + namespace: leonardokrk-dev +spec: + source: + git: + uri: https://github.com/superlinuxex/DO180-apps.git + contextDir: todoapp/todoapp_openshift + strategy: + dockerStrategy: {} + output: + to: + kind: ImageStreamTag + name: todoapp:latest +--- +apiVersion: image.openshift.io/v1 +kind: ImageStream +metadata: + name: todoapp + namespace: leonardokrk-dev +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: todoapp + namespace: leonardokrk-dev + labels: + app: todoapp +spec: + replicas: 1 + selector: + matchLabels: + app: todoapp + template: + metadata: + labels: + app: todoapp + spec: + containers: + - name: todoapp + image: image-registry.openshift-image-registry.svc:5000/leonardokrk-dev/todoapp:latest + ports: + - containerPort: 8080 + env: + - name: NODE_ENV + value: production + - name: DB_NAME + value: todoapp + - name: DB_USER + value: todo + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: todoapp-db-secret + key: DB_PASSWORD + - name: DB_HOST + value: mysql + - name: DB_PORT + value: '3306' + readinessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 30 +--- +apiVersion: v1 +kind: Service +metadata: + name: todoapp + namespace: leonardokrk-dev +spec: + ports: + - port: 80 + targetPort: 8080 + selector: + app: todoapp +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: todoapp + namespace: leonardokrk-dev +spec: + to: + kind: Service + name: todoapp + port: + targetPort: 8080 + tls: + termination: edge diff --git a/todoapp/todoapp_openshift/openshift/deployment.yaml b/todoapp/todoapp_openshift/openshift/deployment.yaml new file mode 100644 index 0000000000..d0f270804e --- /dev/null +++ b/todoapp/todoapp_openshift/openshift/deployment.yaml @@ -0,0 +1,120 @@ +apiVersion: v1 +kind: Secret +metadata: + name: mysql-secret +type: Opaque +data: + MYSQL_ROOT_PASSWORD: cGFzc3dvcmQ= # "password" base64 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql +spec: + replicas: 1 + selector: + matchLabels: + app: mysql + template: + metadata: + labels: + app: mysql + spec: + containers: + - name: mysql + image: mysql:5.7 + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-secret + key: MYSQL_ROOT_PASSWORD + - name: MYSQL_DATABASE + value: todoapp + ports: + - containerPort: 3306 + volumeMounts: + - name: mysql-data + mountPath: /var/lib/mysql + volumes: + - name: mysql-data + emptyDir: {} + +--- +apiVersion: v1 +kind: Service +metadata: + name: mysql +spec: + ports: + - port: 3306 + targetPort: 3306 + selector: + app: mysql + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: todoapp +spec: + replicas: 1 + selector: + matchLabels: + app: todoapp + template: + metadata: + labels: + app: todoapp + spec: + containers: + - name: todoapp + image: /todoapp:latest + ports: + - containerPort: 8080 + env: + - name: DB_HOST + value: mysql + - name: DB_PORT + value: "3306" + - name: DB_USER + value: root + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-secret + key: MYSQL_ROOT_PASSWORD + - name: DB_NAME + value: todoapp + resources: + limits: + memory: "512Mi" + requests: + memory: "256Mi" + +--- +apiVersion: v1 +kind: Service +metadata: + name: todoapp +spec: + selector: + app: todoapp + ports: + - port: 80 + targetPort: 8080 + +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: todoapp +spec: + to: + kind: Service + name: todoapp + port: + targetPort: 8080 + tls: + termination: edge diff --git a/todoapp/todoapp_openshift/package.json b/todoapp/todoapp_openshift/package.json new file mode 100644 index 0000000000..6efad75e58 --- /dev/null +++ b/todoapp/todoapp_openshift/package.json @@ -0,0 +1,15 @@ +{ + "name": "todoapp", + "version": "1.0.0", + "description": "Todo application with Node.js and MySQL for OpenShift", + "main": "app.js", + "scripts": { + "start": "node app.js" + }, + "dependencies": { + "express": "^4.18.2", + "mysql2": "^3.9.4", + "sequelize": "^6.35.1", + "body-parser": "^1.20.2" + } +} diff --git a/todoapp/todoapp_openshift/run.sh b/todoapp/todoapp_openshift/run.sh new file mode 100644 index 0000000000..9b12715ba0 --- /dev/null +++ b/todoapp/todoapp_openshift/run.sh @@ -0,0 +1,2 @@ +#!/bin/bash +npm start