Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Report/img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_15.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_17.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_18.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_19.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_20.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_21.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Report/img_7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
141 changes: 141 additions & 0 deletions Report/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Отчет по работе с Линуксом

## Создание контейнеров в Play-with-docker

Работа проводилась в среде Play-with-docker.

Сначала добавим три контейнера, нажав кнопку `ADD NEW INSTANCE`.

После добавления контейнеров интерфейс будет выглядеть следующим образом:

![img.png](img.png)

Для работы с ними подключимся к каждому контейнеру через терминалы с использованием SSH-соединений.

![img_1.png](img_1.png)

Теперь настроим сеть с использованием ipvlan. Добавим по одному сетевому адаптеру к каждому из контейнеров A и C:

- ВМ A: IP-адрес 192.168.30.10 с маской 255.255.255.0
- ВМ C: IP-адрес 192.168.7.100 с маской 255.255.255.0


![img_11.png](img_11.png)

![img_12.png](img_12.png)
Также добавляем 2 адаптера контейнеру B:

![img_13.png](img_13.png)

### Маршрутизация
Теперь настроим маршрутизацию. Укажем контейнеру A отправлять пакеты к контейнеру C через адаптер `macvlan1`, который находится на контейнере B.

- Контейнер A: ip route add 192.168.7.0/24 via 192.168.30.1

Для контейнера С сделаем наоборот

- Контейнер C: ip route add 192.168.30.0/24 via 192.168.7.1

![img_14.png](img_14.png)

![img_15.png](img_15.png)

сделаем пинг

![img_16.png](img_16.png)

## Создание и запуск сервера

Так как был выбран язык Go для реализации задания то установим его и проверим.

Для этого выполним команды
- apk update
- apk add go
-
![img_6.png](img_6.png)

запустим сервер

![img_7.png](img_7.png)

Теперь проверим работу GET, POST, PUT запросов.

# Описание сервиса
### Описание сервиса сокращения URL

Сервис сокращения URL позволяет пользователям преобразовывать длинные URL-адреса в короткие, которые легче запоминать и делиться. Он предоставляет несколько основных функций, включая создание коротких URL, перенаправление на оригинальные URL, отображение всех сокращенных URL и обновление существующих URL.

#### Основные функции:

1. **Сокращение URL**:
- Метод: `POST`
- Эндпоинт: `/shorten`
- Описание: Пользователь отправляет оригинальный URL, и сервис возвращает сокращенный URL. Сокращенный URL имеет формат `http://localhost:8080/{id}`, где `{id}` — уникальный идентификатор, присвоенный оригинальному URL.

2. **Перенаправление на оригинальный URL**:
- Метод: `GET`
- Эндпоинт: `/`
- Описание: При обращении к сокращенному URL (например, `http://localhost:8080/1`), сервис перенаправляет пользователя на оригинальный URL, связанный с этим идентификатором.

3. **Отображение всех сокращенных URL**:
- Метод: `GET`
- Эндпоинт: `/map`
- Описание: Возвращает JSON-объект, содержащий все сокращенные URL и их соответствующие оригинальные URL. Это позволяет пользователям видеть все их сокращенные ссылки.

4. **Обновление существующего URL**:
- Метод: `PUT`
- Эндпоинт: `/update/{id}`
- Описание: Пользователь может обновить оригинальный URL, связанный с определенным идентификатором. Для этого необходимо указать новый URL в теле запроса.

#### Пример использования:
1. **Сокращение URL**:
- Запрос: `POST /shorten` с телом `url=http://youtube.com`
- Ответ: `Shortened URL: http://localhost:8080/1`

2. **Перенаправление**:
- Запрос: `GET /1`
- Ответ: Перенаправление на `http://youtube.com`

3. **Отображение всех URL**:
- Запрос: `GET /map`
- Ответ: `{"1": "http://youtube.com"}`

4. **Обновление URL**:
- Запрос: `PUT /update/1` с телом `url=https://github.com/play-with-docker/play-with-docker/issues/159`
- Ответ: `Updated URL for 1 to https://github.com/play-with-docker/play-with-docker/issues/159`

# Проделаем все шаги на контейнерах

# 1. Post

![img_18.png](img_18.png)![img_17.png](img_17.png)
```ssh
curl -X POST http://192.168.30.10:8080/shorten -d "url=http://youtube.com"
```
Создадим в мапе новое значение с скоращенной ссылкой

# 2. Get

```ssh
curl -L http://192.168.30.10:8080/2
```

![img_20.png](img_20.png)
Возвращает страцу которая ранее была добавлена в мапу

```ssh
curl http://192.168.30.10:8080/map
```

Возвращает все сохраненные ссылки

![img_19.png](img_19.png)

# 3. Put

```ssh
curl -X PUT http://192.168.30.10:8080/update/2 -d "url=http://vk.com"
```
Обновим существующее значение в мапе

![img_21.png](img_21.png)
122 changes: 122 additions & 0 deletions configs/serverA.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/bin/bash
ip link add macvlan1 link eth0 type macvlan mode bridge
ip address add dev macvlan1 192.168.30.10/24
ip link set macvlan1 up
ip route add 192.168.7.0/24 via 192.168.30.1
apk update
apk add go
touch main.go

cat << EOF > main.go
package main

import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"sync"
)

var (
urlMapping = make(map[int]string)
mu sync.Mutex
nextID = 1
)

func shortenURLHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
originalURL := r.FormValue("url")
if originalURL == "" {
http.Error(w, "URL is required", http.StatusBadRequest)
return
}

