diff --git a/Report/img.png b/Report/img.png new file mode 100644 index 0000000..8a9b284 Binary files /dev/null and b/Report/img.png differ diff --git a/Report/img_1.png b/Report/img_1.png new file mode 100644 index 0000000..d8209af Binary files /dev/null and b/Report/img_1.png differ diff --git a/Report/img_10.png b/Report/img_10.png new file mode 100644 index 0000000..8a03f83 Binary files /dev/null and b/Report/img_10.png differ diff --git a/Report/img_11.png b/Report/img_11.png new file mode 100644 index 0000000..fc65903 Binary files /dev/null and b/Report/img_11.png differ diff --git a/Report/img_12.png b/Report/img_12.png new file mode 100644 index 0000000..9911cc4 Binary files /dev/null and b/Report/img_12.png differ diff --git a/Report/img_13.png b/Report/img_13.png new file mode 100644 index 0000000..6173174 Binary files /dev/null and b/Report/img_13.png differ diff --git a/Report/img_14.png b/Report/img_14.png new file mode 100644 index 0000000..980aa0d Binary files /dev/null and b/Report/img_14.png differ diff --git a/Report/img_15.png b/Report/img_15.png new file mode 100644 index 0000000..d9a3cce Binary files /dev/null and b/Report/img_15.png differ diff --git a/Report/img_16.png b/Report/img_16.png new file mode 100644 index 0000000..3c1cfd7 Binary files /dev/null and b/Report/img_16.png differ diff --git a/Report/img_17.png b/Report/img_17.png new file mode 100644 index 0000000..9e8774b Binary files /dev/null and b/Report/img_17.png differ diff --git a/Report/img_18.png b/Report/img_18.png new file mode 100644 index 0000000..656384e Binary files /dev/null and b/Report/img_18.png differ diff --git a/Report/img_19.png b/Report/img_19.png new file mode 100644 index 0000000..de49fd7 Binary files /dev/null and b/Report/img_19.png differ diff --git a/Report/img_20.png b/Report/img_20.png new file mode 100644 index 0000000..cd561e3 Binary files /dev/null and b/Report/img_20.png differ diff --git a/Report/img_21.png b/Report/img_21.png new file mode 100644 index 0000000..72689a9 Binary files /dev/null and b/Report/img_21.png differ diff --git a/Report/img_6.png b/Report/img_6.png new file mode 100644 index 0000000..b553d48 Binary files /dev/null and b/Report/img_6.png differ diff --git a/Report/img_7.png b/Report/img_7.png new file mode 100644 index 0000000..534dc47 Binary files /dev/null and b/Report/img_7.png differ diff --git a/Report/report.md b/Report/report.md new file mode 100644 index 0000000..d81b602 --- /dev/null +++ b/Report/report.md @@ -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) \ No newline at end of file diff --git a/configs/serverA.sh b/configs/serverA.sh new file mode 100644 index 0000000..d99c887 --- /dev/null +++ b/configs/serverA.sh @@ -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 diff --git a/configs/serverB.sh b/configs/serverB.sh new file mode 100644 index 0000000..32e0e1f --- /dev/null +++ b/configs/serverB.sh @@ -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 + diff --git a/configs/serverC.sh b/configs/serverC.sh new file mode 100644 index 0000000..b267444 --- /dev/null +++ b/configs/serverC.sh @@ -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" \ No newline at end of file diff --git a/src/main.go b/src/main.go new file mode 100644 index 0000000..008f159 --- /dev/null +++ b/src/main.go @@ -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) + } +}