From b4674fcab92b85f2bfc20dccb84785b9c2a20ec7 Mon Sep 17 00:00:00 2001 From: Ilwyrr <45685892+Ilwyrr@users.noreply.github.com> Date: Fri, 7 Dec 2018 11:17:50 +0100 Subject: [PATCH 1/6] Add files via upload --- devops-lab-master/Readme.md | 185 +++++++++++++++++++++++++++++++++++ devops-lab-master/answers.md | 41 ++++++++ 2 files changed, 226 insertions(+) create mode 100644 devops-lab-master/Readme.md create mode 100644 devops-lab-master/answers.md diff --git a/devops-lab-master/Readme.md b/devops-lab-master/Readme.md new file mode 100644 index 00000000..195a2c7e --- /dev/null +++ b/devops-lab-master/Readme.md @@ -0,0 +1,185 @@ +# Lab : Introduction Devops +This lab goal is to introduce DevOps concept (Git, Gitflow, Docker,...) seen in [corresponding course](https://github.com/arthurmauvezin/devops-course). It is adapted to fit ece courses. + +## Update of repo +After having forked this repo, if you want to get updates from the last version of the repo parent, execute following commands +```bash +git remote add parent https://github.com/arthurmauvezin/devops-lab.git +git pull +``` + +## Instructions +This lab rely on your web technologies project. The goal of this lab is to deploy your project with the help of docker and docker-compose. + +> This lab assume your web technologies project is finished, or at least that your can call your REST API to get, create, update or delete items in your zoo. + +All the answers for questions asked in this lab instructions must be filled in **answers.md** file situated in your own fork of this repo. + +This lab must be completed individually. + +## 1: Git + +### 1.0: Create a Github account +Go to [Github](https://github.com/) and create a personal account if you do not have one already. + +### 1.1: Fork course repo +Go to [devops-lab](https://github.com/arthurmauvezin/devops-lab.git) Github project and fork the repo to get your own copy of this repo into your newly created personal space. + +To get more help about fork, see the [official documentation](https://guides.github.com/activities/forking/) + +### 1.2: Clone your fork +Clone your newly forked project on your computer + +### 1.3: Faire un commit +After the clone, you should have your copy of the project on your computer. Go into cloned folder and add your firstname and lastname to **answers.md** file. + +Commit and push your changes. You should see your change on Github graphical interface. + +### 1.4: Create a pull request +From your Github project fork page, create a pull request to propose your change to parent project (lab repo). + +To get more help agout pull requests, see [official documentation](https://help.github.com/articles/about-pull-requests/) + +### 1.5: Commit your project +Add your express js project to this git repo and commit to save it for the future. + +> In order to get your grade, at the end of the lab, commit and push all changes your made to your repo. + +## 2: Docker +### 2.0: Documentation +* [Docker doc reference](https://docs.docker.com/reference/) +* [Dockerfile reference documentation](https://docs.docker.com/engine/reference/builder/) +* [Docker Hub](https://hub.docker.com/) containing all public images + +### 2.1: Dockerise your application +At the root directory of your project, create a file called **Dockerfile** able to build a node image conaining your express code. + +Help: +* Check [Dockerfile reference documentation](https://docs.docker.com/engine/reference/builder/) if needed +* Base your image on node official image [Docker Hub](https://hub.docker.com/) +* Node use librairies to install on host before starting program (cf. `npm `). To install these librairies, execute following command in Dockerfile. +```bash +npm install +``` +* **WORKDIR** command might help +* If you want to optimize, use Alpine images + +### 2.2: Run your app +Start a docker container from the image you just created in the preceding question. Write the command you use in answers.md file. + +Check log output message to validate that your server started correctly. + +### 2.3: Access to your service +Try to access to your service (with postman for example). Why is your call fail ? + +Restart container beeing careful to open needed port to get access to your service (see docker help). Write the command you use in answers.md file. + +### 2.4: Environment variable +Modify your javascript code to read and user the value of following environement variables to connect to MySQL database: +* MYSQL_HOST +* MYSQL_PORT +* MYSQL_DATABASE +* MYSQL_USER +* MYSQL_PASSWORD + +Rebuild your image and run it again being careful to pass corresponding variable as arguments (see environement variables in docker run documentation). + +Your application should run normally at this point. + +### 2.5: Ship your image +In order to share your new image with the world, you will push your image to official public registry called Docker Hub (or Docker Store). + +To do that: +* Create yourself an account on [Docker Hub](https://hub.docker.com/) +* Create a new repository attached to your account +* Then, push your image to your newly created repository + +Your image cannot be pushed as it is. Why ? Modify the name of your image and push it again on your new repository on Docker Hub. Write the command you use in answers.md file. + +### 2.6: Let's Run it +Now that your image is shared with the world, you can pull it from any computer on which Docker is installed. + +Delete all your images created from the start of the lab on your computer. Write the command you use in answers.md file. + +Start a container again with the name you pushed on Docker hub earlier. What happened before container start ? Write the command you use in answers.md file. + +Your container works as intended but if you close your terminal, it will stop. Start your container again in detached mode and call your service to check accessibility. Write the command you use in answers.md file. + +### 2.7: Naming +Your container is normally started. In detached mode, how can you tell that container is started ? What is the name of your container ? Write the command you use in answers.md file. + +Restart your container by renaming it with a name corresponding to its function. Write the command you use in answers.md file. + +### 2.8: Go inside +Your container running, open an interactive session to obseve files inside container. + +Help: +Executing following command get OS informations: +```bash +cat /etc/*release +``` + +What is the OS from the container ? Copy command ouput into answers.md + +## 3: Docker Compose +In this part, we will user docker-compose to automate deployment of the app we built in part 1 of this lab. + +### 3.0: Download docker-compose +Go to [official site](https://docs.docker.com/compose/install/) and install docker-compose for your OS. + +> Be careful: Stop all your running container before starting this part + +### 3.1: Docker-compose file +At your project root folder, create a file called docker-compose.yml containing following code: +```yaml +version: '3' +services: + my-service: + image: my-image +``` + +Edit this file to user your own image and rename service as you wish. Then, start service with the help of **docker-compose** commands. + +> Available documentation on official site + +Write the command you use in answers.md file. + +### 3.2: Ports +Modify docker-compose.yml file to add port mount on your service + +Restart container and test solution. + +### 3.3: Environment variables +Modify docker-compose.yml file to add environment variables needed to use your service. + +Restart container and test solution. + +### 3.4: Detached +Restart services in detached mode. Write the command you use in answers.md file. + +Visualise logs from your service. Write the command you use in answers.md file. + +### 3.5: Upgrade +At any time, when you started your service in detached mode, you can reload a new version by executing the following line again: +```bash +docker-compose up -d +``` + +### 3.6: [BONUS] Dockerise MySQL +Use all knowledge you acquirred today to dockerise mysql database using official MySQL database docker image. + +After this step, add mysql as another service to your docker-compose.yml file. + +#### Answer: +```docker-compose.yml +version: '3.1' +services: + db: + image: arthurmauvezin/docker-labs-mysql:latest + command: --default-authentication-plugin=mysql_native_password + restart: always + environment: + MYSQL_ROOT_PASSWORD: example + MYSQL_DATABASE: project +``` + diff --git a/devops-lab-master/answers.md b/devops-lab-master/answers.md new file mode 100644 index 00000000..f6fd2432 --- /dev/null +++ b/devops-lab-master/answers.md @@ -0,0 +1,41 @@ +# Answers + +Lastname: Valran +Firstname: Adrien + +## 2.2 +command: + +## 2.3 +question: +command: + +## 2.5 +question: +command: + +## 2.6 +command: + +question: +command: + +command: + +## 2.7 +question: +question: +command: + +command: + +## 2.8 +question: +output: + +## 3.1 +command: + +## 3.4 +command: +command: From 5f6e735598ab629ecf80a4b94eaeb4a92bc17882 Mon Sep 17 00:00:00 2001 From: Ilwyrr Date: Fri, 7 Dec 2018 11:35:48 +0100 Subject: [PATCH 2/6] commit! --- answers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/answers.md b/answers.md index b7025b97..f6fd2432 100644 --- a/answers.md +++ b/answers.md @@ -1,7 +1,7 @@ # Answers -Lastname: -Firstname: +Lastname: Valran +Firstname: Adrien ## 2.2 command: From 19affde2100635075f7819bc5f592fd940acf5db Mon Sep 17 00:00:00 2001 From: Ilwyrr Date: Sun, 16 Dec 2018 21:32:47 +0100 Subject: [PATCH 3/6] api --- webapi.js | 869 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 869 insertions(+) create mode 100644 webapi.js diff --git a/webapi.js b/webapi.js new file mode 100644 index 00000000..0a5dd8ac --- /dev/null +++ b/webapi.js @@ -0,0 +1,869 @@ +const express = require ( 'express' ); +const mysql = require ( 'mysql' ); +const app = express(); +const bodyParser = require ( 'body-parser' ); + +app.use(bodyParser.urlencoded({ extended: true })); + +var db = mysql.createConnection({ + host: "localhost" , + user: "root" , + password: "" , + database: "project" , + port: "3306" +}); + +////////////////////////////////////////////////// +// // +// Table animals // +// // +////////////////////////////////////////////////// + +app.post( '/animals' , function (req, res) { + var name = req.body.name; + var breed = req.body.breed + var food_per_day = req.body.food_per_day; + var birthday = req.body.birthday; + var entry_date = req.body.entry_date; + var id_cage = req.body.id_cage; + var query = "INSERT INTO animals (name, breed, food_per_day, birthday, entry_date, id_cage) VALUES ('" + + name + "','" + breed + "'," + food_per_day + ",'" + birthday + "','" + entry_date + "'," + id_cage + ")" ; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.get( '/animals/:id' , function (req, res) { + var id = req.params.id; + var query = "SELECT * FROM animals WHERE id=" + id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + +app.delete( '/animals' , function (req, res) { + var query = "DELETE FROM animals" ; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.delete( '/animals/:id' , function (req, res) { + var id = req.params.id; + var query = "DELETE FROM animals WHERE id=" + id; + + db.query(query, function (err, result, fields) { + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.put( '/animals/:id' , function (req, res) { + var id = req.params.id; + var name = req.body.name; + var breed = req.body.breed; + var food_per_day = req.body.food_per_day; + var birthday = req.body.birthday; + var entry_date = req.body.entry_date; + var id_cage = req.body.id_cage; + var i = 0; + + var query = "UPDATE animals SET "; + + if(name){ + if (i==1) { + query = query + ", "; + } + query = query + "name = " + name; + i = 1; + } + + if(breed){ + if (i==1) { + query = query + ", "; + } + query = query + "breed = " + breed; + i = 1; + } + + if(food_per_day){ + if (i==1) { + query = query + ", "; + } + query = query + "food_per_day = " + food_per_day; + i = 1; + } + + if(birthday){ + if (i==1) { + query = query + ", "; + } + query = query + "birthday = " + birthday; + i = 1; + } + + if(entry_date){ + if (i==1) { + query = query + ", "; + } + query = query + "birthday = " + birthday; + i = 1; + } + + if (id_cage) { + if (i==1) { + query = query + ", "; + } + query = query + "id_cage = " + id_cage; + } + + query = query + " WHERE id="+ id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + + +////////////////////////////////////////////////// +// // +// Table cages // +// // +////////////////////////////////////////////////// + +app.post( '/cages' , function (req, res) { + var name = req.body.name; + var description = req.body.description; + var area = req.body.area; + var query = "INSERT INTO cages (name, description, area) VALUES ('" + name + "','" + description + "'," + area + ")"; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.get( '/cages/:id' , function (req, res) { + var id = req.params.id; + var query = "SELECT * FROM cages WHERE id=" + id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + +app.delete( '/cages' , function (req, res) { + var query = "DELETE FROM cages" ; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.delete( '/cages/:id' , function (req, res) { + var id = req.params.id; + var query = "DELETE FROM cages WHERE id=" + id; + + db.query(query, function (err, result, fields) { + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.put( '/cages/:id' , function (req, res) { + var id = req.params.id; + var name = req.body.name; + var description = req.body.description; + var area = req.body.area; + var i = 0; + + var query = "UPDATE cages SET "; + + if(name){ + query = query + "name = '" + name + "'"; + i = 1; + } + + if (description) { + if (i==1) { + query = query + ", "; + } + query = query + "description = '" + description + "' "; + i = 1; + } + + if (area) { + if (i == 1) { + query = query + ", "; + } + query = query + "area = " + area; + } + + query = query + " WHERE id="+ id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + + +////////////////////////////////////////////////// +// // +// Table food // +// // +////////////////////////////////////////////////// + +app.post( '/food' , function (req, res) { + var name = req.body.name; + var quantity = req.body.quantity; + var id_animal = req.body.id_animal; + var query = "INSERT INTO food (name, quantity, id_animal) VALUES ('" + name + "'," + quantity + "," + id_animal + ")"; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.get( '/food/:id' , function (req, res) { + var id = req.params.id; + var query = "SELECT * FROM food WHERE id=" + id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + +app.delete( '/food' , function (req, res) { + var query = "DELETE FROM food" ; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.delete( '/food/:id' , function (req, res) { + var id = req.params.id; + var query = "DELETE FROM food WHERE id=" + id; + + db.query(query, function (err, result, fields) { + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.put( '/food/:id' , function (req, res) { + var id = req.params.id; + var name = reg.body.name; + var quantity = req.body.quantity; + var id_animal = req.body.id_animal; + var i = 0; + + var query = "UPDATE food SET "; + + if (name) { + if (i==1) { + query = query + ", "; + } + query = query + "name = " + name; + i = 1; + } + + if(quantity){ + if (i==1) { + query = query + ", "; + } + query = query + "quantity = " + quantity; + i = 1; + } + + if (id_animal) { + if (i==1) { + query = query + ", "; + } + query = query + "id_animal = " + id_animal; + } + + query = query + " WHERE id="+ id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + + +////////////////////////////////////////////////// +// // +// Table staff // +// // +////////////////////////////////////////////////// + +app.post( '/staff' , function (req, res) { + var firstname = req.body.firstname; + var lastname = req.body.lastname; + var wage = req.body.wage; + var query = "INSERT INTO staff (firstname, lastname, wage) VALUES ('" + firstname + "','" + lastname + "'," + wage + ")"; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + + +app.get( '/staff/:id' , function (req, res) { + var id = req.params.id; + var query = "SELECT * FROM staff WHERE id=" + id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + +app.delete( '/staff' , function (req, res) { + var query = "DELETE FROM staff" ; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.delete( '/staff/:id' , function (req, res) { + var id = req.params.id; + var query = "DELETE FROM staff WHERE id=" + id; + + db.query(query, function (err, result, fields) { + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.put( '/staff/:id' , function (req, res) { + var id = req.params.id; + var wage = req.body.wage; + var firstname = req.body.firstname; + var lastname = req.body.lastname; + + var query = "UPDATE staff SET "; + + if (firstname) { + if (i==1) { + query = query + ", "; + } + query = query + "firstname = " + firstname; + } + + if (lastname) { + if (i==1) { + query = query + ", "; + } + query = query + "lastname = " + lastname; + } + + if (wage) { + if (i==1) { + query = query + ", "; + } + query = query + "wage = " + wage; + } + + query = query + " WHERE id="+ id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +////////////////////////////////////////////////// +// // +// Table users // +// // +////////////////////////////////////////////////// + +app.post( '/users' , function (req, res) { + var username = req.body.username; + var apikey = req.body.apikey; + + var query = "INSERT INTO users (username, apikey) VALUES ('" + username + "','" + apikey + "')"; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.get( '/users/:id' , function (req, res) { + var id = req.params.id; + var query = "SELECT * FROM users WHERE id=" + id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + +app.delete( '/users' , function (req, res) { + var query = "DELETE FROM users" ; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.delete( '/users/:id' , function (req, res) { + var id = req.params.id; + var query = "DELETE FROM users WHERE id=" + id; + + db.query(query, function (err, result, fields) { + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + +app.put( '/users/:id' , function (req, res) { + var id = req.params.id; + var apikey = req.body.apikey; + var username = req.body.username; + + var query = "UPDATE staff SET "; + + if (username) { + if (i==1) { + query = query + ", "; + } + query = query + "username = " + username; + } + + if (apikey) { + if (i==1) { + query = query + ", "; + } + query = query + "apikey = " + apikey; + } + + query = query + " WHERE id="+ id; + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify( "Success" )); + }); +}); + + +////////////////////////////////////////////////// +// // +// Relationships // +// // +////////////////////////////////////////////////// + +app.get('/animals/:id/cages', function(req, res) { + var id = req.params.id; + var query = "SELECT animals.name, animals.breed, animals.id_cage, cages.name as cage, cages.area " + + "FROM animals INNER JOIN cages ON animals.id_cage = cages.id WHERE animals.id=" + id; + + db.query(query, function(err, result, fields) { + + if (err) throw err; + res.send(JSON.stringify(result)); + }); +}); + +app.get('/animals/:id/food', function(req, res) { + var id = req.params.id; + var query = "SELECT animals.name, animals.breed, animals.food_per_day, animals.id_cage, food.name as food, food.quantity " + + "FROM animals INNER JOIN food ON animals.id = food.id_animal WHERE animals.id=" + id; + + db.query(query, function(err, result, fields) { + + if (err) throw err; + res.send(JSON.stringify(result)); + }); +}); + +app.get('/animals/:ida/cages/:idc', function(req, res) { + var id_user = req.params.ida; + var id_data = req.params.idc; + var query = "SELECT * FROM animals INNER JOIN cages ON animals.id_cage = cage.id WHERE animals.id=" + ida + " AND cages.id=" +idc; + + db.query(query, function(err, result, fields) { + + if (err) throw err; + res.send(JSON.stringify(result)); + }); +}); + +app.get('/animals/:ida/food/:idf', function(req, res) { + var id_user = req.params.ida; + var id_data = req.params.idf; + var query = "SELECT * FROM animals INNER JOIN food ON animals.id = food.animal_id WHERE animals.id=" + ida + " AND food.id=" +idc; + + db.query(query, function(err, result, fields) { + + if (err) throw err; + res.send(JSON.stringify(result)); + }); +}); + +////////////////////////////////////////////////// +// // +// get animals // +// // +////////////////////////////////////////////////// + +app.get( '/animals' , function (req, res) { + var query = "SELECT * FROM animals" ; + var conditions = [ "name", "breed", "food_per_day", "birthday", "entry_date", "id_cage" ]; + + for ( var index in conditions) { + if (conditions[index] in req.query) { + if (query.indexOf( "WHERE" ) < 0 ) { + query += " WHERE" ; + } else { + query += " AND" ; + } + query += " " + conditions[index] + "='" + req.query[conditions[index]] + "'" ; + } + } + + if ( "fields" in req.query) { + query = query.replace( "*" , req.query[ "fields" ]); + } + + if ( "limit" in req.query) { + query += " LIMIT " + req.query[ "limit" ]; + if ( "offset" in req.query) { + query += " OFFSET " + req.query[ "offset" ]; + } + } + + if ( "sort" in req.query) { + var sort = req.query[ "sort" ].split( "," ); + query += " ORDER BY" ; + for ( var index in sort) { + var direction = sort[index].substr( -1 ); + var field = sort[index].slice(0,-1); + + query += " " + field; + if (direction == "-" ) query += " DESC" ; + else query += " ASC" ; + } + } + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + + +////////////////////////////////////////////////// +// // +// get cages // +// // +////////////////////////////////////////////////// + +app.get( '/cages' , function (req, res) { + var query = "SELECT * FROM cages" ; + var conditions = [ "id", "name", "description", "area" ]; + + for ( var index in conditions) { + if (conditions[index] in req.query) { + if (query.indexOf( "WHERE" ) < 0 ) { + query += " WHERE" ; + } else { + query += " AND" ; + } + query += " " + conditions[index] + "='" + + req.query[conditions[index]] + "'" ; + } + } + + if ( "fields" in req.query) { + query = query.replace( "*" , req.query[ "fields" ]); + } + + if ( "limit" in req.query) { + query += " LIMIT " + req.query[ "limit" ]; + if ( "offset" in req.query) { + query += " OFFSET " + req.query[ "offset" ]; + } + } + + if ( "sort" in req.query) { + var sort = req.query[ "sort" ].split( "," ); + query += " ORDER BY" ; + for ( var index in sort) { + var direction = sort[index].substr( -1 ); + var field = sort[index].slice(0,-1); + + query += " " + field; + if (direction == "-" ) query += " DESC" ; + else query += " ASC" ; + } + } + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + +////////////////////////////////////////////////// +// // +// get food // +// // +////////////////////////////////////////////////// + +app.get( '/food' , function (req, res) { + var query = "SELECT * FROM food" ; + var conditions = [ "id", "name", "quantity", "id_animal" ]; + + for ( var index in conditions) { + if (conditions[index] in req.query) { + if (query.indexOf( "WHERE" ) < 0 ) { + query += " WHERE" ; + } else { + query += " AND" ; + } + query += " " + conditions[index] + "='" + + req.query[conditions[index]] + "'" ; + } + } + + if ( "fields" in req.query) { + query = query.replace( "*" , req.query[ "fields" ]); + } + + if ( "limit" in req.query) { + query += " LIMIT " + req.query[ "limit" ]; + if ( "offset" in req.query) { + query += " OFFSET " + req.query[ "offset" ]; + } + } + + if ( "sort" in req.query) { + var sort = req.query[ "sort" ].split( "," ); + query += " ORDER BY" ; + for ( var index in sort) { + var direction = sort[index].substr( -1 ); + var field = sort[index].slice(0,-1); + + query += " " + field; + if (direction == "-" ) query += " DESC" ; + else query += " ASC" ; + } + } + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + +////////////////////////////////////////////////// +// // +// get staff // +// // +////////////////////////////////////////////////// + + +app.get('/staff', function(req, res) { + var query = "SELECT * FROM staff"; + var conditions = ["firstname", "lastname", "wage"]; + + for (var index in conditions) { + if (conditions[index] in req.query) { + if (query.indexOf("WHERE") < 0) { + query += " WHERE"; + } else { + query += " AND"; + } + query += " " + conditions[index] + "='" + + req.query[conditions[index]] + "'"; + } + } + + if ( "fields" in req.query) { + query = query.replace( "*" , req.query[ "fields" ]); + } + + if ( "limit" in req.query) { + query += " LIMIT " + req.query[ "limit" ]; + if ( "offset" in req.query) { + query += " OFFSET " + req.query[ "offset" ]; + } + } + + if ( "sort" in req.query) { + var sort = req.query[ "sort" ].split( "," ); + query += " ORDER BY" ; + for ( var index in sort) { + var direction = sort[index].substr( -1 ); + var field = sort[index].slice(0,-1); + + query += " " + field; + if (direction == "-" ) query += " DESC" ; + else query += " ASC" ; + } + } + + db.query(query, function(err, result, fields) { + if (err) throw err; + res.send(JSON.stringify(result)); + }); +}); + + +////////////////////////////////////////////////// +// // +// get users // +// // +////////////////////////////////////////////////// + +app.get( '/users' , function (req, res) { + var query = "SELECT * FROM users" ; + var conditions = [ "username", "apikey" ]; + + for ( var index in conditions) { + if (conditions[index] in req.query) { + if (query.indexOf( "WHERE" ) < 0 ) { + query += " WHERE" ; + } else { + query += " AND" ; + } + query += " " + conditions[index] + "='" + + req.query[conditions[index]] + "'" ; + } + } + + if ( "fields" in req.query) { + query = query.replace( "*" , req.query[ "fields" ]); + } + + if ( "limit" in req.query) { + query += " LIMIT " + req.query[ "limit" ]; + if ( "offset" in req.query) { + query += " OFFSET " + req.query[ "offset" ]; + } + } + + if ( "sort" in req.query) { + var sort = req.query[ "sort" ].split( "," ); + query += " ORDER BY" ; + for ( var index in sort) { + var direction = sort[index].substr( -1 ); + var field = sort[index].slice(0,-1); + + query += " " + field; + if (direction == "-" ) query += " DESC" ; + else query += " ASC" ; + } + } + + db.query(query, function (err, result, fields) { + + if (err) throw err; + res.send( JSON .stringify(result)); + }); +}); + + +////////////////////////////////////////////////// +// // +// food-stats // +// // +////////////////////////////////////////////////// + +app.get('/food-stats', function(req, res) { + var query = "SELECT animals.id as id, if(animals.food_per_day = 0,0,food.quantity/animals.food_per_day) as days_left " + + "from animals join food where animals.id = food.id_animal"; + + var conditions = [ "id", "days_left" ]; + + for ( var index in conditions) { + if (conditions[index] in req.query) { + if (query.indexOf( "WHERE" ) < 0 ) { + query += " WHERE" ; + } else { + query += " AND" ; + } + query += " " + conditions[index] + "='" + + req.query[conditions[index]] + "'" ; + } + } + + if ( "limit" in req.query) { + query += " LIMIT " + req.query[ "limit" ]; + if ( "offset" in req.query) { + query += " OFFSET " + req.query[ "offset" ]; + } + } + + if ( "sort" in req.query) { + var sort = req.query[ "sort" ].split( "," ); + query += " ORDER BY" ; + for ( var index in sort) { + var direction = sort[index].substr( -1 ); + var field = sort[index].slice(0,-1); + + query += " " + field; + if (direction == "-" ) query += " DESC" ; + else query += " ASC" ; + } + } + + db.query(query, function(err, result, fields) { + + if (err) throw err; + res.send(JSON.stringify(result)); + }); +}); + + +app.listen( 3000 , function () { + db.connect( function (err) { + if (err) throw err; + console .log( 'Connection to database successful!' ); + }); + console .log( 'Example app listening on port 3000!' ); +}); From 3bad86a63fe28e0f603b897f81b7e999f9530b7d Mon Sep 17 00:00:00 2001 From: Ilwyrr Date: Sun, 16 Dec 2018 22:40:18 +0100 Subject: [PATCH 4/6] Docherfile --- Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..5bdf1aec --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM node:8 +WORKDIR /usr/src/app +COPY package*.json ./ +RUN npm install +COPY . . +EXPOSE 3000 +CMD [ "npm", "start" ] \ No newline at end of file From 44359709cc2aa716b8109e40dc2789bb21390766 Mon Sep 17 00:00:00 2001 From: Ilwyrr Date: Sun, 16 Dec 2018 23:49:22 +0100 Subject: [PATCH 5/6] last commit --- Dockerfile | 11 +- answers.md | 22 +- devops-lab-master/Readme.md | 185 ---------------- devops-lab-master/answers.md | 41 ---- package-lock.json | 419 +++++++++++++++++++++++++++++++++++ 5 files changed, 439 insertions(+), 239 deletions(-) delete mode 100644 devops-lab-master/Readme.md delete mode 100644 devops-lab-master/answers.md create mode 100644 package-lock.json diff --git a/Dockerfile b/Dockerfile index 5bdf1aec..83095b64 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,14 @@ FROM node:8 + WORKDIR /usr/src/app + COPY package*.json ./ -RUN npm install + +RUN npm install express +RUN npm install mysql + COPY . . + EXPOSE 3000 -CMD [ "npm", "start" ] \ No newline at end of file + +CMD node webapi.js diff --git a/answers.md b/answers.md index f6fd2432..9e3dceb0 100644 --- a/answers.md +++ b/answers.md @@ -4,28 +4,28 @@ Lastname: Valran Firstname: Adrien ## 2.2 -command: +command: $ docker run api ## 2.3 -question: -command: +question: The image doesn't know in which port it has to connect +command: $ docker run -p 3000:3000 api ## 2.5 -question: -command: +question: An image doesn't exist locally with the tag. We have to rename the image in order to match with the repositoty. +command: $ docker push Ilwyrr/test:testapi ## 2.6 -command: +command: docker image prune -all -question: -command: +question: Docker has to download the given image from the repository. +command: $ docker run Ilwyrr/test:testapi -command: +command: docker run --detach Ilwyrr/test:testapi ## 2.7 +question: We can get the status of containers with the docker -ps command question: -question: -command: +command: docker ps -a command: diff --git a/devops-lab-master/Readme.md b/devops-lab-master/Readme.md deleted file mode 100644 index 195a2c7e..00000000 --- a/devops-lab-master/Readme.md +++ /dev/null @@ -1,185 +0,0 @@ -# Lab : Introduction Devops -This lab goal is to introduce DevOps concept (Git, Gitflow, Docker,...) seen in [corresponding course](https://github.com/arthurmauvezin/devops-course). It is adapted to fit ece courses. - -## Update of repo -After having forked this repo, if you want to get updates from the last version of the repo parent, execute following commands -```bash -git remote add parent https://github.com/arthurmauvezin/devops-lab.git -git pull -``` - -## Instructions -This lab rely on your web technologies project. The goal of this lab is to deploy your project with the help of docker and docker-compose. - -> This lab assume your web technologies project is finished, or at least that your can call your REST API to get, create, update or delete items in your zoo. - -All the answers for questions asked in this lab instructions must be filled in **answers.md** file situated in your own fork of this repo. - -This lab must be completed individually. - -## 1: Git - -### 1.0: Create a Github account -Go to [Github](https://github.com/) and create a personal account if you do not have one already. - -### 1.1: Fork course repo -Go to [devops-lab](https://github.com/arthurmauvezin/devops-lab.git) Github project and fork the repo to get your own copy of this repo into your newly created personal space. - -To get more help about fork, see the [official documentation](https://guides.github.com/activities/forking/) - -### 1.2: Clone your fork -Clone your newly forked project on your computer - -### 1.3: Faire un commit -After the clone, you should have your copy of the project on your computer. Go into cloned folder and add your firstname and lastname to **answers.md** file. - -Commit and push your changes. You should see your change on Github graphical interface. - -### 1.4: Create a pull request -From your Github project fork page, create a pull request to propose your change to parent project (lab repo). - -To get more help agout pull requests, see [official documentation](https://help.github.com/articles/about-pull-requests/) - -### 1.5: Commit your project -Add your express js project to this git repo and commit to save it for the future. - -> In order to get your grade, at the end of the lab, commit and push all changes your made to your repo. - -## 2: Docker -### 2.0: Documentation -* [Docker doc reference](https://docs.docker.com/reference/) -* [Dockerfile reference documentation](https://docs.docker.com/engine/reference/builder/) -* [Docker Hub](https://hub.docker.com/) containing all public images - -### 2.1: Dockerise your application -At the root directory of your project, create a file called **Dockerfile** able to build a node image conaining your express code. - -Help: -* Check [Dockerfile reference documentation](https://docs.docker.com/engine/reference/builder/) if needed -* Base your image on node official image [Docker Hub](https://hub.docker.com/) -* Node use librairies to install on host before starting program (cf. `npm `). To install these librairies, execute following command in Dockerfile. -```bash -npm install -``` -* **WORKDIR** command might help -* If you want to optimize, use Alpine images - -### 2.2: Run your app -Start a docker container from the image you just created in the preceding question. Write the command you use in answers.md file. - -Check log output message to validate that your server started correctly. - -### 2.3: Access to your service -Try to access to your service (with postman for example). Why is your call fail ? - -Restart container beeing careful to open needed port to get access to your service (see docker help). Write the command you use in answers.md file. - -### 2.4: Environment variable -Modify your javascript code to read and user the value of following environement variables to connect to MySQL database: -* MYSQL_HOST -* MYSQL_PORT -* MYSQL_DATABASE -* MYSQL_USER -* MYSQL_PASSWORD - -Rebuild your image and run it again being careful to pass corresponding variable as arguments (see environement variables in docker run documentation). - -Your application should run normally at this point. - -### 2.5: Ship your image -In order to share your new image with the world, you will push your image to official public registry called Docker Hub (or Docker Store). - -To do that: -* Create yourself an account on [Docker Hub](https://hub.docker.com/) -* Create a new repository attached to your account -* Then, push your image to your newly created repository - -Your image cannot be pushed as it is. Why ? Modify the name of your image and push it again on your new repository on Docker Hub. Write the command you use in answers.md file. - -### 2.6: Let's Run it -Now that your image is shared with the world, you can pull it from any computer on which Docker is installed. - -Delete all your images created from the start of the lab on your computer. Write the command you use in answers.md file. - -Start a container again with the name you pushed on Docker hub earlier. What happened before container start ? Write the command you use in answers.md file. - -Your container works as intended but if you close your terminal, it will stop. Start your container again in detached mode and call your service to check accessibility. Write the command you use in answers.md file. - -### 2.7: Naming -Your container is normally started. In detached mode, how can you tell that container is started ? What is the name of your container ? Write the command you use in answers.md file. - -Restart your container by renaming it with a name corresponding to its function. Write the command you use in answers.md file. - -### 2.8: Go inside -Your container running, open an interactive session to obseve files inside container. - -Help: -Executing following command get OS informations: -```bash -cat /etc/*release -``` - -What is the OS from the container ? Copy command ouput into answers.md - -## 3: Docker Compose -In this part, we will user docker-compose to automate deployment of the app we built in part 1 of this lab. - -### 3.0: Download docker-compose -Go to [official site](https://docs.docker.com/compose/install/) and install docker-compose for your OS. - -> Be careful: Stop all your running container before starting this part - -### 3.1: Docker-compose file -At your project root folder, create a file called docker-compose.yml containing following code: -```yaml -version: '3' -services: - my-service: - image: my-image -``` - -Edit this file to user your own image and rename service as you wish. Then, start service with the help of **docker-compose** commands. - -> Available documentation on official site - -Write the command you use in answers.md file. - -### 3.2: Ports -Modify docker-compose.yml file to add port mount on your service - -Restart container and test solution. - -### 3.3: Environment variables -Modify docker-compose.yml file to add environment variables needed to use your service. - -Restart container and test solution. - -### 3.4: Detached -Restart services in detached mode. Write the command you use in answers.md file. - -Visualise logs from your service. Write the command you use in answers.md file. - -### 3.5: Upgrade -At any time, when you started your service in detached mode, you can reload a new version by executing the following line again: -```bash -docker-compose up -d -``` - -### 3.6: [BONUS] Dockerise MySQL -Use all knowledge you acquirred today to dockerise mysql database using official MySQL database docker image. - -After this step, add mysql as another service to your docker-compose.yml file. - -#### Answer: -```docker-compose.yml -version: '3.1' -services: - db: - image: arthurmauvezin/docker-labs-mysql:latest - command: --default-authentication-plugin=mysql_native_password - restart: always - environment: - MYSQL_ROOT_PASSWORD: example - MYSQL_DATABASE: project -``` - diff --git a/devops-lab-master/answers.md b/devops-lab-master/answers.md deleted file mode 100644 index f6fd2432..00000000 --- a/devops-lab-master/answers.md +++ /dev/null @@ -1,41 +0,0 @@ -# Answers - -Lastname: Valran -Firstname: Adrien - -## 2.2 -command: - -## 2.3 -question: -command: - -## 2.5 -question: -command: - -## 2.6 -command: - -question: -command: - -command: - -## 2.7 -question: -question: -command: - -command: - -## 2.8 -question: -output: - -## 3.1 -command: - -## 3.4 -command: -command: diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..0850a96f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,419 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "bignumber.js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", + "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" + }, + "mime-types": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "requires": { + "mime-db": "~1.37.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mysql": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.16.0.tgz", + "integrity": "sha512-dPbN2LHonQp7D5ja5DJXNbCLe/HRdu+f3v61aguzNRQIrmZLOeRoymBYyeThrR6ug+FqzDL95Gc9maqZUJS+Gw==", + "requires": { + "bignumber.js": "4.1.0", + "readable-stream": "2.3.6", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} From 0847f315d0a800878770ff26fd26eb71a6926480 Mon Sep 17 00:00:00 2001 From: Ilwyrr Date: Sun, 16 Dec 2018 23:52:31 +0100 Subject: [PATCH 6/6] der des der --- answers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/answers.md b/answers.md index 9e3dceb0..9042d327 100644 --- a/answers.md +++ b/answers.md @@ -30,7 +30,7 @@ command: docker ps -a command: ## 2.8 -question: +question: Linux output: ## 3.1