mu.Lock()
shortURLID := nextID
urlMapping[shortURLID] = originalURL
nextID++
mu.Unlock()

shortURL := fmt.Sprintf("http://localhost:8080/%d", shortURLID)
fmt.Fprintf(w, "Shortened URL: %s\n", shortURL)
fmt.Printf("INFO Shortened URL: %s\n", shortURL)
} else {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
}
}

func redirectHandler(w http.ResponseWriter, r *http.Request) {
shortURLIDStr := r.URL.Path[1:]
shortURLID, err := strconv.Atoi(shortURLIDStr)
if err != nil {
http.Error(w, "Invalid URL ID", http.StatusBadRequest)
return
}

mu.Lock()
originalURL, exists := urlMapping[shortURLID]
mu.Unlock()

if !exists {
http.Error(w, "URL not found", http.StatusNotFound)
return
}

http.Redirect(w, r, originalURL, http.StatusPermanentRedirect)
}

func mapHandler(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(urlMapping)
}

func updateURLHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPut {
shortURLIDStr := r.URL.Path[8:]
shortURLID, err := strconv.Atoi(shortURLIDStr)
if err != nil {
http.Error(w, "Invalid URL ID", http.StatusBadRequest)
return
}

originalURL := r.FormValue("url")
if originalURL == "" {
http.Error(w, "URL is required", http.StatusBadRequest)
return
}

mu.Lock()
defer mu.Unlock()

if _, exists := urlMapping[shortURLID]; !exists {
http.Error(w, "URL not found", http.StatusNotFound)
return
}

urlMapping[shortURLID] = originalURL
fmt.Fprintf(w, "Updated URL for %d to %s\n", shortURLID, originalURL)
fmt.Printf("INFO Updated URL for %d to %s\n", shortURLID, originalURL)
} else {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
}
}

func main() {
http.HandleFunc("/shorten", shortenURLHandler)
http.HandleFunc("/", redirectHandler)
http.HandleFunc("/map", mapHandler)
http.HandleFunc("/update/", updateURLHandler) // Note the trailing slash for the update handler

fmt.Println("Starting server on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}


EOF
echo "Run server"
go run main.go
8 changes: 8 additions & 0 deletions configs/serverB.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
ip link add macvlan1 link eth0 type macvlan mode bridge
ip address add dev macvlan1 192.168.30.1/24
ip link set macvlan1 up
ip link add macvlan2 link eth0 type macvlan mode bridge
ip address add dev macvlan2 192.168.7.1/24
ip link set macvlan2 up

14 changes: 14 additions & 0 deletions configs/serverC.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
ip link add macvlan1 link eth0 type macvlan mode bridge
ip address add dev macvlan1 192.168.7.100/24
ip link set macvlan1 up
ip route add 192.168.30.0/24 via 192.168.7.1

echo "GET-request"
curl "http://192.168.20.10:5000/"

echo "POST-request"
curl -X POST "http://192.168.20.10:5000?sent=modern"

echo "PUT-request"
curl -X PUT "http://192.168.20.10:5000?sent=very modern"
107 changes: 107 additions & 0 deletions src/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package main

import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"sync"
)

var (
urlMapping = make(map[int]string)
mu sync.Mutex
nextID = 1
)

func shortenURLHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
originalURL := r.FormValue("url")
if originalURL == "" {
http.Error(w, "URL is required", http.StatusBadRequest)
return
}

mu.Lock()
shortURLID := nextID
urlMapping[shortURLID] = originalURL
nextID++
mu.Unlock()

shortURL := fmt.Sprintf("http://localhost:8080/%d", shortURLID)
fmt.Fprintf(w, "Shortened URL: %s\n", shortURL)
fmt.Printf("INFO Shortened URL: %s\n", shortURL)
} else {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
}
}

func redirectHandler(w http.ResponseWriter, r *http.Request) {
shortURLIDStr := r.URL.Path[1:]
shortURLID, err := strconv.Atoi(shortURLIDStr)
if err != nil {
http.Error(w, "Invalid URL ID", http.StatusBadRequest)
return
}

mu.Lock()
originalURL, exists := urlMapping[shortURLID]
mu.Unlock()

if !exists {
http.Error(w, "URL not found", http.StatusNotFound)
return
}

http.Redirect(w, r, originalURL, http.StatusPermanentRedirect)
}

func mapHandler(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(urlMapping)
}

func updateURLHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPut {
shortURLIDStr := r.URL.Path[8:]
shortURLID, err := strconv.Atoi(shortURLIDStr)
if err != nil {
http.Error(w, "Invalid URL ID", http.StatusBadRequest)
return
}

originalURL := r.FormValue("url")
if originalURL == "" {
http.Error(w, "URL is required", http.StatusBadRequest)
return
}

mu.Lock()
defer mu.Unlock()

if _, exists := urlMapping[shortURLID]; !exists {
http.Error(w, "URL not found", http.StatusNotFound)
return
}

urlMapping[shortURLID] = originalURL
fmt.Fprintf(w, "Updated URL for %d to %s\n", shortURLID, originalURL)
fmt.Printf("INFO Updated URL for %d to %s\n", shortURLID, originalURL)
} else {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
}
}

func main() {
http.HandleFunc("/shorten", shortenURLHandler)
http.HandleFunc("/", redirectHandler)
http.HandleFunc("/map", mapHandler)
http.HandleFunc("/update/", updateURLHandler) // Note the trailing slash for the update handler

fmt.Println("Starting server on :8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}