mirror of
https://github.com/GNS3/gns3-server.git
synced 2024-12-19 12:57:56 +00:00
Merge remote-tracking branch 'origin/3.0' into gh-pages
This commit is contained in:
commit
c554861070
16
CHANGELOG
16
CHANGELOG
@ -1,5 +1,21 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.29 08/01/2022
|
||||
|
||||
* Release web UI 2.2.29
|
||||
* Add NixOS in list of distributions with a package
|
||||
|
||||
## 2.2.28 15/12/2021
|
||||
|
||||
* Fix compute Docker test. Fixes #2003
|
||||
* Release web UI 2.2.28
|
||||
* Simpler Systemd service file. Ref #1996
|
||||
|
||||
## 2.2.27 12/11/2021
|
||||
|
||||
* Release web UI 2.2.27
|
||||
* Fix unhandled KeyError exception when starting Docker container. Ref #1991
|
||||
|
||||
## 2.2.26 08/10/2021
|
||||
|
||||
* Release web UI 2.2.26
|
||||
|
34
Dockerfile
34
Dockerfile
@ -1,21 +1,37 @@
|
||||
FROM python:3.6-alpine3.11
|
||||
FROM ubuntu:focal
|
||||
|
||||
WORKDIR /gns3server
|
||||
|
||||
RUN apt update && DEBIAN_FRONTEND=noninteractive apt install -y \
|
||||
locales \
|
||||
locales-all
|
||||
|
||||
ENV LANG en_US.UTF-8
|
||||
ENV LANGUAGE en_US:en
|
||||
ENV LC_ALL en_US.UTF-8
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
ENV PYTHONBUFFERED 1
|
||||
|
||||
COPY ./requirements.txt /gns3server/requirements.txt
|
||||
|
||||
RUN set -eux \
|
||||
&& apk add --no-cache --virtual .build-deps build-base \
|
||||
gcc libc-dev musl-dev linux-headers python3-dev \
|
||||
vpcs qemu libvirt ubridge \
|
||||
&& pip install --no-cache-dir --upgrade pip setuptools wheel \
|
||||
&& pip install --no-cache-dir -r /gns3server/requirements.txt
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt install -y \
|
||||
locales \
|
||||
software-properties-common \
|
||||
python3-pip \
|
||||
python3-all \
|
||||
python3-setuptools \
|
||||
python3-dev \
|
||||
busybox-static \
|
||||
gcc \
|
||||
qemu-kvm \
|
||||
libvirt-daemon-system
|
||||
|
||||
RUN add-apt-repository ppa:gns3/ppa && apt update && DEBIAN_FRONTEND=noninteractive apt install -y \
|
||||
vpcs \
|
||||
ubridge \
|
||||
dynamips
|
||||
|
||||
COPY . /gns3server
|
||||
|
||||
RUN mkdir -p ~/.config/GNS3/3.0/
|
||||
RUN cp scripts/gns3_server.conf ~/.config/GNS3/3.0/
|
||||
|
||||
RUN python3 setup.py install
|
||||
|
@ -58,6 +58,7 @@ GNS3 is perhaps packaged for your distribution:
|
||||
|
||||
* Gentoo: https://packages.gentoo.org/package/net-misc/gns3-server
|
||||
* Alpine: https://pkgs.alpinelinux.org/package/v3.10/community/x86_64/gns3-server
|
||||
* NixOS: https://search.nixos.org/packages?channel=21.11&from=0&size=50&sort=relevance&type=packages&query=gns3-server
|
||||
|
||||
|
||||
Linux (Debian based)
|
||||
|
@ -1,3 +1,18 @@
|
||||
[Controller]
|
||||
|
||||
; Options for JWT tokens (user authentication)
|
||||
jwt_secret_key = efd08eccec3bd0a1be2e086670e5efa90969c68d07e072d7354a76cea5e33d4e
|
||||
jwt_algorithm = HS256
|
||||
jwt_access_token_expire_minutes = 1440
|
||||
|
||||
; Initial default super admin username
|
||||
; It cannot be changed once the controller has started once
|
||||
default_admin_username = admin
|
||||
|
||||
; Initial default super admin password
|
||||
; It cannot be changed once the controller has started once
|
||||
default_admin_password = admin
|
||||
|
||||
[Server]
|
||||
|
||||
; What protocol the server uses (http or https)
|
||||
@ -57,20 +72,10 @@ udp_end_port_range = 30000
|
||||
; uBridge executable location, default: search in PATH
|
||||
;ubridge_path = ubridge
|
||||
|
||||
; Option to enable HTTP authentication.
|
||||
enable_http_auth = False
|
||||
; Username for HTTP authentication.
|
||||
user = gns3
|
||||
; Password for HTTP authentication.
|
||||
password = gns3
|
||||
|
||||
; Initial default super admin username
|
||||
; It cannot be changed once the server has started once
|
||||
default_admin_username = "admin"
|
||||
|
||||
; Initial default super admin password
|
||||
; It cannot be changed once the server has started once
|
||||
default_admin_password = "admin"
|
||||
; Username for compute HTTP authentication.
|
||||
compute_username = gns3
|
||||
; Password for compute HTTP authentication.
|
||||
compute_password = gns3
|
||||
|
||||
; Only allow these interfaces to be used by GNS3, for the Cloud node for example (Linux/OSX only)
|
||||
; Do not forget to allow virbr0 in order for the NAT node to work
|
||||
@ -80,12 +85,6 @@ allowed_interfaces = eth0,eth1,virbr0
|
||||
; Default is virbr0 on Linux (requires libvirt) and vmnet8 for other platforms (requires VMware)
|
||||
default_nat_interface = vmnet10
|
||||
|
||||
[Controller]
|
||||
; Options for JWT tokens (user authentication)
|
||||
jwt_secret_key = efd08eccec3bd0a1be2e086670e5efa90969c68d07e072d7354a76cea5e33d4e
|
||||
jwt_algorithm = HS256
|
||||
jwt_access_token_expire_minutes = 1440
|
||||
|
||||
[VPCS]
|
||||
; VPCS executable location, default: search in PATH
|
||||
;vpcs_path = vpcs
|
||||
|
@ -1,8 +1,8 @@
|
||||
-r requirements.txt
|
||||
|
||||
pytest==6.2.4
|
||||
flake8==3.9.2
|
||||
pytest-timeout==1.4.2
|
||||
pytest-asyncio==0.15.1
|
||||
pytest==6.2.5
|
||||
flake8==4.0.1
|
||||
pytest-timeout==2.0.1
|
||||
pytest-asyncio==0.16.0
|
||||
requests==2.26.0
|
||||
httpx==0.18.2
|
||||
httpx==0.21.1
|
||||
|
@ -15,13 +15,15 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi import FastAPI, Request, Depends
|
||||
from fastapi.responses import JSONResponse
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
from gns3server.controller.gns3vm.gns3_vm_error import GNS3VMError
|
||||
from gns3server.compute.error import ImageMissingError, NodeError
|
||||
from gns3server.compute.ubridge.ubridge_error import UbridgeError
|
||||
|
||||
from .dependencies.authentication import compute_authentication
|
||||
|
||||
from gns3server.compute.compute_error import (
|
||||
ComputeError,
|
||||
ComputeNotFoundError,
|
||||
@ -49,13 +51,15 @@ from . import virtualbox_nodes
|
||||
from . import vmware_nodes
|
||||
from . import vpcs_nodes
|
||||
|
||||
|
||||
compute_api = FastAPI(
|
||||
title="GNS3 compute API",
|
||||
dependencies=[Depends(compute_authentication)],
|
||||
description="This page describes the private compute API for GNS3. PLEASE DO NOT USE DIRECTLY!",
|
||||
version="v3",
|
||||
)
|
||||
|
||||
compute_api.state.controller_host = None
|
||||
|
||||
|
||||
@compute_api.exception_handler(ComputeError)
|
||||
async def controller_error_handler(request: Request, exc: ComputeError):
|
||||
|
@ -21,7 +21,7 @@ API routes for capabilities
|
||||
import sys
|
||||
import psutil
|
||||
|
||||
from fastapi import APIRouter
|
||||
from fastapi import APIRouter, Request
|
||||
|
||||
from gns3server.version import __version__
|
||||
from gns3server.compute import MODULES
|
||||
@ -32,12 +32,15 @@ router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/capabilities", response_model=schemas.Capabilities)
|
||||
def get_capabilities() -> dict:
|
||||
def get_capabilities(request: Request) -> dict:
|
||||
|
||||
node_types = []
|
||||
for module in MODULES:
|
||||
node_types.extend(module.node_types())
|
||||
|
||||
# record the controller hostname or IP address
|
||||
request.app.state.controller_host = request.client.host
|
||||
|
||||
return {
|
||||
"version": __version__,
|
||||
"platform": sys.platform,
|
||||
|
37
gns3server/api/routes/compute/dependencies/authentication.py
Normal file
37
gns3server/api/routes/compute/dependencies/authentication.py
Normal file
@ -0,0 +1,37 @@
|
||||
#
|
||||
# Copyright (C) 2021 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import secrets
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
from gns3server.config import Config
|
||||
from typing import Optional
|
||||
|
||||
security = HTTPBasic()
|
||||
|
||||
|
||||
def compute_authentication(credentials: Optional[HTTPBasicCredentials] = Depends(security)) -> None:
|
||||
|
||||
server_settings = Config.instance().settings.Server
|
||||
username = secrets.compare_digest(credentials.username, server_settings.compute_username)
|
||||
password = secrets.compare_digest(credentials.password, server_settings.compute_password.get_secret_value())
|
||||
if not (username and password):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid compute username or password",
|
||||
headers={"WWW-Authenticate": "Basic"},
|
||||
)
|
@ -18,7 +18,11 @@
|
||||
API routes for compute notifications.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
|
||||
import base64
|
||||
import binascii
|
||||
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, status, HTTPException
|
||||
from fastapi.security.utils import get_authorization_scheme_param
|
||||
from websockets.exceptions import ConnectionClosed, WebSocketException
|
||||
|
||||
from gns3server.compute.notification_manager import NotificationManager
|
||||
@ -37,6 +41,32 @@ async def notification_ws(websocket: WebSocket) -> None:
|
||||
"""
|
||||
|
||||
await websocket.accept()
|
||||
|
||||
# handle basic HTTP authentication
|
||||
invalid_user_credentials_exc = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid authentication credentials",
|
||||
headers={"WWW-Authenticate": "Basic"},
|
||||
)
|
||||
|
||||
try:
|
||||
authorization = websocket.headers.get("Authorization")
|
||||
scheme, param = get_authorization_scheme_param(authorization)
|
||||
if not authorization or scheme.lower() != "basic":
|
||||
raise invalid_user_credentials_exc
|
||||
try:
|
||||
data = base64.b64decode(param).decode("ascii")
|
||||
except (ValueError, UnicodeDecodeError, binascii.Error):
|
||||
raise invalid_user_credentials_exc
|
||||
username, separator, password = data.partition(":")
|
||||
if not separator:
|
||||
raise invalid_user_credentials_exc
|
||||
except invalid_user_credentials_exc as e:
|
||||
websocket_error = {"action": "log.error", "event": {"message": f"Could not authenticate while connecting to "
|
||||
f"compute WebSocket: {e.detail}"}}
|
||||
await websocket.send_json(websocket_error)
|
||||
return await websocket.close(code=1008)
|
||||
|
||||
log.info(f"New client {websocket.client.host}:{websocket.client.port} has connected to compute WebSocket")
|
||||
try:
|
||||
with NotificationManager.instance().queue() as queue:
|
||||
@ -48,8 +78,10 @@ async def notification_ws(websocket: WebSocket) -> None:
|
||||
except WebSocketException as e:
|
||||
log.warning(f"Error while sending to controller event to WebSocket client: {e}")
|
||||
finally:
|
||||
await websocket.close()
|
||||
|
||||
try:
|
||||
await websocket.close()
|
||||
except OSError:
|
||||
pass # ignore OSError: [Errno 107] Transport endpoint is not connected
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
@ -19,7 +19,7 @@ API routes for computes.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, Response, status
|
||||
from typing import List, Union
|
||||
from typing import List, Union, Optional
|
||||
from uuid import UUID
|
||||
|
||||
from gns3server.controller import Controller
|
||||
@ -47,12 +47,25 @@ router = APIRouter(responses=responses)
|
||||
async def create_compute(
|
||||
compute_create: schemas.ComputeCreate,
|
||||
computes_repo: ComputesRepository = Depends(get_repository(ComputesRepository)),
|
||||
connect: Optional[bool] = False
|
||||
) -> schemas.Compute:
|
||||
"""
|
||||
Create a new compute on the controller.
|
||||
"""
|
||||
|
||||
return await ComputesService(computes_repo).create_compute(compute_create)
|
||||
return await ComputesService(computes_repo).create_compute(compute_create, connect)
|
||||
|
||||
|
||||
@router.post("/{compute_id}/connect", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def connect_compute(compute_id: Union[str, UUID]) -> Response:
|
||||
"""
|
||||
Connect to compute on the controller.
|
||||
"""
|
||||
|
||||
compute = Controller.instance().get_compute(str(compute_id))
|
||||
if not compute.connected:
|
||||
await compute.connect(report_failed_connection=True)
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
@router.get("/{compute_id}", response_model=schemas.Compute, response_model_exclude_unset=True)
|
||||
|
@ -18,8 +18,9 @@ import asyncio
|
||||
import signal
|
||||
import os
|
||||
|
||||
from fastapi import APIRouter, Depends, Response, status
|
||||
from fastapi import APIRouter, Depends, Request, Response, status
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from fastapi.routing import Mount
|
||||
from typing import List
|
||||
|
||||
from gns3server.config import Config
|
||||
@ -41,13 +42,24 @@ router = APIRouter()
|
||||
"/version",
|
||||
response_model=schemas.Version,
|
||||
)
|
||||
def get_version() -> dict:
|
||||
def get_version(request: Request) -> dict:
|
||||
"""
|
||||
Return the server version number.
|
||||
"""
|
||||
|
||||
# retrieve the controller host information from the mounted
|
||||
# compute subapp
|
||||
controller_host = None
|
||||
for route in request.app.routes:
|
||||
if isinstance(route, Mount) and route.name == "compute":
|
||||
controller_host = route.app.state.controller_host
|
||||
|
||||
local_server = Config.instance().settings.Server.local
|
||||
return {"version": __version__, "local": local_server}
|
||||
return {
|
||||
"controller_host": controller_host,
|
||||
"version": __version__,
|
||||
"local": local_server
|
||||
}
|
||||
|
||||
|
||||
@router.post(
|
||||
@ -61,7 +73,6 @@ def check_version(version: schemas.Version) -> dict:
|
||||
Check if version is the same as the server.
|
||||
"""
|
||||
|
||||
print(version.version)
|
||||
if version.version != __version__:
|
||||
raise ControllerError(f"Client version {version.version} is not the same as server version {__version__}")
|
||||
return {"version": __version__}
|
||||
|
@ -16,8 +16,9 @@
|
||||
|
||||
import re
|
||||
|
||||
from fastapi import Request, Depends, HTTPException, status
|
||||
from fastapi import Request, Query, Depends, HTTPException, WebSocket, status
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from typing import Optional
|
||||
|
||||
from gns3server import schemas
|
||||
from gns3server.db.repositories.users import UsersRepository
|
||||
@ -76,3 +77,53 @@ async def get_current_active_user(
|
||||
)
|
||||
|
||||
return current_user
|
||||
|
||||
|
||||
async def get_current_active_user_from_websocket(
|
||||
websocket: WebSocket,
|
||||
token: str = Query(...),
|
||||
user_repo: UsersRepository = Depends(get_repository(UsersRepository)),
|
||||
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository))
|
||||
) -> Optional[schemas.User]:
|
||||
|
||||
await websocket.accept()
|
||||
|
||||
try:
|
||||
username = auth_service.get_username_from_token(token)
|
||||
user = await user_repo.get_user_by_username(username)
|
||||
|
||||
if user is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail=f"Could not validate credentials for '{username}'"
|
||||
)
|
||||
|
||||
# Super admin is always authorized
|
||||
if user.is_superadmin:
|
||||
return user
|
||||
|
||||
if not user.is_active:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail=f"'{username}' is not an active user"
|
||||
)
|
||||
|
||||
# remove the prefix (e.g. "/v3") from URL path
|
||||
path = re.sub(r"^/v[0-9]", "", websocket.url.path)
|
||||
|
||||
# there are no HTTP methods for web sockets, assuming "GET"...
|
||||
authorized = await rbac_repo.check_user_is_authorized(user.user_id, "GET", path)
|
||||
if not authorized:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail=f"User is not authorized '{user.user_id}' on '{path}'",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
return user
|
||||
|
||||
except HTTPException as e:
|
||||
websocket_error = {"action": "log.error", "event": {"message": f"Could not authenticate while connecting to "
|
||||
f"WebSocket: {e.detail}"}}
|
||||
await websocket.send_json(websocket_error)
|
||||
await websocket.close(code=1008)
|
||||
|
@ -15,13 +15,14 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Callable, Type
|
||||
from fastapi import Depends, Request
|
||||
from fastapi import Depends
|
||||
from starlette.requests import HTTPConnection
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from gns3server.db.repositories.base import BaseRepository
|
||||
|
||||
|
||||
async def get_db_session(request: Request) -> AsyncSession:
|
||||
async def get_db_session(request: HTTPConnection) -> AsyncSession:
|
||||
|
||||
session = AsyncSession(request.app.state._db_engine, expire_on_commit=False)
|
||||
try:
|
||||
|
@ -67,7 +67,7 @@ async def upload_image(
|
||||
templates_repo: TemplatesRepository = Depends(get_repository(TemplatesRepository)),
|
||||
current_user: schemas.User = Depends(get_current_active_user),
|
||||
rbac_repo: RbacRepository = Depends(get_repository(RbacRepository)),
|
||||
install_appliances: Optional[bool] = True
|
||||
install_appliances: Optional[bool] = False
|
||||
) -> schemas.Image:
|
||||
"""
|
||||
Upload an image.
|
||||
|
@ -198,7 +198,14 @@ async def stream_pcap(request: Request, link: Link = Depends(dep_link)) -> Strea
|
||||
async def compute_pcap_stream():
|
||||
|
||||
try:
|
||||
async with HTTPClient.request(request.method, pcap_streaming_url, timeout=None, data=body) as response:
|
||||
async with HTTPClient.request(
|
||||
request.method,
|
||||
pcap_streaming_url,
|
||||
user=compute.user,
|
||||
password=compute.password,
|
||||
timeout=None,
|
||||
data=body
|
||||
) as response:
|
||||
async for data in response.content.iter_any():
|
||||
if not data:
|
||||
break
|
||||
|
@ -18,14 +18,14 @@
|
||||
API routes for controller notifications.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, Query, WebSocket, WebSocketDisconnect, HTTPException
|
||||
from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect
|
||||
from fastapi.responses import StreamingResponse
|
||||
from websockets.exceptions import ConnectionClosed, WebSocketException
|
||||
|
||||
from gns3server.services import auth_service
|
||||
from gns3server.controller import Controller
|
||||
from gns3server import schemas
|
||||
|
||||
from .dependencies.authentication import get_current_active_user
|
||||
from .dependencies.authentication import get_current_active_user, get_current_active_user_from_websocket
|
||||
|
||||
import logging
|
||||
|
||||
@ -35,7 +35,7 @@ router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", dependencies=[Depends(get_current_active_user)])
|
||||
async def http_notification() -> StreamingResponse:
|
||||
async def controller_http_notifications() -> StreamingResponse:
|
||||
"""
|
||||
Receive controller notifications about the controller from HTTP stream.
|
||||
"""
|
||||
@ -50,19 +50,16 @@ async def http_notification() -> StreamingResponse:
|
||||
|
||||
|
||||
@router.websocket("/ws")
|
||||
async def notification_ws(websocket: WebSocket, token: str = Query(None)) -> None:
|
||||
async def controller_ws_notifications(
|
||||
websocket: WebSocket,
|
||||
current_user: schemas.User = Depends(get_current_active_user_from_websocket)
|
||||
) -> None:
|
||||
"""
|
||||
Receive project notifications about the controller from WebSocket.
|
||||
"""
|
||||
await websocket.accept()
|
||||
|
||||
if token:
|
||||
try:
|
||||
username = auth_service.get_username_from_token(token)
|
||||
except HTTPException:
|
||||
log.error("Invalid token received")
|
||||
await websocket.close(code=1008)
|
||||
return
|
||||
if current_user is None:
|
||||
return
|
||||
|
||||
log.info(f"New client {websocket.client.host}:{websocket.client.port} has connected to controller WebSocket")
|
||||
try:
|
||||
@ -75,4 +72,7 @@ async def notification_ws(websocket: WebSocket, token: str = Query(None)) -> Non
|
||||
except WebSocketException as e:
|
||||
log.warning(f"Error while sending to controller event to WebSocket client: {e}")
|
||||
finally:
|
||||
await websocket.close()
|
||||
try:
|
||||
await websocket.close()
|
||||
except OSError:
|
||||
pass # ignore OSError: [Errno 107] Transport endpoint is not connected
|
||||
|
@ -51,7 +51,7 @@ from gns3server.db.repositories.rbac import RbacRepository
|
||||
from gns3server.db.repositories.templates import TemplatesRepository
|
||||
from gns3server.services.templates import TemplatesService
|
||||
|
||||
from .dependencies.authentication import get_current_active_user
|
||||
from .dependencies.authentication import get_current_active_user, get_current_active_user_from_websocket
|
||||
from .dependencies.database import get_repository
|
||||
|
||||
responses = {404: {"model": schemas.ErrorMessage, "description": "Could not find project"}}
|
||||
@ -204,17 +204,12 @@ async def load_project(path: str = Body(..., embed=True)) -> schemas.Project:
|
||||
|
||||
controller = Controller.instance()
|
||||
dot_gns3_file = path
|
||||
if Config.instance().settings.Server.local is False:
|
||||
log.error(f"Cannot load '{dot_gns3_file}' because the server has not been started with the '--local' parameter")
|
||||
raise ControllerForbiddenError("Cannot load project when server is not local")
|
||||
project = await controller.load_project(
|
||||
dot_gns3_file,
|
||||
)
|
||||
project = await controller.load_project(dot_gns3_file)
|
||||
return project.asdict()
|
||||
|
||||
|
||||
@router.get("/{project_id}/notifications")
|
||||
async def notification(project_id: UUID) -> StreamingResponse:
|
||||
async def project_http_notifications(project_id: UUID) -> StreamingResponse:
|
||||
"""
|
||||
Receive project notifications about the controller from HTTP stream.
|
||||
"""
|
||||
@ -245,14 +240,20 @@ async def notification(project_id: UUID) -> StreamingResponse:
|
||||
|
||||
|
||||
@router.websocket("/{project_id}/notifications/ws")
|
||||
async def notification_ws(project_id: UUID, websocket: WebSocket) -> None:
|
||||
async def project_ws_notifications(
|
||||
project_id: UUID,
|
||||
websocket: WebSocket,
|
||||
current_user: schemas.User = Depends(get_current_active_user_from_websocket)
|
||||
) -> None:
|
||||
"""
|
||||
Receive project notifications about the controller from WebSocket.
|
||||
"""
|
||||
|
||||
if current_user is None:
|
||||
return
|
||||
|
||||
controller = Controller.instance()
|
||||
project = controller.get_project(str(project_id))
|
||||
await websocket.accept()
|
||||
|
||||
log.info(f"New client has connected to the notification stream for project ID '{project.id}' (WebSocket method)")
|
||||
try:
|
||||
@ -265,7 +266,10 @@ async def notification_ws(project_id: UUID, websocket: WebSocket) -> None:
|
||||
except WebSocketException as e:
|
||||
log.warning(f"Error while sending to project event to WebSocket client: {e}")
|
||||
finally:
|
||||
await websocket.close()
|
||||
try:
|
||||
await websocket.close()
|
||||
except OSError:
|
||||
pass # ignore OSError: [Errno 107] Transport endpoint is not connected
|
||||
if project.auto_close:
|
||||
# To avoid trouble with client connecting disconnecting we sleep few seconds before checking
|
||||
# if someone else is not connected
|
||||
|
@ -21,8 +21,7 @@ FastAPI app
|
||||
|
||||
import time
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
from fastapi import FastAPI, Request, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
@ -53,22 +52,9 @@ def get_application() -> FastAPI:
|
||||
title="GNS3 controller API", description="This page describes the public controller API for GNS3", version="v3"
|
||||
)
|
||||
|
||||
origins = [
|
||||
"http://127.0.0.1",
|
||||
"http://localhost",
|
||||
"http://localhost:4200",
|
||||
"http://127.0.0.1:4200"
|
||||
"http://127.0.0.1:8080",
|
||||
"http://localhost:8080",
|
||||
"http://127.0.0.1:3080",
|
||||
"http://localhost:3080",
|
||||
"http://gns3.github.io",
|
||||
"https://gns3.github.io",
|
||||
]
|
||||
|
||||
application.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_origin_regex=r"http(s)?://(localhost|127.0.0.1)(:\d+)?",
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
@ -78,7 +64,7 @@ def get_application() -> FastAPI:
|
||||
application.add_event_handler("shutdown", tasks.create_shutdown_handler(application))
|
||||
application.include_router(index.router, tags=["Index"])
|
||||
application.include_router(controller.router, prefix="/v3")
|
||||
application.mount("/v3/compute", compute_api)
|
||||
application.mount("/v3/compute", compute_api, name="compute")
|
||||
|
||||
return application
|
||||
|
||||
@ -153,11 +139,12 @@ async def controller_bad_request_error_handler(request: Request, exc: Controller
|
||||
|
||||
|
||||
# make sure the content key is "message", not "detail" per default
|
||||
@app.exception_handler(StarletteHTTPException)
|
||||
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
|
||||
@app.exception_handler(HTTPException)
|
||||
async def http_exception_handler(request: Request, exc: HTTPException):
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content={"message": exc.detail},
|
||||
headers=exc.headers
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,68 +0,0 @@
|
||||
{
|
||||
"appliance_id": "2def5797-cb7d-429e-b85e-497ff4b81547",
|
||||
"name": "ParrotOS",
|
||||
"category": "guest",
|
||||
"description": " Parrot is a GNU/Linux distribution based on Debian Testing and designed with Security, Development and Privacy in mind. It includes a full portable laboratory for security and digital forensics experts, but it also includes all you need to develop your own software or protect your privacy while surfing the net.",
|
||||
"vendor_name": "Parrot Project",
|
||||
"vendor_url": "https://parrotsec.org/",
|
||||
"documentation_url": "https://docs.parrotsec.org/doku.php",
|
||||
"product_name": "ParrotOS",
|
||||
"product_url": "https://parrotsec.org/",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "Brent Stewart",
|
||||
"maintainer_email": "brent@stewart.tc",
|
||||
"usage": "Passwords are set during installation.",
|
||||
"symbol": "parrotlogo.png",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
"ram": 2048,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "Parrot-security-4.6_amd64.iso",
|
||||
"version": "Security Build 4.6",
|
||||
"md5sum": "ead812edc83119e8bcb4ee9daabdc105",
|
||||
"filesize": 3788668928,
|
||||
"download_url": "https://www.parrotsec.org/download-security.php",
|
||||
"direct_download_url": "https://download.parrotsec.org/parrot/iso/4.6/Parrot-security-4.6_amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "Parrot-security-3.11_amd64.iso",
|
||||
"version": "Security Build 3.11",
|
||||
"md5sum": "71c94474fb474f682da0844d95f0040b",
|
||||
"filesize": 3788668928,
|
||||
"download_url": "https://www.parrotsec.org/download.fx",
|
||||
"direct_download_url": "https://www.parrotsec.org/download-full.fx"
|
||||
},
|
||||
{
|
||||
"filename": "empty30G.qcow2",
|
||||
"version": "1.0",
|
||||
"md5sum": "3411a599e822f2ac6be560a26405821a",
|
||||
"filesize": 197120,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%30disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty30G.qcow2/download"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "Security Build 4.6",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "Parrot-security-4.6_amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Security Build 3.11",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2",
|
||||
"cdrom_image": "Parrot-security-3.11_amd64.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
52
gns3server/appliances/almalinux.gns3a
Normal file
52
gns3server/appliances/almalinux.gns3a
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"appliance_id": "5c09a704-0e38-48ac-8392-52e0c5890cf3",
|
||||
"name": "AlmaLinux",
|
||||
"category": "guest",
|
||||
"description": "An Open Source, community-governed and forever-free enterprise Linux distribution, focused on long-term stability, providing a robust production-grade platform. AlmaLinux OS is 1:1 binary compatible with RHEL and pre-Stream CentOS.",
|
||||
"vendor_name": "Alma Linux",
|
||||
"vendor_url": "https://almalinux.org/",
|
||||
"documentation_url": "https://wiki.almalinux.org/",
|
||||
"product_name": "Alma Linux",
|
||||
"product_url": "https://almalinux.org/",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"maintainer": "Da-Geek",
|
||||
"maintainer_email": "dageek@dageeks-geeks.gg",
|
||||
"usage": "Username:\talmalinux\nPassword:\talmalinux\nTo become root, use \"sudo -i\".\n",
|
||||
"port_name_format": "eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 1536,
|
||||
"hda_disk_interface": "sata",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "AlmaLinux-8-GenericCloud-8.5-20211119.x86_64.qcow2",
|
||||
"version": "8.5",
|
||||
"md5sum": "a64ece809ae06180ac59cfa622d98af0",
|
||||
"filesize": 561774592,
|
||||
"download_url": "https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/",
|
||||
"direct_download_url": "https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/AlmaLinux-8-GenericCloud-8.5-20211119.x86_64.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "almalinux-cloud-init-data.iso",
|
||||
"version": "1.0",
|
||||
"md5sum": "72fb52af76e9561d125dd99224e2c1d1",
|
||||
"filesize": 374784,
|
||||
"download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/AlmaLinux/almalinux-cloud-init-data.iso"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.5",
|
||||
"images": {
|
||||
"hda_disk_image": "AlmaLinux-8-GenericCloud-8.5-20211119.x86_64.qcow2",
|
||||
"cdrom_image": "almalinux-cloud-init-data.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
"availability": "service-contract",
|
||||
"maintainer": "Aruba",
|
||||
"maintainer_email": "vincent.giles@hpe.com",
|
||||
"usage": "Default username admin has to be set at first login.",
|
||||
"usage": "Default username: admin, no password. New Password has to be set at first login.",
|
||||
"symbol": ":/symbols/route_switch_processor.svg",
|
||||
"first_port_name": "mgmt",
|
||||
"port_name_format": "1/1/{port1}",
|
||||
@ -30,6 +30,34 @@
|
||||
"process_priority": "normal"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "arubaoscx-disk-image-genericx86-p4-20211206170615.vmdk",
|
||||
"version": "10.09.0002",
|
||||
"md5sum": "3c772546482013495e31fc9cb0591b46",
|
||||
"filesize": 555656704,
|
||||
"download_url": "https://asp.arubanetworks.com/"
|
||||
},
|
||||
{
|
||||
"filename": "arubaoscx-disk-image-genericx86-p4-20210812172945.vmdk",
|
||||
"version": "10.08.0001",
|
||||
"md5sum": "762b139432aef1012d8be5afdfcb286e",
|
||||
"filesize": 542237696,
|
||||
"download_url": "https://asp.arubanetworks.com/"
|
||||
},
|
||||
{
|
||||
"filename": "arubaoscx-disk-image-genericx86-p4-20210610000730.vmdk",
|
||||
"version": "10.07.0010",
|
||||
"md5sum": "396dc7ad964b7c517e01bc408e3bf84a",
|
||||
"filesize": 531603968,
|
||||
"download_url": "https://asp.arubanetworks.com/"
|
||||
},
|
||||
{
|
||||
"filename": "arubaoscx-disk-image-genericx86-p4-20210316185909.vmdk",
|
||||
"version": "10.06.0110",
|
||||
"md5sum": "f1ed67d5c7e009e21bfb6a91d9183e8e",
|
||||
"filesize": 381285376,
|
||||
"download_url": "https://asp.arubanetworks.com/"
|
||||
},
|
||||
{
|
||||
"filename": "arubaoscx-disk-image-genericx86-p4-20201110192651.vmdk",
|
||||
"version": "10.06.0001",
|
||||
@ -53,6 +81,30 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "10.09.0002",
|
||||
"images": {
|
||||
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20211206170615.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10.08.0001",
|
||||
"images": {
|
||||
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20210812172945.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10.07.0010",
|
||||
"images": {
|
||||
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20210610000730.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10.06.0110",
|
||||
"images": {
|
||||
"hda_disk_image": "arubaoscx-disk-image-genericx86-p4-20210316185909.vmdk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10.06.0001",
|
||||
"images": {
|
||||
|
@ -26,6 +26,13 @@
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "CentOS-7-x86_64-GenericCloud-2111.qcow2",
|
||||
"version": "7 (2111)",
|
||||
"md5sum": "730b8662695831670721c8245be61dac",
|
||||
"filesize": 897384448,
|
||||
"download_url": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2111.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "CentOS-7-x86_64-GenericCloud-1809.qcow2",
|
||||
"version": "7 (1809)",
|
||||
@ -33,6 +40,13 @@
|
||||
"filesize": 914948096,
|
||||
"download_url": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1809.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "CentOS-8-GenericCloud-8.4.2105-20210603.0.x86_64.qcow2",
|
||||
"version": "8.4 (2105)",
|
||||
"md5sum": "032eed270415526546eac07628905a62",
|
||||
"filesize": 1309652992,
|
||||
"download_url": "https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.4.2105-20210603.0.x86_64.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "centos-cloud-init-data.iso",
|
||||
"version": "1.0",
|
||||
@ -42,6 +56,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.4 (2105)",
|
||||
"images": {
|
||||
"hda_disk_image": "CentOS-8-GenericCloud-8.4.2105-20210603.0.x86_64.qcow2",
|
||||
"cdrom_image": "centos-cloud-init-data.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7 (2111)",
|
||||
"images": {
|
||||
"hda_disk_image": "CentOS-7-x86_64-GenericCloud-2111.qcow2",
|
||||
"cdrom_image": "centos-cloud-init-data.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "7 (1809)",
|
||||
"images": {
|
||||
|
46
gns3server/appliances/citrix-sd-wan.gns3a
Normal file
46
gns3server/appliances/citrix-sd-wan.gns3a
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"appliance_id": "2d5634dc-ad39-46cf-a2fd-17b291abab91",
|
||||
"name": "Citrix SD-WAN",
|
||||
"category": "router",
|
||||
"description": "A software-defined wide area network (SD-WAN) is a virtual WAN architecture, in which any blend of network transport types — not only multiprotocol label switching (MPLS) but also broadband internet, cellular, and satellite — can be virtualized and bonded then centrally managed in software, to securely connect users to applications and desktops in accordance with policy. Essentially, SD-WAN is software-defined networking (SDN) for the WAN.",
|
||||
"vendor_name": "Citrix",
|
||||
"vendor_url": "http://www.citrix.com/",
|
||||
"documentation_url": "https://docs.citrix.com/en-us/citrix-sd-wan",
|
||||
"product_name": "Citrix SD-WAN",
|
||||
"product_url": "https://docs.citrix.com/en-us/citrix-sd-wan",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"maintainer": "Kiel Czu",
|
||||
"maintainer_email": "kielczu@gmail.com",
|
||||
"usage": "The image file is large (3GB), make sure you have enough space. Default credentials: admin/ password",
|
||||
"port_name_format": "1/{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 4,
|
||||
"ram": 4096,
|
||||
"cpus": 4,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "cd",
|
||||
"kvm": "require",
|
||||
"options": "-cpu Nehalem"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ctx-sdw-os-11.4.1.27_kvm.qcow2",
|
||||
"version": "11.4.1.27",
|
||||
"md5sum": "e57d8fcf8c136cc3fd2359103d885462",
|
||||
"filesize": 3235315712,
|
||||
"download_url": "https://www.citrix.com/pl-pl/downloads/citrix-sd-wan/standard-premium-edition/vpx-release-114127.html"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "11.4.1.27",
|
||||
"images": {
|
||||
"hda_disk_image": "ctx-sdw-os-11.4.1.27_kvm.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
46
gns3server/appliances/citrix-sdwan-center.gns3a
Normal file
46
gns3server/appliances/citrix-sdwan-center.gns3a
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"appliance_id": "9021f581-a54d-48e0-bb84-8286ce6e08f0",
|
||||
"name": "Citrix SD-WAN Center",
|
||||
"category": "guest",
|
||||
"description": "Citrix SD-WAN Center is a centralized management system that enables you to configure, monitor, and analyze all the Citrix SD-WAN appliances on your WAN.",
|
||||
"vendor_name": "Citrix",
|
||||
"vendor_url": "http://www.citrix.com/",
|
||||
"documentation_url": "https://docs.citrix.com/en-us/citrix-sd-wan",
|
||||
"product_name": "Citrix SD-WAN Center",
|
||||
"product_url": "https://docs.citrix.com/en-us/citrix-sd-wan",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"maintainer": "Kiel Czu",
|
||||
"maintainer_email": "kielczu@gmail.com",
|
||||
"usage": "The image file is large (1.6 GB), make sure you have enough space. Default credentials: admin/ password",
|
||||
"port_name_format": "1/{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 4,
|
||||
"ram": 8192,
|
||||
"cpus": 4,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "cd",
|
||||
"kvm": "require",
|
||||
"options": "-smbios type=2,product='440BX Desktop Reference Platform'"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "ctx-sdwc-11.4.1.27.qcow2",
|
||||
"version": "11.4.1.27",
|
||||
"md5sum": "d788035384a53a7b73c853383efae49a",
|
||||
"filesize": 1661861888,
|
||||
"download_url": "https://www.citrix.com/pl-pl/downloads/citrix-sd-wan/citrix-sd-wan-standard-premium-advance-edition/management-console-release-114127.html"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "11.4.1.27",
|
||||
"images": {
|
||||
"hda_disk_image": "ctx-sdwc-11.4.1.27.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
66
gns3server/appliances/debian.gns3a
Normal file
66
gns3server/appliances/debian.gns3a
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
"appliance_id": "fb5797d0-512e-4ab2-a588-d4766a441000",
|
||||
"name": "Debian",
|
||||
"category": "guest",
|
||||
"description": "Debian is a GNU/Linux distribution composed of free and open-source software, developed by the community-supported Debian Project.",
|
||||
"vendor_name": "Debian",
|
||||
"vendor_url": "https://www.debian.org",
|
||||
"product_name": "Debian",
|
||||
"registry_version": 3,
|
||||
"status": "experimental",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Username:\tdebian\nPassword:\tdebian\nTo become root, use \"sudo -s\".\n\nNetwork configuration:\n- In \"/etc/network/interfaces\" comment out \"source-directory /run/network/interfaces.d\"\n- Remove \"/etc/network/interfaces.d/50-cloud-init\"\n- Create \"/etc/network/interfaces.d/10-ens4\", for example:\n\nauto ens4\n#iface ens4 inet dhcp\niface ens4 inet static\n address 10.1.1.100/24\n gateway 10.1.1.1\n dns-nameservers 10.1.1.1\n",
|
||||
"symbol": "linux_guest.svg",
|
||||
"port_name_format": "ens{port4}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 512,
|
||||
"hda_disk_interface": "scsi",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "debian-11-genericcloud-amd64-20211220-862.qcow2",
|
||||
"version": "11.2",
|
||||
"md5sum": "3bdc52b0b3622a72095efdd001780a45",
|
||||
"filesize": 253231104,
|
||||
"download_url": "https://cloud.debian.org/images/cloud/bullseye/",
|
||||
"direct_download_url": "https://cloud.debian.org/images/cloud/bullseye/20211220-862/debian-11-genericcloud-amd64-20211220-862.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "debian-10-genericcloud-amd64-20211011-792.qcow2",
|
||||
"version": "10.11",
|
||||
"md5sum": "ea4de19b17d114b6db813ee64a6b8284",
|
||||
"filesize": 232980480,
|
||||
"download_url": "https://cloud.debian.org/images/cloud/buster/",
|
||||
"direct_download_url": "https://cloud.debian.org/images/cloud/buster/20211011-792/debian-10-genericcloud-amd64-20211011-792.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "debian-cloud-init-data.iso",
|
||||
"version": "1.0",
|
||||
"md5sum": "43f6bf70c178a9d3c270b5c24971e578",
|
||||
"filesize": 374784,
|
||||
"download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/Debian/debian-cloud-init-data.iso"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "11.2",
|
||||
"images": {
|
||||
"hda_disk_image": "debian-11-genericcloud-amd64-20211220-862.qcow2",
|
||||
"cdrom_image": "debian-cloud-init-data.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "10.11",
|
||||
"images": {
|
||||
"hda_disk_image": "debian-10-genericcloud-amd64-20211011-792.qcow2",
|
||||
"cdrom_image": "debian-cloud-init-data.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
{
|
||||
"appliance_id": "8f8df56b-605d-447c-94a4-4848e3ae8392",
|
||||
"name": "Debian 10 Minimal",
|
||||
"category": "guest",
|
||||
"description": "Debian 10 Custom, with automatic disk resize and ssh/nmap",
|
||||
"vendor_name": "Debian",
|
||||
"vendor_url": "https://debian.org",
|
||||
"documentation_url": "https://wiki.debian.org",
|
||||
"product_name": "Debian",
|
||||
"product_url": "https://debian.org",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "Ramiro Magallanes",
|
||||
"maintainer_email": "ramiro@gnubit.com",
|
||||
"usage": "Username: root\nPassword: debian | MD5: 860d5051877bf4246eabc0bcb391b9a1",
|
||||
"port_name_format": "enp1s{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 2048,
|
||||
"hda_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"boot_priority": "c",
|
||||
"kvm": "require",
|
||||
"options": "-vga virtio"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "debian10-gns3.qcow2",
|
||||
"version": "10.2.0",
|
||||
"md5sum": "860d5051877bf4246eabc0bcb391b9a1",
|
||||
"filesize": 2685009920,
|
||||
"download_url": "https://downloads.gnubit.com/gns3-deb10-min/"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "10.2.0",
|
||||
"images": {
|
||||
"hda_disk_image": "debian10-gns3.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
53
gns3server/appliances/fedora-cloud.gns3a
Normal file
53
gns3server/appliances/fedora-cloud.gns3a
Normal file
@ -0,0 +1,53 @@
|
||||
{
|
||||
"appliance_id": "0d505121-14e3-4414-88ab-b7f102ea6176",
|
||||
"name": "Fedora Cloud Base",
|
||||
"category": "guest",
|
||||
"description": "Fedora Official image for self-hosted cloud",
|
||||
"vendor_name": "The Fedora Project",
|
||||
"vendor_url": "https://getfedora.org/",
|
||||
"documentation_url": "https://docs.fedoraproject.org/en-US/docs/",
|
||||
"product_name": "Fedora Cloud Base",
|
||||
"product_url": "https://alt.fedoraproject.org/cloud/",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "Da-Geek",
|
||||
"maintainer_email": "dageek@dageeks-geeks.gg",
|
||||
"usage": "Username: fedora\nPassword: fedora",
|
||||
"port_name_format": "Eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 1024,
|
||||
"hda_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "c",
|
||||
"kvm": "require",
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "Fedora-Cloud-Base-35-1.2.x86_64.qcow2",
|
||||
"version": "35-1.2",
|
||||
"md5sum": "cfa9cdcfb946e5f4cf9dd4d7906008d0",
|
||||
"filesize": 376897536,
|
||||
"download_url": "https://download.fedoraproject.org/pub/fedora/linux/releases/35/Cloud/x86_64/images/Fedora-Cloud-Base-35-1.2.x86_64.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "fedora-cloud-init-data.iso",
|
||||
"version": "1.0",
|
||||
"md5sum": "3d0d6391d3f5ece1180c70b9667c4dca",
|
||||
"filesize": 374784,
|
||||
"download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/fedora-cloud/fedora-cloud-init-data.iso"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "35-1.2",
|
||||
"images": {
|
||||
"hda_disk_image": "Fedora-Cloud-Base-35-1.2.x86_64.qcow2",
|
||||
"cdrom_image": "fedora-cloud-init-data.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
45
gns3server/appliances/lancom-vrouter.gns3a
Normal file
45
gns3server/appliances/lancom-vrouter.gns3a
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"appliance_id": "c83b42bb-7f8f-4273-94a5-395384898da4",
|
||||
"name": "LANCOM vRouter",
|
||||
"category": "router",
|
||||
"description": "\"The LANCOM vRouter is a software-based router for operation in virtualized environments [..]. With its comprehensive range of functions and the numerous security features based on the operating system LCOS, it offers the best basis for modern infrastructures. Be it as a virtual VPN router (vCPE), as central-site VPN gateway (vGateway), or as WLAN controller (vWLC), [..].\" quote from 'product_url'",
|
||||
"vendor_name": "LANCOM Systems GmbH",
|
||||
"vendor_url": "https://www.lancom-systems.com",
|
||||
"product_name": "vRouter",
|
||||
"product_url": "https://www.lancom-systems.com/products/routers-vpn-gateways/central-site-vpn-gateways/lancom-vrouter/",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"availability": "free-to-try",
|
||||
"maintainer": "hirnpfirsich",
|
||||
"maintainer_email": "hirnpfirsich@brainpeach.de",
|
||||
"usage": "The vRouter installs itself on first boot\nAfterwards set the root/administrative password via the console\nETH-0 is the LAN facing interface. If there is already an dhcp server on ETH-0 the vRouter requests an address. Otherwise it will run it's own dhcp server (172.23.56.254)\nConfigure via console/ssh(root@<ip>)/WebGUI(https://<ip>)/LANConfig/...",
|
||||
"port_name_format": "ETH-{port1}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 5,
|
||||
"ram": 1024,
|
||||
"hda_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "LANCOM-VROUTER-installer-10.50.0145-Rel.img",
|
||||
"version": "10.50.0145-Rel-KVM",
|
||||
"md5sum": "afa50e257d2703acb3ed3257962b2fb5",
|
||||
"filesize": 536870912,
|
||||
"download_url": "https://www.lancom-systems.de/downloads/",
|
||||
"direct_download_url": "https://www.lancom-systems.de/download/firmware/?id=fece9b54978e2af8f7a161798fff2a16&file=LC-vRouter/LC-vRouter-10.50.0145-Rel-img.zip",
|
||||
"compression": "zip"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "10.50.0145-Rel-KVM",
|
||||
"images": {
|
||||
"hda_disk_image": "LANCOM-VROUTER-installer-10.50.0145-Rel.img"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -28,200 +28,80 @@
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "chr-7.0beta8.img",
|
||||
"version": "7.0beta8",
|
||||
"md5sum": "dbc5b9a1d7cc0e56d5361a0e212dbd96",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/7.0beta8/chr-7.0beta8.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.47.img",
|
||||
"version": "6.47",
|
||||
"md5sum": "39dea5d6a58708eebfa73332456566f4",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.47/chr-6.47.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.46.5.img",
|
||||
"version": "6.46.5",
|
||||
"md5sum": "f9ea37f5a5ac3110f8f5de33e24a7749",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.46.5/chr-6.46.5.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.45.8.img",
|
||||
"version": "6.45.8",
|
||||
"md5sum": "73cc01e22e0b301dc29416f59ced8a7d",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.45.8/chr-6.45.8.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.45.6.img",
|
||||
"version": "6.45.6",
|
||||
"md5sum": "e68db699ba23ac7e4fba95b3075c1c6b",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.45.6/chr-6.45.6.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.44.5.img",
|
||||
"version": "6.44.5",
|
||||
"md5sum": "19aa21073c8ea4540daacde69bacda24",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.44.5/chr-6.44.5.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.44.3.img",
|
||||
"version": "6.44.3",
|
||||
"md5sum": "c46b33125d536faa24473a519abbb89d",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.44.3/chr-6.44.3.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.44.2.img",
|
||||
"version": "6.44.2",
|
||||
"md5sum": "f1ddaa47829e12c1f9f023d8c06b88cc",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.44.2/chr-6.44.2.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.44.img",
|
||||
"version": "6.44",
|
||||
"md5sum": "86fdf9f0093b4e8f9e7b1c8019fb37b5",
|
||||
"filesize": 33621035,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.44/chr-6.44.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.43.8.img",
|
||||
"version": "6.43.8",
|
||||
"md5sum": "9437133fc7e77779dc3ff62b98f30dc2",
|
||||
"filename": "chr-7.1rc7.img",
|
||||
"version": "7.1rc7",
|
||||
"md5sum": "04bc0ae1e5fbbda1522135bc57cf6560",
|
||||
"filesize": 134217728,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.43.8/chr-6.43.8.img.zip",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/7.1rc7/chr-7.1rc7.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.42.12.img",
|
||||
"version": "6.42.12",
|
||||
"md5sum": "8485c606eb38e629fb1f5356d31bbc86",
|
||||
"filesize": 45537201,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.42.12/chr-6.42.12.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.42.9.img",
|
||||
"version": "6.42.9",
|
||||
"md5sum": "1f856978cfc3ceb4b5e18e4e079f2e32",
|
||||
"filename": "chr-7.1.img",
|
||||
"version": "7.1",
|
||||
"md5sum": "41545bc7b55717fe5bb1e489ee39ca45",
|
||||
"filesize": 134217728,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.42.9/chr-6.42.9.img.zip",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/7.1/chr-7.1.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.42.img",
|
||||
"version": "6.42",
|
||||
"md5sum": "279bb518497b40f41c8585128916a2fb",
|
||||
"filesize": 134217728,
|
||||
"filename": "chr-6.49rc2.img",
|
||||
"version": "6.49rc2",
|
||||
"md5sum": "e1088f8f64ac3d6ecf2e56ac96261226",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.42/chr-6.42.img.zip",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.49rc2/chr-6.49rc2.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.49.1.img",
|
||||
"version": "6.49.1",
|
||||
"md5sum": "6c896c4c853de99f2ea77f0f4b102261",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.49.1/chr-6.49.1.img.zip",
|
||||
"compression": "zip"
|
||||
},
|
||||
{
|
||||
"filename": "chr-6.48.5.img",
|
||||
"version": "6.48.5",
|
||||
"md5sum": "d14debd4cd989f16f695b5b075960703",
|
||||
"filesize": 67108864,
|
||||
"download_url": "http://www.mikrotik.com/download",
|
||||
"direct_download_url": "https://download.mikrotik.com/routeros/6.48.5/chr-6.48.5.img.zip",
|
||||
"compression": "zip"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "7.0beta8",
|
||||
"name": "7.1rc7",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-7.0beta8.img"
|
||||
"hda_disk_image": "chr-7.1rc7.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.47",
|
||||
"name": "7.1",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.47.img"
|
||||
"hda_disk_image": "chr-7.1.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.46.5",
|
||||
"name": "6.49rc2",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.46.5.img"
|
||||
"hda_disk_image": "chr-6.49rc2.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.45.8",
|
||||
"name": "6.49.1",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.45.8.img"
|
||||
"hda_disk_image": "chr-6.49.1.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.45.6",
|
||||
"name": "6.48.5",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.45.6.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.44.5",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.44.5.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.44.3",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.44.3.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.44.2",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.44.2.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.44",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.44.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.43.8",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.43.8.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.42.12",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.42.12.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.42.9",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.42.9.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "6.42",
|
||||
"images": {
|
||||
"hda_disk_image": "chr-6.42.img"
|
||||
"hda_disk_image": "chr-6.48.5.img"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -23,6 +23,15 @@
|
||||
"kvm": "allow"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "openwrt-21.02.1-x86-64-generic-ext4-combined.img",
|
||||
"version": "21.02.1",
|
||||
"md5sum": "75896afa8f31bacc57fd84e7b5ff03b0",
|
||||
"filesize": 126353408,
|
||||
"download_url": "https://downloads.openwrt.org/releases/21.02.1/targets/x86/64/",
|
||||
"direct_download_url": "https://downloads.openwrt.org/releases/21.02.1/targets/x86/64/openwrt-21.02.1-x86-64-generic-ext4-combined.img.gz",
|
||||
"compression": "gzip"
|
||||
},
|
||||
{
|
||||
"filename": "openwrt-21.02.0-x86-64-generic-ext4-combined.img",
|
||||
"version": "21.02.0",
|
||||
@ -187,6 +196,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "21.02.1",
|
||||
"images": {
|
||||
"hda_disk_image": "openwrt-21.02.1-x86-64-generic-ext4-combined.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "21.02.0",
|
||||
"images": {
|
||||
|
@ -25,6 +25,13 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "OPNsense-21.7.1-OpenSSL-nano-amd64.img",
|
||||
"version": "21.7.1",
|
||||
"md5sum": "97f15ffec18202daec2485aa74593236",
|
||||
"filesize": 3221225472,
|
||||
"download_url": "https://opnsense.c0urier.net/releases/21.7/"
|
||||
},
|
||||
{
|
||||
"filename": "OPNsense-20.7-OpenSSL-nano-amd64.img",
|
||||
"version": "20.7",
|
||||
@ -41,6 +48,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "21.7.1",
|
||||
"images": {
|
||||
"hda_disk_image": "OPNsense-21.7.1-OpenSSL-nano-amd64.img"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.7",
|
||||
"images": {
|
||||
|
@ -24,6 +24,13 @@
|
||||
"process_priority": "normal"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "pfSense-CE-2.5.2-RELEASE-amd64.iso",
|
||||
"version": "2.5.2",
|
||||
"md5sum": "8c85a55f6ea0c33d6eba3fb9926c016b",
|
||||
"filesize": 651773952,
|
||||
"download_url": "https://www.pfsense.org/download/mirror.php?section=downloads"
|
||||
},
|
||||
{
|
||||
"filename": "pfSense-CE-2.4.5-RELEASE-p1-amd64.iso",
|
||||
"version": "2.4.5-p1",
|
||||
@ -55,6 +62,13 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "2.5.2",
|
||||
"images": {
|
||||
"hda_disk_image": "empty100G.qcow2",
|
||||
"cdrom_image": "pfSense-CE-2.5.2-RELEASE-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2.4.5-p1",
|
||||
"images": {
|
||||
|
@ -13,7 +13,7 @@
|
||||
"availability": "service-contract",
|
||||
"maintainer": "Neyder Achahuanco",
|
||||
"maintainer_email": "neyder@neyder.net",
|
||||
"usage": "You should download Red Hat Enterprise Linux KVM Guest Image from https://access.redhat.com/downloads/content/479/ver=/rhel---8/8.3/x86_64/product-software attach/customize cloud-init.iso and start.\nusername: cloud-user\npassword: redhat",
|
||||
"usage": "You should download Red Hat Enterprise Linux KVM Guest Image from https://access.redhat.com/downloads/content/479/ver=/rhel---8/8.5/x86_64/product-software attach/customize cloud-init.iso and start.\nusername: cloud-user\npassword: redhat",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
@ -26,6 +26,20 @@
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "rhel-8.5-x86_64-kvm.qcow2",
|
||||
"version": "8.5",
|
||||
"md5sum": "1efb78dbb2033ba4ac6589a06c95c2d4",
|
||||
"filesize": 779419648,
|
||||
"download_url": "https://access.redhat.com/downloads/content/479/ver=/rhel---8/8.5/x86_64/product-software"
|
||||
},
|
||||
{
|
||||
"filename": "rhel-8.4-x86_64-kvm.qcow2",
|
||||
"version": "8.4",
|
||||
"md5sum": "db4c3a72857b784dc6e96120351f2894",
|
||||
"filesize": 727449600,
|
||||
"download_url": "https://access.redhat.com/downloads/content/479/ver=/rhel---8/8.4/x86_64/product-software"
|
||||
},
|
||||
{
|
||||
"filename": "rhel-8.3-x86_64-kvm.qcow2",
|
||||
"version": "8.3",
|
||||
@ -56,6 +70,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.5",
|
||||
"images": {
|
||||
"hda_disk_image": "rhel-8.5-x86_64-kvm.qcow2",
|
||||
"cdrom_image": "rhel-cloud-init.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "8.4",
|
||||
"images": {
|
||||
"hda_disk_image": "rhel-8.4-x86_64-kvm.qcow2",
|
||||
"cdrom_image": "rhel-cloud-init.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "8.3",
|
||||
"images": {
|
||||
|
@ -7,39 +7,47 @@
|
||||
"vendor_url": "https://rockylinux.org",
|
||||
"documentation_url": "https://docs.rockylinux.org",
|
||||
"product_name": "Rocky Linux",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"maintainer": "Bernhard Ehlers",
|
||||
"maintainer_email": "none@b-ehlers.de",
|
||||
"usage": "Username:\trockylinux\nPassword:\trockylinux\nTo become root, use \"sudo su\".\n\nTo improve performance, increase RAM and vCPUs in the VM settings.",
|
||||
"registry_version": 3,
|
||||
"status": "stable",
|
||||
"maintainer": "Da-Geek",
|
||||
"maintainer_email": "dageek@dageeks-geeks.gg",
|
||||
"usage": "Username:\trocky\nPassword:\trocky\nTo become root, use \"sudo -i\".\n\nTo improve performance, increase RAM and vCPUs in the VM settings.",
|
||||
"symbol": "linux_guest.svg",
|
||||
"port_name_format": "ens{port4}",
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 1,
|
||||
"ram": 1536,
|
||||
"hda_disk_interface": "sata",
|
||||
"ram": 1024,
|
||||
"hda_disk_interface": "virtio",
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"console_type": "telnet",
|
||||
"boot_priority": "c",
|
||||
"kvm": "require",
|
||||
"options": "-usbdevice tablet"
|
||||
"options": "-nographic"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "RockyLinux_8.4_VMG_LinuxVMImages.COM.vmdk",
|
||||
"version": "8.4",
|
||||
"md5sum": "3452d5b0fbb4cdcf3ac6fe8de8d0ac08",
|
||||
"filesize": 5273878528,
|
||||
"download_url": "https://www.linuxvmimages.com/images/rockylinux-8",
|
||||
"direct_download_url": "https://sourceforge.net/projects/linuxvmimages/files/VMware/R/rockylinux/8/RockyLinux_8.4_VMM.7z/download",
|
||||
"compression": "7z"
|
||||
"filename": "Rocky-8-GenericCloud-8.5-20211114.2.x86_64.qcow2",
|
||||
"version": "8.5",
|
||||
"md5sum": "44982ddace75a1dba17942401086d72c",
|
||||
"filesize": 1502701568,
|
||||
"download_url": "https://download.rockylinux.org/pub/rocky/8/images/",
|
||||
"direct_download_url": "https://download.rockylinux.org/pub/rocky/8/images/Rocky-8-GenericCloud-8.5-20211114.2.x86_64.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "rocky-cloud-init-data.iso",
|
||||
"version": "1.0",
|
||||
"md5sum": "33ffda3a81436e305f37fb913edd6d43",
|
||||
"filesize": 374784,
|
||||
"download_url": "https://github.com/GNS3/gns3-registry/raw/master/cloud-init/rocky-cloud/rocky-cloud-init-data.iso"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.4",
|
||||
"name": "8.5",
|
||||
"images": {
|
||||
"hda_disk_image": "RockyLinux_8.4_VMG_LinuxVMImages.COM.vmdk"
|
||||
"hda_disk_image": "Rocky-8-GenericCloud-8.5-20211114.2.x86_64.qcow2",
|
||||
"cdrom_image": "rocky-cloud-init-data.iso"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -13,7 +13,7 @@
|
||||
"symbol": "linux_guest.svg",
|
||||
"docker": {
|
||||
"adapters": 1,
|
||||
"image": "gns3/ubuntu:xenial",
|
||||
"image": "gns3/ubuntu:focal",
|
||||
"console_type": "telnet"
|
||||
}
|
||||
}
|
||||
|
@ -27,12 +27,19 @@
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "vyos-1.3.0-epa1-amd64.iso",
|
||||
"version": "1.3.0-epa1",
|
||||
"md5sum": "a2aaa5bd3bc5827909d07a18a9de80a7",
|
||||
"filename": "vyos-1.3.0-amd64.iso",
|
||||
"version": "1.3.0",
|
||||
"md5sum": "2019bd9c5efa6194e2761de678d0073f",
|
||||
"filesize": 338690048,
|
||||
"download_url": "https://support.vyos.io/en/downloads/files/vyos-1-3-0-generic-iso-image"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.3.0-epa3-amd64.iso",
|
||||
"version": "1.3.0-epa3",
|
||||
"md5sum": "1b5de684d8995844e35fa5cec3171811",
|
||||
"filesize": 331350016,
|
||||
"download_url": "https://vyos.net/get/snapshots/",
|
||||
"direct_download_url": "https://s3.amazonaws.com/s3-us.vyos.io/snapshot/vyos-1.3.0-epa1/generic-iso/vyos-1.3.0-epa1-amd64.iso"
|
||||
"direct_download_url": "https://s3.amazonaws.com/s3-us.vyos.io/snapshot/vyos-1.3.0-epa3/vyos-1.3.0-epa3-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.2.8-amd64.iso",
|
||||
@ -67,10 +74,17 @@
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "1.3.0-epa1",
|
||||
"name": "1.3.0",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.3.0-epa1-amd64.iso"
|
||||
"cdrom_image": "vyos-1.3.0-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1.3.0-epa3",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "vyos-1.3.0-epa3-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -110,7 +110,7 @@ class Docker(BaseManager):
|
||||
body = await response.read()
|
||||
response.close()
|
||||
if body and len(body):
|
||||
if response.headers["CONTENT-TYPE"] == "application/json":
|
||||
if response.headers.get('CONTENT-TYPE') == 'application/json':
|
||||
body = json.loads(body.decode("utf-8"))
|
||||
else:
|
||||
body = body.decode("utf-8")
|
||||
|
@ -114,7 +114,7 @@ class DockerVM(BaseNode):
|
||||
self._extra_volumes = extra_volumes or []
|
||||
self._memory = memory
|
||||
self._cpus = cpus
|
||||
self._permissions_fixed = False
|
||||
self._permissions_fixed = True
|
||||
self._display = None
|
||||
self._closing = False
|
||||
|
||||
|
@ -21,6 +21,7 @@ import uuid
|
||||
import socket
|
||||
import shutil
|
||||
import asyncio
|
||||
import random
|
||||
|
||||
from ..config import Config
|
||||
from .project import Project
|
||||
@ -73,10 +74,6 @@ class Controller:
|
||||
if host == "0.0.0.0":
|
||||
host = "127.0.0.1"
|
||||
|
||||
name = socket.gethostname()
|
||||
if name == "gns3vm":
|
||||
name = "Main server"
|
||||
|
||||
self._load_controller_settings()
|
||||
|
||||
if server_config.enable_ssl:
|
||||
@ -92,15 +89,16 @@ class Controller:
|
||||
try:
|
||||
self._local_server = await self.add_compute(
|
||||
compute_id="local",
|
||||
name=name,
|
||||
name=f"{socket.gethostname()} (controller)",
|
||||
protocol=protocol,
|
||||
host=host,
|
||||
console_host=console_host,
|
||||
port=port,
|
||||
user=server_config.user,
|
||||
password=server_config.password,
|
||||
user=server_config.compute_username,
|
||||
password=server_config.compute_password,
|
||||
force=True,
|
||||
connect=True,
|
||||
wait_connection=False,
|
||||
ssl_context=self._ssl_context,
|
||||
)
|
||||
except ControllerError:
|
||||
@ -112,7 +110,12 @@ class Controller:
|
||||
if computes:
|
||||
for c in computes:
|
||||
try:
|
||||
await self.add_compute(**c, connect=False)
|
||||
#FIXME: Task exception was never retrieved
|
||||
await self.add_compute(
|
||||
compute_id=str(c.compute_id),
|
||||
connect=False,
|
||||
**c.dict(exclude_unset=True, exclude={"compute_id", "created_at", "updated_at"}),
|
||||
)
|
||||
except (ControllerError, KeyError):
|
||||
pass # Skip not available servers at loading
|
||||
|
||||
@ -154,8 +157,8 @@ class Controller:
|
||||
"""
|
||||
|
||||
if self._local_server:
|
||||
self._local_server.user = Config.instance().settings.Server.user
|
||||
self._local_server.password = Config.instance().settings.Server.password
|
||||
self._local_server.user = Config.instance().settings.Server.compute_username
|
||||
self._local_server.password = Config.instance().settings.Server.compute_password
|
||||
|
||||
async def stop(self):
|
||||
|
||||
@ -340,7 +343,7 @@ class Controller:
|
||||
os.makedirs(configs_path, exist_ok=True)
|
||||
return configs_path
|
||||
|
||||
async def add_compute(self, compute_id=None, name=None, force=False, connect=True, **kwargs):
|
||||
async def add_compute(self, compute_id=None, name=None, force=False, connect=True, wait_connection=True, **kwargs):
|
||||
"""
|
||||
Add a server to the dictionary of computes controlled by this controller
|
||||
|
||||
@ -370,8 +373,11 @@ class Controller:
|
||||
self._computes[compute.id] = compute
|
||||
# self.save()
|
||||
if connect:
|
||||
# call compute.connect() later to give time to the controller to be fully started
|
||||
asyncio.get_event_loop().call_later(1, lambda: asyncio.ensure_future(compute.connect()))
|
||||
if wait_connection:
|
||||
await compute.connect()
|
||||
else:
|
||||
# call compute.connect() later to give time to the controller to be fully started
|
||||
asyncio.get_event_loop().call_later(1, lambda: asyncio.ensure_future(compute.connect()))
|
||||
self.notification.controller_emit("compute.created", compute.asdict())
|
||||
return compute
|
||||
else:
|
||||
@ -439,6 +445,16 @@ class Controller:
|
||||
Returns a compute or raise a 404 error.
|
||||
"""
|
||||
|
||||
if compute_id is None:
|
||||
computes = list(self._computes.values())
|
||||
if len(computes) == 1:
|
||||
# return the only available compute
|
||||
return computes[0]
|
||||
else:
|
||||
# randomly pick a compute until we have proper scalability handling
|
||||
# https://github.com/GNS3/gns3-server/issues/1676
|
||||
return random.choice(computes)
|
||||
|
||||
try:
|
||||
return self._computes[compute_id]
|
||||
except KeyError:
|
||||
@ -508,6 +524,9 @@ class Controller:
|
||||
:param load: Load the topology
|
||||
"""
|
||||
|
||||
if not os.path.exists(path):
|
||||
raise ControllerError(f"'{path}' does not exist on the controller")
|
||||
|
||||
topo_data = load_topology(path)
|
||||
topo_data.pop("topology")
|
||||
topo_data.pop("version")
|
||||
@ -518,7 +537,10 @@ class Controller:
|
||||
project = self._projects[topo_data["project_id"]]
|
||||
else:
|
||||
project = await self.add_project(
|
||||
path=os.path.dirname(path), status="closed", filename=os.path.basename(path), **topo_data
|
||||
path=os.path.dirname(path),
|
||||
status="closed",
|
||||
filename=os.path.basename(path),
|
||||
**topo_data
|
||||
)
|
||||
if load or project.auto_open:
|
||||
await project.open()
|
||||
|
@ -119,6 +119,7 @@ class Compute:
|
||||
"""
|
||||
Set authentication parameters
|
||||
"""
|
||||
|
||||
if user is None or len(user.strip()) == 0:
|
||||
self._user = None
|
||||
self._password = None
|
||||
@ -153,6 +154,7 @@ class Compute:
|
||||
return self._interfaces_cache
|
||||
|
||||
async def update(self, **kwargs):
|
||||
|
||||
for kw in kwargs:
|
||||
if kw not in ("user", "password"):
|
||||
setattr(self, kw, kwargs[kw])
|
||||
@ -372,7 +374,7 @@ class Compute:
|
||||
pass
|
||||
|
||||
@locking
|
||||
async def connect(self):
|
||||
async def connect(self, report_failed_connection=False):
|
||||
"""
|
||||
Check if remote server is accessible
|
||||
"""
|
||||
@ -382,6 +384,8 @@ class Compute:
|
||||
log.info(f"Connecting to compute '{self._id}'")
|
||||
response = await self._run_http_query("GET", "/capabilities")
|
||||
except ComputeError as e:
|
||||
if report_failed_connection:
|
||||
raise
|
||||
log.warning(f"Cannot connect to compute '{self._id}': {e}")
|
||||
# Try to reconnect after 5 seconds if server unavailable only if not during tests (otherwise we create a ressource usage bomb)
|
||||
if not hasattr(sys, "_called_from_test") or not sys._called_from_test:
|
||||
@ -468,6 +472,8 @@ class Compute:
|
||||
# FIXME: slow down number of compute events
|
||||
self._controller.notification.controller_emit("compute.updated", self.asdict())
|
||||
else:
|
||||
if action == "log.error":
|
||||
log.error(event.pop("message"))
|
||||
await self._controller.notification.dispatch(
|
||||
action, event, project_id=project_id, compute_id=self.id
|
||||
)
|
||||
@ -488,7 +494,7 @@ class Compute:
|
||||
# Try to reconnect after 1 second if server unavailable only if not during tests (otherwise we create a ressources usage bomb)
|
||||
from gns3server.api.server import app
|
||||
if not app.state.exiting and not hasattr(sys, "_called_from_test"):
|
||||
log.info(f"Reconnecting to to compute '{self._id}' WebSocket '{ws_url}'")
|
||||
log.info(f"Reconnecting to compute '{self._id}' WebSocket '{ws_url}'")
|
||||
asyncio.get_event_loop().call_later(1, lambda: asyncio.ensure_future(self.connect()))
|
||||
|
||||
self._cpu_usage_percent = None
|
||||
@ -569,7 +575,7 @@ class Compute:
|
||||
msg = ""
|
||||
|
||||
if response.status == 401:
|
||||
raise ControllerUnauthorizedError(f"Invalid authentication for compute {self.id}")
|
||||
raise ControllerUnauthorizedError(f"Invalid authentication for compute '{self.name}' [{self.id}]")
|
||||
elif response.status == 403:
|
||||
raise ControllerForbiddenError(msg)
|
||||
elif response.status == 404:
|
||||
|
@ -183,7 +183,7 @@ class UDPLink(Link):
|
||||
self._capture_node = self._choose_capture_side()
|
||||
data = {"capture_file_name": capture_file_name, "data_link_type": data_link_type}
|
||||
await self._capture_node["node"].post(
|
||||
"/adapters/{adapter_number}/ports/{port_number}/start_capture".format(
|
||||
"/adapters/{adapter_number}/ports/{port_number}/capture/start".format(
|
||||
adapter_number=self._capture_node["adapter_number"], port_number=self._capture_node["port_number"]
|
||||
),
|
||||
data=data,
|
||||
@ -196,7 +196,7 @@ class UDPLink(Link):
|
||||
"""
|
||||
if self._capture_node:
|
||||
await self._capture_node["node"].post(
|
||||
"/adapters/{adapter_number}/ports/{port_number}/stop_capture".format(
|
||||
"/adapters/{adapter_number}/ports/{port_number}/capture/stop".format(
|
||||
adapter_number=self._capture_node["adapter_number"], port_number=self._capture_node["port_number"]
|
||||
)
|
||||
)
|
||||
|
@ -59,7 +59,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://959feb527c7441068b1bf80301b6e2c4:efa6d99da4c64faa8a7d929360765b40@o19455.ingest.sentry.io/38482"
|
||||
DSN = "https://8eb8a1f4730949f9886df2c6fdc27755:795f8ac399d04d24a273fcb35f48b725@o19455.ingest.sentry.io/38482"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
|
@ -57,6 +57,12 @@ def create_default_roles(target, connection, **kw):
|
||||
"path": "/",
|
||||
"action": "ALLOW"
|
||||
},
|
||||
{
|
||||
"description": "Allow to receive controller notifications",
|
||||
"methods": ["GET"],
|
||||
"path": "/notifications",
|
||||
"action": "ALLOW"
|
||||
},
|
||||
{
|
||||
"description": "Allow to create and list projects",
|
||||
"methods": ["GET", "POST"],
|
||||
@ -112,7 +118,7 @@ def add_permissions_to_role(target, connection, **kw):
|
||||
role_id = result.first().role_id
|
||||
|
||||
# add minimum required paths to the "User" role
|
||||
for path in ("/projects", "/templates", "/computes/*", "/symbols/*"):
|
||||
for path in ("/notifications", "/projects", "/templates", "/computes/*", "/symbols/*"):
|
||||
stmt = permissions_table.select().where(permissions_table.c.path == path)
|
||||
result = connection.execute(stmt)
|
||||
permission_id = result.first().permission_id
|
||||
|
@ -56,8 +56,8 @@ class User(BaseTable):
|
||||
def create_default_super_admin(target, connection, **kw):
|
||||
|
||||
config = Config.instance().settings
|
||||
default_admin_username = config.Server.default_admin_username
|
||||
default_admin_password = config.Server.default_admin_password.get_secret_value()
|
||||
default_admin_username = config.Controller.default_admin_username
|
||||
default_admin_password = config.Controller.default_admin_password.get_secret_value()
|
||||
hashed_password = auth_service.hash_password(default_admin_password)
|
||||
stmt = target.insert().values(
|
||||
username=default_admin_username,
|
||||
|
@ -52,18 +52,14 @@ class ComputesRepository(BaseRepository):
|
||||
|
||||
async def create_compute(self, compute_create: schemas.ComputeCreate) -> models.Compute:
|
||||
|
||||
password = compute_create.password
|
||||
if password:
|
||||
password = password.get_secret_value()
|
||||
|
||||
db_compute = models.Compute(
|
||||
compute_id=compute_create.compute_id,
|
||||
name=compute_create.name,
|
||||
protocol=compute_create.protocol.value,
|
||||
protocol=compute_create.protocol,
|
||||
host=compute_create.host,
|
||||
port=compute_create.port,
|
||||
user=compute_create.user,
|
||||
password=password,
|
||||
password=compute_create.password.get_secret_value(),
|
||||
)
|
||||
self._db_session.add(db_compute)
|
||||
await self._db_session.commit()
|
||||
|
@ -125,7 +125,7 @@ class UsersRepository(BaseRepository):
|
||||
|
||||
async def authenticate_user(self, username: str, password: str) -> Optional[models.User]:
|
||||
"""
|
||||
Authenticate an user.
|
||||
Authenticate user.
|
||||
"""
|
||||
|
||||
user = await self.get_user_by_username(username)
|
||||
|
@ -68,9 +68,7 @@ async def get_computes(app: FastAPI) -> List[dict]:
|
||||
db_computes = await ComputesRepository(db_session).get_computes()
|
||||
for db_compute in db_computes:
|
||||
try:
|
||||
compute = jsonable_encoder(
|
||||
schemas.Compute.from_orm(db_compute), exclude_unset=True, exclude={"created_at", "updated_at"}
|
||||
)
|
||||
compute = schemas.Compute.from_orm(db_compute)
|
||||
except ValidationError as e:
|
||||
log.error(f"Could not load compute '{db_compute.compute_id}' from database: {e}")
|
||||
continue
|
||||
|
@ -37,24 +37,31 @@ from .controller.iou_license import IOULicense
|
||||
from .controller.capabilities import Capabilities
|
||||
|
||||
# Controller template schemas
|
||||
from .controller.templates.vpcs_templates import VPCSTemplate
|
||||
from .controller.templates.cloud_templates import CloudTemplate
|
||||
from .controller.templates.iou_templates import IOUTemplate
|
||||
from .controller.templates.docker_templates import DockerTemplate
|
||||
from .controller.templates.ethernet_hub_templates import EthernetHubTemplate
|
||||
from .controller.templates.ethernet_switch_templates import EthernetSwitchTemplate
|
||||
from .controller.templates.virtualbox_templates import VirtualBoxTemplate
|
||||
from .controller.templates.vmware_templates import VMwareTemplate
|
||||
from .controller.templates.qemu_templates import QemuTemplate
|
||||
from .controller.templates.vpcs_templates import VPCSTemplate, VPCSTemplateUpdate
|
||||
from .controller.templates.cloud_templates import CloudTemplate, CloudTemplateUpdate
|
||||
from .controller.templates.iou_templates import IOUTemplate, IOUTemplateUpdate
|
||||
from .controller.templates.docker_templates import DockerTemplate, DockerTemplateUpdate
|
||||
from .controller.templates.ethernet_hub_templates import EthernetHubTemplate, EthernetHubTemplateUpdate
|
||||
from .controller.templates.ethernet_switch_templates import EthernetSwitchTemplate, EthernetSwitchTemplateUpdate
|
||||
from .controller.templates.virtualbox_templates import VirtualBoxTemplate, VirtualBoxTemplateUpdate
|
||||
from .controller.templates.vmware_templates import VMwareTemplate, VMwareTemplateUpdate
|
||||
from .controller.templates.qemu_templates import QemuTemplate, QemuTemplateUpdate
|
||||
from .controller.templates.dynamips_templates import (
|
||||
DynamipsTemplate,
|
||||
C1700DynamipsTemplate,
|
||||
C1700DynamipsTemplateUpdate,
|
||||
C2600DynamipsTemplate,
|
||||
C2600DynamipsTemplateUpdate,
|
||||
C2691DynamipsTemplate,
|
||||
C2691DynamipsTemplateUpdate,
|
||||
C3600DynamipsTemplate,
|
||||
C3600DynamipsTemplateUpdate,
|
||||
C3725DynamipsTemplate,
|
||||
C3725DynamipsTemplateUpdate,
|
||||
C3745DynamipsTemplate,
|
||||
C3745DynamipsTemplateUpdate,
|
||||
C7200DynamipsTemplate,
|
||||
C7200DynamipsTemplateUpdate
|
||||
)
|
||||
|
||||
# Compute schemas
|
||||
|
@ -24,6 +24,8 @@ class ControllerSettings(BaseModel):
|
||||
jwt_secret_key: str = None
|
||||
jwt_algorithm: str = "HS256"
|
||||
jwt_access_token_expire_minutes: int = 1440 # 24 hours
|
||||
default_admin_username: str = "admin"
|
||||
default_admin_password: SecretStr = SecretStr("admin")
|
||||
|
||||
class Config:
|
||||
validate_assignment = True
|
||||
@ -131,11 +133,8 @@ class ServerSettings(BaseModel):
|
||||
udp_start_port_range: int = Field(10000, gt=0, le=65535)
|
||||
udp_end_port_range: int = Field(30000, gt=0, le=65535)
|
||||
ubridge_path: str = "ubridge"
|
||||
user: str = None
|
||||
password: SecretStr = None
|
||||
enable_http_auth: bool = False
|
||||
default_admin_username: str = "admin"
|
||||
default_admin_password: SecretStr = SecretStr("admin")
|
||||
compute_username: str = "admin"
|
||||
compute_password: SecretStr = SecretStr("")
|
||||
allowed_interfaces: List[str] = Field(default_factory=list)
|
||||
default_nat_interface: str = None
|
||||
allow_remote_console: bool = False
|
||||
@ -164,14 +163,6 @@ class ServerSettings(BaseModel):
|
||||
raise ValueError("vnc_console_end_port_range must be > vnc_console_start_port_range")
|
||||
return v
|
||||
|
||||
@validator("enable_http_auth")
|
||||
def validate_enable_auth(cls, v, values):
|
||||
|
||||
if v is True:
|
||||
if "user" not in values or not values["user"]:
|
||||
raise ValueError("HTTP authentication is enabled but user is not configured")
|
||||
return v
|
||||
|
||||
@validator("enable_ssl")
|
||||
def validate_enable_ssl(cls, v, values):
|
||||
|
||||
|
@ -41,9 +41,13 @@ class ComputeBase(BaseModel):
|
||||
protocol: Protocol
|
||||
host: str
|
||||
port: int = Field(..., gt=0, le=65535)
|
||||
user: Optional[str] = None
|
||||
user: str = None
|
||||
password: Optional[SecretStr] = None
|
||||
name: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
use_enum_values = True
|
||||
|
||||
|
||||
class ComputeCreate(ComputeBase):
|
||||
"""
|
||||
@ -51,7 +55,6 @@ class ComputeCreate(ComputeBase):
|
||||
"""
|
||||
|
||||
compute_id: Union[str, uuid.UUID] = None
|
||||
password: Optional[SecretStr] = None
|
||||
|
||||
class Config:
|
||||
schema_extra = {
|
||||
@ -102,6 +105,7 @@ class ComputeUpdate(ComputeBase):
|
||||
protocol: Optional[Protocol] = None
|
||||
host: Optional[str] = None
|
||||
port: Optional[int] = Field(None, gt=0, le=65535)
|
||||
user: Optional[str] = None
|
||||
password: Optional[SecretStr] = None
|
||||
|
||||
class Config:
|
||||
|
@ -50,9 +50,6 @@ class TemplateBase(BaseModel):
|
||||
compute_id: Optional[str] = None
|
||||
usage: Optional[str] = ""
|
||||
|
||||
class Config:
|
||||
extra = "allow"
|
||||
|
||||
|
||||
class TemplateCreate(TemplateBase):
|
||||
"""
|
||||
@ -61,12 +58,15 @@ class TemplateCreate(TemplateBase):
|
||||
|
||||
name: str
|
||||
template_type: NodeType
|
||||
compute_id: str
|
||||
|
||||
class Config:
|
||||
extra = "allow"
|
||||
|
||||
|
||||
class TemplateUpdate(TemplateBase):
|
||||
|
||||
pass
|
||||
class Config:
|
||||
extra = "allow"
|
||||
|
||||
|
||||
class Template(DateTimeModelMixin, TemplateBase):
|
||||
@ -77,9 +77,9 @@ class Template(DateTimeModelMixin, TemplateBase):
|
||||
symbol: str
|
||||
builtin: bool
|
||||
template_type: NodeType
|
||||
compute_id: Union[str, None]
|
||||
|
||||
class Config:
|
||||
extra = "allow"
|
||||
orm_mode = True
|
||||
|
||||
|
||||
|
@ -37,3 +37,8 @@ class CloudTemplate(TemplateBase):
|
||||
remote_console_port: Optional[int] = Field(23, gt=0, le=65535, description="Remote console TCP port")
|
||||
remote_console_type: Optional[CloudConsoleType] = Field("none", description="Remote console type")
|
||||
remote_console_http_path: Optional[str] = Field("/", description="Path of the remote web interface")
|
||||
|
||||
|
||||
class CloudTemplateUpdate(CloudTemplate):
|
||||
|
||||
pass
|
||||
|
@ -51,3 +51,8 @@ class DockerTemplate(TemplateBase):
|
||||
memory: Optional[int] = Field(0, description="Maximum amount of memory the container can use in MB")
|
||||
cpus: Optional[int] = Field(0, description="Maximum amount of CPU resources the container can use")
|
||||
custom_adapters: Optional[List[CustomAdapter]] = Field(default_factory=list, description="Custom adapters")
|
||||
|
||||
|
||||
class DockerTemplateUpdate(DockerTemplate):
|
||||
|
||||
image: Optional[str] = Field(None, description="Docker image name")
|
@ -77,6 +77,12 @@ class C7200DynamipsTemplate(DynamipsTemplate):
|
||||
sparsemem: Optional[bool] = Field(True, description="Sparse memory feature")
|
||||
|
||||
|
||||
class C7200DynamipsTemplateUpdate(C7200DynamipsTemplate):
|
||||
|
||||
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
|
||||
image: Optional[str] = Field(None, description="Path to the IOS image")
|
||||
|
||||
|
||||
class C3725DynamipsTemplate(DynamipsTemplate):
|
||||
|
||||
ram: Optional[int] = Field(128, description="Amount of RAM in MB")
|
||||
@ -85,6 +91,12 @@ class C3725DynamipsTemplate(DynamipsTemplate):
|
||||
sparsemem: Optional[bool] = Field(True, description="Sparse memory feature")
|
||||
|
||||
|
||||
class C3725DynamipsTemplateUpdate(C3725DynamipsTemplate):
|
||||
|
||||
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
|
||||
image: Optional[str] = Field(None, description="Path to the IOS image")
|
||||
|
||||
|
||||
class C3745DynamipsTemplate(DynamipsTemplate):
|
||||
|
||||
ram: Optional[int] = Field(256, description="Amount of RAM in MB")
|
||||
@ -93,6 +105,12 @@ class C3745DynamipsTemplate(DynamipsTemplate):
|
||||
sparsemem: Optional[bool] = Field(True, description="Sparse memory feature")
|
||||
|
||||
|
||||
class C3745DynamipsTemplateUpdate(C3745DynamipsTemplate):
|
||||
|
||||
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
|
||||
image: Optional[str] = Field(None, description="Path to the IOS image")
|
||||
|
||||
|
||||
class C3600ChassisType(str, Enum):
|
||||
|
||||
chassis_3620 = "3620"
|
||||
@ -109,6 +127,12 @@ class C3600DynamipsTemplate(DynamipsTemplate):
|
||||
sparsemem: Optional[bool] = Field(True, description="Sparse memory feature")
|
||||
|
||||
|
||||
class C3600DynamipsTemplateUpdate(C3600DynamipsTemplate):
|
||||
|
||||
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
|
||||
image: Optional[str] = Field(None, description="Path to the IOS image")
|
||||
|
||||
|
||||
class C2691DynamipsTemplate(DynamipsTemplate):
|
||||
|
||||
ram: Optional[int] = Field(192, description="Amount of RAM in MB")
|
||||
@ -117,6 +141,12 @@ class C2691DynamipsTemplate(DynamipsTemplate):
|
||||
sparsemem: Optional[bool] = Field(True, description="Sparse memory feature")
|
||||
|
||||
|
||||
class C2691DynamipsTemplateUpdate(C2691DynamipsTemplate):
|
||||
|
||||
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
|
||||
image: Optional[str] = Field(None, description="Path to the IOS image")
|
||||
|
||||
|
||||
class C2600ChassisType(str, Enum):
|
||||
|
||||
chassis_2610 = "2610"
|
||||
@ -139,6 +169,12 @@ class C2600DynamipsTemplate(DynamipsTemplate):
|
||||
sparsemem: Optional[bool] = Field(True, description="Sparse memory feature")
|
||||
|
||||
|
||||
class C2600DynamipsTemplateUpdate(C2600DynamipsTemplate):
|
||||
|
||||
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
|
||||
image: Optional[str] = Field(None, description="Path to the IOS image")
|
||||
|
||||
|
||||
class C1700ChassisType(str, Enum):
|
||||
|
||||
chassis_1720 = "1720"
|
||||
@ -155,3 +191,9 @@ class C1700DynamipsTemplate(DynamipsTemplate):
|
||||
nvram: Optional[int] = Field(128, description="Amount of NVRAM in KB")
|
||||
iomem: Optional[int] = Field(15, ge=0, le=100, description="I/O memory percentage")
|
||||
sparsemem: Optional[bool] = Field(False, description="Sparse memory feature")
|
||||
|
||||
|
||||
class C1700DynamipsTemplateUpdate(C1700DynamipsTemplate):
|
||||
|
||||
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
|
||||
image: Optional[str] = Field(None, description="Path to the IOS image")
|
||||
|
@ -39,3 +39,8 @@ class EthernetHubTemplate(TemplateBase):
|
||||
default_name_format: Optional[str] = "Hub{0}"
|
||||
symbol: Optional[str] = ":/symbols/hub.svg"
|
||||
ports_mapping: Optional[List[EthernetHubPort]] = Field(DEFAULT_PORTS, description="Ports")
|
||||
|
||||
|
||||
class EthernetHubTemplateUpdate(EthernetHubTemplate):
|
||||
|
||||
pass
|
||||
|
@ -50,3 +50,8 @@ class EthernetSwitchTemplate(TemplateBase):
|
||||
symbol: Optional[str] = ":/symbols/ethernet_switch.svg"
|
||||
ports_mapping: Optional[List[EthernetSwitchPort]] = Field(DEFAULT_PORTS, description="Ports")
|
||||
console_type: Optional[ConsoleType] = Field("none", description="Console type")
|
||||
|
||||
|
||||
class EthernetSwitchTemplateUpdate(EthernetSwitchTemplate):
|
||||
|
||||
pass
|
||||
|
@ -40,3 +40,8 @@ class IOUTemplate(TemplateBase):
|
||||
console_auto_start: Optional[bool] = Field(
|
||||
False, description="Automatically start the console when the node has started"
|
||||
)
|
||||
|
||||
|
||||
class IOUTemplateUpdate(IOUTemplate):
|
||||
|
||||
path: Optional[str] = Field(None, description="Path of IOU executable")
|
||||
|
@ -37,7 +37,7 @@ class QemuTemplate(TemplateBase):
|
||||
default_name_format: Optional[str] = "{name}-{0}"
|
||||
symbol: Optional[str] = ":/symbols/qemu_guest.svg"
|
||||
qemu_path: Optional[str] = Field("", description="Qemu executable path")
|
||||
platform: Optional[QemuPlatform] = Field("i386", description="Platform to emulate")
|
||||
platform: Optional[QemuPlatform] = Field("x86_64", description="Platform to emulate")
|
||||
linked_clone: Optional[bool] = Field(True, description="Whether the VM is a linked clone or not")
|
||||
ram: Optional[int] = Field(256, description="Amount of RAM in MB")
|
||||
cpus: Optional[int] = Field(1, ge=1, le=255, description="Number of vCPUs")
|
||||
@ -85,3 +85,8 @@ class QemuTemplate(TemplateBase):
|
||||
process_priority: Optional[QemuProcessPriority] = Field("normal", description="Process priority for QEMU")
|
||||
options: Optional[str] = Field("", description="Additional QEMU options")
|
||||
custom_adapters: Optional[List[CustomAdapter]] = Field(default_factory=list, description="Custom adapters")
|
||||
|
||||
|
||||
class QemuTemplateUpdate(QemuTemplate):
|
||||
|
||||
pass
|
||||
|
@ -58,3 +58,8 @@ class VirtualBoxTemplate(TemplateBase):
|
||||
False, description="Automatically start the console when the node has started"
|
||||
)
|
||||
custom_adapters: Optional[List[CustomAdapter]] = Field(default_factory=list, description="Custom adapters")
|
||||
|
||||
|
||||
class VirtualBoxTemplateUpdate(VirtualBoxTemplate):
|
||||
|
||||
vmname: Optional[str] = Field(None, description="VirtualBox VM name (in VirtualBox itself)")
|
||||
|
@ -54,3 +54,8 @@ class VMwareTemplate(TemplateBase):
|
||||
False, description="Automatically start the console when the node has started"
|
||||
)
|
||||
custom_adapters: Optional[List[CustomAdapter]] = Field(default_factory=list, description="Custom adapters")
|
||||
|
||||
|
||||
class VMwareTemplateUpdate(VMwareTemplate):
|
||||
|
||||
vmx_path: Optional[str] = Field(None, description="Path to the vmx file")
|
||||
|
@ -32,3 +32,8 @@ class VPCSTemplate(TemplateBase):
|
||||
console_auto_start: Optional[bool] = Field(
|
||||
False, description="Automatically start the console when the node has started"
|
||||
)
|
||||
|
||||
|
||||
class VPCSTemplateUpdate(VPCSTemplate):
|
||||
|
||||
pass
|
||||
|
@ -20,5 +20,6 @@ from typing import Optional
|
||||
|
||||
class Version(BaseModel):
|
||||
|
||||
controller_host: Optional[str] = Field(None, description="Controller hostname or IP address")
|
||||
version: str = Field(..., description="Version number")
|
||||
local: Optional[bool] = Field(None, description="Whether this is a local server or not")
|
||||
|
@ -30,6 +30,8 @@ import asyncio
|
||||
import signal
|
||||
import functools
|
||||
import uvicorn
|
||||
import secrets
|
||||
import string
|
||||
|
||||
from gns3server.controller import Controller
|
||||
from gns3server.compute.port_manager import PortManager
|
||||
@ -38,7 +40,7 @@ from gns3server.version import __version__
|
||||
from gns3server.config import Config
|
||||
from gns3server.crash_report import CrashReport
|
||||
from gns3server.api.server import app
|
||||
from pydantic import ValidationError
|
||||
from pydantic import ValidationError, SecretStr
|
||||
|
||||
import logging
|
||||
|
||||
@ -199,9 +201,9 @@ class Server:
|
||||
loop.add_signal_handler(getattr(signal, signal_name), callback)
|
||||
|
||||
@staticmethod
|
||||
def _kill_ghosts(self):
|
||||
def _kill_ghosts():
|
||||
"""
|
||||
Kill process from previous GNS3 session
|
||||
Kill processes from previous GNS3 session
|
||||
"""
|
||||
detect_process = ["vpcs", "ubridge", "dynamips"]
|
||||
for proc in psutil.process_iter():
|
||||
@ -214,7 +216,7 @@ class Server:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _pid_lock(self, path):
|
||||
def _pid_lock(path):
|
||||
"""
|
||||
Write the file in a file on the system.
|
||||
Check if the process is not already running.
|
||||
@ -269,8 +271,15 @@ class Server:
|
||||
if config.Server.local:
|
||||
log.warning("Local mode is enabled. Beware, clients will have full control on your filesystem")
|
||||
|
||||
if config.Server.enable_http_auth:
|
||||
log.info(f"HTTP authentication is enabled with username '{config.Server.user}'")
|
||||
if not config.Server.compute_password.get_secret_value():
|
||||
alphabet = string.ascii_letters + string.digits + string.punctuation
|
||||
generated_password = ''.join(secrets.choice(alphabet) for _ in range(16))
|
||||
config.Server.compute_password = SecretStr(generated_password)
|
||||
log.warning(f"Compute authentication is enabled with username '{config.Server.compute_username}' and "
|
||||
f"a randomly generated password. Please set a password in the config file if this compute "
|
||||
f"is to be used by an external controller")
|
||||
else:
|
||||
log.info(f"Compute authentication is enabled with username '{config.Server.compute_username}'")
|
||||
|
||||
# we only support Python 3 version >= 3.6
|
||||
if sys.version_info < (3, 6, 0):
|
||||
|
@ -35,6 +35,7 @@ DEFAULT_JWT_SECRET_KEY = "efd08eccec3bd0a1be2e086670e5efa90969c68d07e072d7354a76
|
||||
|
||||
|
||||
class AuthService:
|
||||
|
||||
def hash_password(self, password: str) -> str:
|
||||
|
||||
return pwd_context.hash(password)
|
||||
|
@ -41,17 +41,17 @@ class ComputesService:
|
||||
db_computes = await self._computes_repo.get_computes()
|
||||
return db_computes
|
||||
|
||||
async def create_compute(self, compute_create: schemas.ComputeCreate) -> models.Compute:
|
||||
async def create_compute(self, compute_create: schemas.ComputeCreate, connect: bool = False) -> models.Compute:
|
||||
|
||||
if await self._computes_repo.get_compute(compute_create.compute_id):
|
||||
raise ControllerBadRequestError(f"Compute '{compute_create.compute_id}' is already registered")
|
||||
db_compute = await self._computes_repo.create_compute(compute_create)
|
||||
await self._controller.add_compute(
|
||||
compute = await self._controller.add_compute(
|
||||
compute_id=str(db_compute.compute_id),
|
||||
connect=False,
|
||||
connect=connect,
|
||||
**compute_create.dict(exclude_unset=True, exclude={"compute_id"}),
|
||||
)
|
||||
self._controller.notification.controller_emit("compute.created", db_compute.asjson())
|
||||
self._controller.notification.controller_emit("compute.created", compute.asdict())
|
||||
return db_compute
|
||||
|
||||
async def get_compute(self, compute_id: Union[str, UUID]) -> models.Compute:
|
||||
@ -70,7 +70,7 @@ class ComputesService:
|
||||
db_compute = await self._computes_repo.update_compute(compute_id, compute_update)
|
||||
if not db_compute:
|
||||
raise ControllerNotFoundError(f"Compute '{compute_id}' not found")
|
||||
self._controller.notification.controller_emit("compute.updated", db_compute.asjson())
|
||||
self._controller.notification.controller_emit("compute.updated", compute.asdict())
|
||||
return db_compute
|
||||
|
||||
async def delete_compute(self, compute_id: Union[str, UUID]) -> None:
|
||||
|
@ -32,7 +32,7 @@ from gns3server.controller.controller_error import (
|
||||
ControllerForbiddenError,
|
||||
)
|
||||
|
||||
TEMPLATE_TYPE_TO_SHEMA = {
|
||||
TEMPLATE_TYPE_TO_SCHEMA = {
|
||||
"cloud": schemas.CloudTemplate,
|
||||
"ethernet_hub": schemas.EthernetHubTemplate,
|
||||
"ethernet_switch": schemas.EthernetSwitchTemplate,
|
||||
@ -45,7 +45,19 @@ TEMPLATE_TYPE_TO_SHEMA = {
|
||||
"qemu": schemas.QemuTemplate,
|
||||
}
|
||||
|
||||
DYNAMIPS_PLATFORM_TO_SHEMA = {
|
||||
TEMPLATE_TYPE_TO_UPDATE_SCHEMA = {
|
||||
"cloud": schemas.CloudTemplateUpdate,
|
||||
"ethernet_hub": schemas.EthernetHubTemplateUpdate,
|
||||
"ethernet_switch": schemas.EthernetSwitchTemplateUpdate,
|
||||
"docker": schemas.DockerTemplateUpdate,
|
||||
"vpcs": schemas.VPCSTemplateUpdate,
|
||||
"virtualbox": schemas.VirtualBoxTemplateUpdate,
|
||||
"vmware": schemas.VMwareTemplateUpdate,
|
||||
"iou": schemas.IOUTemplateUpdate,
|
||||
"qemu": schemas.QemuTemplateUpdate,
|
||||
}
|
||||
|
||||
DYNAMIPS_PLATFORM_TO_SCHEMA = {
|
||||
"c7200": schemas.C7200DynamipsTemplate,
|
||||
"c3745": schemas.C3745DynamipsTemplate,
|
||||
"c3725": schemas.C3725DynamipsTemplate,
|
||||
@ -55,6 +67,16 @@ DYNAMIPS_PLATFORM_TO_SHEMA = {
|
||||
"c1700": schemas.C1700DynamipsTemplate,
|
||||
}
|
||||
|
||||
DYNAMIPS_PLATFORM_TO_UPDATE_SCHEMA = {
|
||||
"c7200": schemas.C7200DynamipsTemplateUpdate,
|
||||
"c3745": schemas.C3745DynamipsTemplateUpdate,
|
||||
"c3725": schemas.C3725DynamipsTemplateUpdate,
|
||||
"c3600": schemas.C3600DynamipsTemplateUpdate,
|
||||
"c2691": schemas.C2691DynamipsTemplateUpdate,
|
||||
"c2600": schemas.C2600DynamipsTemplateUpdate,
|
||||
"c1700": schemas.C1700DynamipsTemplateUpdate,
|
||||
}
|
||||
|
||||
# built-in templates have their compute_id set to None to tell clients to select a compute
|
||||
BUILTIN_TEMPLATES = [
|
||||
{
|
||||
@ -159,8 +181,10 @@ class TemplatesService:
|
||||
async def _find_image(self, image_path: str):
|
||||
|
||||
image = await self._templates_repo.get_image(image_path)
|
||||
if not image or not os.path.exists(image.path):
|
||||
raise ControllerNotFoundError(f"Image '{image_path}' could not be found")
|
||||
if not image:
|
||||
raise ControllerNotFoundError(f"Image '{image_path}' could not be found in the controller database")
|
||||
if not os.path.exists(image.path):
|
||||
raise ControllerNotFoundError(f"Image '{image.path}' could not be found on disk")
|
||||
return image
|
||||
|
||||
async def _find_images(self, template_type: str, settings: dict) -> List[models.Image]:
|
||||
@ -205,20 +229,18 @@ class TemplatesService:
|
||||
|
||||
try:
|
||||
# get the default template settings
|
||||
template_settings = jsonable_encoder(template_create, exclude_unset=True)
|
||||
template_schema = TEMPLATE_TYPE_TO_SHEMA[template_create.template_type]
|
||||
template_settings_with_defaults = template_schema.parse_obj(template_settings)
|
||||
settings = template_settings_with_defaults.dict()
|
||||
create_settings = jsonable_encoder(template_create, exclude_unset=True)
|
||||
template_schema = TEMPLATE_TYPE_TO_SCHEMA[template_create.template_type]
|
||||
template_settings = template_schema.parse_obj(create_settings).dict()
|
||||
if template_create.template_type == "dynamips":
|
||||
# special case for Dynamips to cover all platform types that contain specific settings
|
||||
dynamips_template_schema = DYNAMIPS_PLATFORM_TO_SHEMA[settings["platform"]]
|
||||
dynamips_template_settings_with_defaults = dynamips_template_schema.parse_obj(template_settings)
|
||||
settings = dynamips_template_settings_with_defaults.dict()
|
||||
dynamips_template_schema = DYNAMIPS_PLATFORM_TO_SCHEMA[template_settings["platform"]]
|
||||
template_settings = dynamips_template_schema.parse_obj(create_settings).dict()
|
||||
except pydantic.ValidationError as e:
|
||||
raise ControllerBadRequestError(f"JSON schema error received while creating new template: {e}")
|
||||
|
||||
images_to_add_to_template = await self._find_images(template_create.template_type, settings)
|
||||
db_template = await self._templates_repo.create_template(template_create.template_type, settings)
|
||||
images_to_add_to_template = await self._find_images(template_create.template_type, template_settings)
|
||||
db_template = await self._templates_repo.create_template(template_create.template_type, template_settings)
|
||||
for image in images_to_add_to_template:
|
||||
await self._templates_repo.add_image_to_template(db_template.template_id, image)
|
||||
template = db_template.asjson()
|
||||
@ -245,12 +267,22 @@ class TemplatesService:
|
||||
|
||||
if self.get_builtin_template(template_id):
|
||||
raise ControllerForbiddenError(f"Template '{template_id}' cannot be updated because it is built-in")
|
||||
template_settings = jsonable_encoder(template_update, exclude_unset=True)
|
||||
|
||||
db_template = await self._templates_repo.get_template(template_id)
|
||||
if not db_template:
|
||||
raise ControllerNotFoundError(f"Template '{template_id}' not found")
|
||||
|
||||
try:
|
||||
# validate the update settings
|
||||
update_settings = jsonable_encoder(template_update, exclude_unset=True)
|
||||
if db_template.template_type == "dynamips":
|
||||
template_schema = DYNAMIPS_PLATFORM_TO_UPDATE_SCHEMA[db_template.platform]
|
||||
else:
|
||||
template_schema = TEMPLATE_TYPE_TO_UPDATE_SCHEMA[db_template.template_type]
|
||||
template_settings = template_schema.parse_obj(update_settings).dict(exclude_unset=True)
|
||||
except pydantic.ValidationError as e:
|
||||
raise ControllerBadRequestError(f"JSON schema error received while updating template: {e}")
|
||||
|
||||
images_to_add_to_template = await self._find_images(db_template.template_type, template_settings)
|
||||
if db_template.template_type == "dynamips" and "image" in template_settings:
|
||||
await self._remove_image(db_template.template_id, db_template.image)
|
||||
|
1
gns3server/static/web-ui/26.288b4de0ead3b7b9276b.js
Normal file
1
gns3server/static/web-ui/26.288b4de0ead3b7b9276b.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
gns3server/static/web-ui/main.228427ce89197cdf9b3b.js
Normal file
1
gns3server/static/web-ui/main.228427ce89197cdf9b3b.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
!function(){"use strict";var e,v={},g={};function n(e){var u=g[e];if(void 0!==u)return u.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e](t,t.exports,n),t.loaded=!0,t.exports}n.m=v,e=[],n.O=function(u,t,a,o){if(!t){var r=1/0;for(i=0;i<e.length;i++){t=e[i][0],a=e[i][1],o=e[i][2];for(var l=!0,f=0;f<t.length;f++)(!1&o||r>=o)&&Object.keys(n.O).every(function(b){return n.O[b](t[f])})?t.splice(f--,1):(l=!1,o<r&&(r=o));if(l){e.splice(i--,1);var s=a();void 0!==s&&(u=s)}}return u}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,a,o]},n.n=function(e){var u=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(u,{a:u}),u},n.d=function(e,u){for(var t in u)n.o(u,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:u[t]})},n.f={},n.e=function(e){return Promise.all(Object.keys(n.f).reduce(function(u,t){return n.f[t](e,u),u},[]))},n.u=function(e){return e+".eace20bb0639f4909f27.js"},n.miniCssF=function(e){return"styles.bf28628fcb2844ad74bd.css"},n.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},n.o=function(e,u){return Object.prototype.hasOwnProperty.call(e,u)},function(){var e={},u="gns3-web-ui:";n.l=function(t,a,o,i){if(e[t])e[t].push(a);else{var r,l;if(void 0!==o)for(var f=document.getElementsByTagName("script"),s=0;s<f.length;s++){var c=f[s];if(c.getAttribute("src")==t||c.getAttribute("data-webpack")==u+o){r=c;break}}r||(l=!0,(r=document.createElement("script")).charset="utf-8",r.timeout=120,n.nc&&r.setAttribute("nonce",n.nc),r.setAttribute("data-webpack",u+o),r.src=n.tu(t)),e[t]=[a];var d=function(h,b){r.onerror=r.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],r.parentNode&&r.parentNode.removeChild(r),_&&_.forEach(function(m){return m(b)}),h)return h(b)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=d.bind(null,r.onerror),r.onload=d.bind(null,r.onload),l&&document.head.appendChild(r)}}}(),n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e;n.tu=function(u){return void 0===e&&(e={createScriptURL:function(t){return t}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(u)}}(),n.p="",function(){var e={666:0};n.f.j=function(a,o){var i=n.o(e,a)?e[a]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=a){var r=new Promise(function(c,d){i=e[a]=[c,d]});o.push(i[2]=r);var l=n.p+n.u(a),f=new Error;n.l(l,function(c){if(n.o(e,a)&&(0!==(i=e[a])&&(e[a]=void 0),i)){var d=c&&("load"===c.type?"missing":c.type),p=c&&c.target&&c.target.src;f.message="Loading chunk "+a+" failed.\n("+d+": "+p+")",f.name="ChunkLoadError",f.type=d,f.request=p,i[1](f)}},"chunk-"+a,a)}else e[a]=0},n.O.j=function(a){return 0===e[a]};var u=function(a,o){var f,s,i=o[0],r=o[1],l=o[2],c=0;for(f in r)n.o(r,f)&&(n.m[f]=r[f]);if(l)var d=l(n);for(a&&a(o);c<i.length;c++)n.o(e,s=i[c])&&e[s]&&e[s][0](),e[i[c]]=0;return n.O(d)},t=self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[];t.forEach(u.bind(null,0)),t.push=u.bind(null,t.push.bind(t))}()}();
|
1
gns3server/static/web-ui/runtime.445d8d501d6ed9a85ab9.js
Normal file
1
gns3server/static/web-ui/runtime.445d8d501d6ed9a85ab9.js
Normal file
@ -0,0 +1 @@
|
||||
!function(){"use strict";var e,v={},g={};function n(e){var a=g[e];if(void 0!==a)return a.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e](t,t.exports,n),t.loaded=!0,t.exports}n.m=v,e=[],n.O=function(a,t,u,o){if(!t){var r=1/0;for(i=0;i<e.length;i++){t=e[i][0],u=e[i][1],o=e[i][2];for(var l=!0,f=0;f<t.length;f++)(!1&o||r>=o)&&Object.keys(n.O).every(function(b){return n.O[b](t[f])})?t.splice(f--,1):(l=!1,o<r&&(r=o));if(l){e.splice(i--,1);var s=u();void 0!==s&&(a=s)}}return a}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,u,o]},n.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(a,{a:a}),a},n.d=function(e,a){for(var t in a)n.o(a,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},n.f={},n.e=function(e){return Promise.all(Object.keys(n.f).reduce(function(a,t){return n.f[t](e,a),a},[]))},n.u=function(e){return e+".288b4de0ead3b7b9276b.js"},n.miniCssF=function(e){return"styles.f8555f2eecf8cf87f666.css"},n.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},n.o=function(e,a){return Object.prototype.hasOwnProperty.call(e,a)},function(){var e={},a="gns3-web-ui:";n.l=function(t,u,o,i){if(e[t])e[t].push(u);else{var r,l;if(void 0!==o)for(var f=document.getElementsByTagName("script"),s=0;s<f.length;s++){var c=f[s];if(c.getAttribute("src")==t||c.getAttribute("data-webpack")==a+o){r=c;break}}r||(l=!0,(r=document.createElement("script")).charset="utf-8",r.timeout=120,n.nc&&r.setAttribute("nonce",n.nc),r.setAttribute("data-webpack",a+o),r.src=n.tu(t)),e[t]=[u];var d=function(h,b){r.onerror=r.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],r.parentNode&&r.parentNode.removeChild(r),_&&_.forEach(function(m){return m(b)}),h)return h(b)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=d.bind(null,r.onerror),r.onload=d.bind(null,r.onload),l&&document.head.appendChild(r)}}}(),n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e;n.tu=function(a){return void 0===e&&(e={createScriptURL:function(t){return t}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(a)}}(),n.p="",function(){var e={666:0};n.f.j=function(u,o){var i=n.o(e,u)?e[u]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=u){var r=new Promise(function(c,d){i=e[u]=[c,d]});o.push(i[2]=r);var l=n.p+n.u(u),f=new Error;n.l(l,function(c){if(n.o(e,u)&&(0!==(i=e[u])&&(e[u]=void 0),i)){var d=c&&("load"===c.type?"missing":c.type),p=c&&c.target&&c.target.src;f.message="Loading chunk "+u+" failed.\n("+d+": "+p+")",f.name="ChunkLoadError",f.type=d,f.request=p,i[1](f)}},"chunk-"+u,u)}else e[u]=0},n.O.j=function(u){return 0===e[u]};var a=function(u,o){var f,s,i=o[0],r=o[1],l=o[2],c=0;for(f in r)n.o(r,f)&&(n.m[f]=r[f]);if(l)var d=l(n);for(u&&u(o);c<i.length;c++)n.o(e,s=i[c])&&e[s]&&e[s][0](),e[i[c]]=0;return n.O(d)},t=self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[];t.forEach(a.bind(null,0)),t.push=a.bind(null,t.push.bind(t))}()}();
|
File diff suppressed because one or more lines are too long
11
gns3server/static/web-ui/styles.f8555f2eecf8cf87f666.css
Normal file
11
gns3server/static/web-ui/styles.f8555f2eecf8cf87f666.css
Normal file
File diff suppressed because one or more lines are too long
@ -52,7 +52,7 @@ class HTTPClient:
|
||||
if not password:
|
||||
password = ""
|
||||
try:
|
||||
basic_auth = aiohttp.BasicAuth(user, password, "utf-8")
|
||||
basic_auth = aiohttp.BasicAuth(user, password.get_secret_value(), "utf-8")
|
||||
except ValueError as e:
|
||||
log.error(f"Basic authentication set-up error: {e}")
|
||||
|
||||
|
@ -4,17 +4,9 @@ Wants=network-online.target
|
||||
After=network.target network-online.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
User=gns3
|
||||
Group=gns3
|
||||
PermissionsStartOnly=true
|
||||
ExecStartPre=/bin/mkdir -p /var/log/gns3 /var/run/gns3
|
||||
ExecStartPre=/bin/chown -R gns3:gns3 /var/log/gns3 /var/run/gns3
|
||||
ExecStart=/usr/local/bin/gns3server --log /var/log/gns3/gns3.log \
|
||||
--pid /var/run/gns3/gns3.pid --daemon
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
Restart=on-abort
|
||||
PIDFile=/var/run/gns3/gns3.pid
|
||||
ExecStart=/usr/bin/gns3server
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target
|
@ -1,17 +1,19 @@
|
||||
uvicorn==0.15.0
|
||||
fastapi==0.70.0
|
||||
websockets==10.0 ; python_version >= "3.7"
|
||||
websockets==9.1 ; python_version < "3.7"
|
||||
uvicorn==0.17.0
|
||||
fastapi==0.72.0
|
||||
python-multipart==0.0.5
|
||||
aiohttp==3.7.4.post0
|
||||
aiofiles==0.7.0
|
||||
Jinja2==3.0.2
|
||||
sentry-sdk==1.4.3
|
||||
psutil==5.8.0
|
||||
async-timeout==3.0.1
|
||||
websockets==10.1 ; python_version >= "3.7"
|
||||
websockets==9.1 ; python_version < "3.7"
|
||||
aiohttp==3.8.1 ; python_version >= "3.7"
|
||||
aiohttp==3.7.4.post0 ; python_version < "3.7"
|
||||
async-timeout==4.0.2 ; python_version >= "3.7"
|
||||
async-timeout==3.0.1 ; python_version < "3.7"
|
||||
aiofiles==0.8.0
|
||||
Jinja2==3.0.3
|
||||
sentry-sdk==1.5.2
|
||||
psutil==5.9.0
|
||||
distro==1.6.0
|
||||
py-cpuinfo==8.0.0
|
||||
sqlalchemy==1.4.26
|
||||
sqlalchemy==1.4.29
|
||||
aiosqlite===0.17.0
|
||||
passlib[bcrypt]==1.7.4
|
||||
python-jose==3.3.0
|
||||
|
3
scripts/gns3_server.conf
Normal file
3
scripts/gns3_server.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[Server]
|
||||
compute_username = gns3
|
||||
compute_password = gns3
|
@ -30,9 +30,9 @@ pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
|
||||
async def test_get(app: FastAPI, client: AsyncClient, windows_platform) -> None:
|
||||
async def test_get(app: FastAPI, compute_client: AsyncClient, windows_platform) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_capabilities"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_capabilities"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == {'node_types': ['cloud', 'ethernet_hub', 'ethernet_switch', 'nat', 'vpcs', 'virtualbox', 'dynamips', 'frame_relay_switch', 'atm_switch', 'qemu', 'vmware', 'docker', 'iou'],
|
||||
'version': __version__,
|
||||
@ -44,9 +44,9 @@ async def test_get(app: FastAPI, client: AsyncClient, windows_platform) -> None:
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
|
||||
async def test_get_on_gns3vm(app: FastAPI, client: AsyncClient, on_gns3vm) -> None:
|
||||
async def test_get_on_gns3vm(app: FastAPI, compute_client: AsyncClient, on_gns3vm) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_capabilities"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_capabilities"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == {'node_types': ['cloud', 'ethernet_hub', 'ethernet_switch', 'nat', 'vpcs', 'virtualbox', 'dynamips', 'frame_relay_switch', 'atm_switch', 'qemu', 'vmware', 'docker', 'iou'],
|
||||
'version': __version__,
|
||||
|
@ -28,115 +28,115 @@ pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
async def vm(app: FastAPI, client: AsyncClient, compute_project: Project, on_gns3vm) -> dict:
|
||||
async def vm(app: FastAPI, compute_client: AsyncClient, compute_project: Project, on_gns3vm) -> dict:
|
||||
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._start_ubridge"):
|
||||
response = await client.post(app.url_path_for("create_cloud", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_cloud", project_id=compute_project.id),
|
||||
json={"name": "Cloud 1"})
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
return response.json()
|
||||
|
||||
|
||||
async def test_cloud_create(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def test_cloud_create(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._start_ubridge"):
|
||||
response = await client.post(app.url_path_for("create_cloud", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_cloud", project_id=compute_project.id),
|
||||
json={"name": "Cloud 1"})
|
||||
assert response.status_code == 201
|
||||
assert response.json()["name"] == "Cloud 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
|
||||
|
||||
async def test_get_cloud(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_get_cloud(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_cloud", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_cloud", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["name"] == "Cloud 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
assert response.json()["status"] == "started"
|
||||
|
||||
|
||||
async def test_cloud_nio_create_udp(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_cloud_nio_create_udp(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
params = {"type": "nio_udp",
|
||||
"lport": 4242,
|
||||
"rport": 4343,
|
||||
"rhost": "127.0.0.1"}
|
||||
|
||||
url = app.url_path_for("create_cloud_nio",
|
||||
url = app.url_path_for("compute:create_cloud_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_cloud_nio_update_udp(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_cloud_nio_update_udp(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
params = {"type": "nio_udp",
|
||||
"lport": 4242,
|
||||
"rport": 4343,
|
||||
"rhost": "127.0.0.1"}
|
||||
|
||||
url = app.url_path_for("create_cloud_nio",
|
||||
url = app.url_path_for("compute:create_cloud_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
|
||||
params["filters"] = {}
|
||||
url = app.url_path_for("create_cloud_nio",
|
||||
url = app.url_path_for("compute:create_cloud_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
response = await client.put(url, json=params)
|
||||
response = await compute_client.put(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_cloud_delete_nio(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_cloud_delete_nio(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
params = {"type": "nio_udp",
|
||||
"lport": 4242,
|
||||
"rport": 4343,
|
||||
"rhost": "127.0.0.1"}
|
||||
|
||||
url = app.url_path_for("create_cloud_nio",
|
||||
url = app.url_path_for("compute:create_cloud_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
|
||||
url = app.url_path_for("delete_cloud_nio",
|
||||
url = app.url_path_for("compute:delete_cloud_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._start_ubridge"):
|
||||
response = await client.delete(url)
|
||||
response = await compute_client.delete(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_cloud_delete(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_cloud_delete(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
response = await client.delete(app.url_path_for("delete_cloud", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
response = await compute_client.delete(app.url_path_for("compute:delete_cloud", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_cloud_update(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_cloud_update(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
response = await client.put(app.url_path_for("update_cloud", project_id=vm["project_id"], node_id=vm["node_id"]),
|
||||
response = await compute_client.put(app.url_path_for("compute:update_cloud", project_id=vm["project_id"], node_id=vm["node_id"]),
|
||||
json={"name": "test"})
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["name"] == "test"
|
||||
|
||||
|
||||
async def test_cloud_start_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_cloud_start_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"capture_file_name": "test.pcap",
|
||||
@ -144,7 +144,7 @@ async def test_cloud_start_capture(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud.start_capture") as mock:
|
||||
response = await client.post(app.url_path_for("start_cloud_capture",
|
||||
response = await compute_client.post(app.url_path_for("compute:start_cloud_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -155,10 +155,10 @@ async def test_cloud_start_capture(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
assert "test.pcap" in response.json()["pcap_file_path"]
|
||||
|
||||
|
||||
async def test_cloud_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_cloud_stop_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud.stop_capture") as mock:
|
||||
response = await client.post(app.url_path_for("stop_cloud_capture",
|
||||
response = await compute_client.post(app.url_path_for("compute:stop_cloud_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
|
@ -27,27 +27,33 @@ from gns3server.compute.project import Project
|
||||
pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
async def test_udp_allocation(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def test_udp_allocation(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("allocate_udp_port", project_id=compute_project.id), json={})
|
||||
response = await compute_client.post(app.url_path_for("compute:allocate_udp_port", project_id=compute_project.id), json={})
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()['udp_port'] is not None
|
||||
|
||||
|
||||
async def test_interfaces(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_interfaces(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("network_interfaces"))
|
||||
response = await compute_client.get(app.url_path_for("compute:network_interfaces"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert isinstance(response.json(), list)
|
||||
|
||||
|
||||
async def test_version_output(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_version_output(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("compute_version"))
|
||||
response = await compute_client.get(app.url_path_for("compute:compute_version"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == {'local': True, 'version': __version__}
|
||||
|
||||
|
||||
async def test_compute_authentication(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
response = await compute_client.get(app.url_path_for("compute:compute_version"), auth=("admin", "invalid_password"))
|
||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_debug_output(compute_api):
|
||||
#
|
||||
@ -55,7 +61,7 @@ async def test_version_output(app: FastAPI, client: AsyncClient) -> None:
|
||||
# assert response.status_code == 200
|
||||
|
||||
|
||||
async def test_statistics_output(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_statistics_output(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("compute_statistics"))
|
||||
response = await compute_client.get(app.url_path_for("compute:compute_statistics"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
|
@ -57,22 +57,22 @@ def base_params() -> dict:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def vm(app: FastAPI, client: AsyncClient, compute_project: Project, base_params: dict) -> dict:
|
||||
async def vm(app: FastAPI, compute_client: AsyncClient, compute_project: Project, base_params: dict) -> dict:
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}):
|
||||
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="exited"):
|
||||
response = await client.post(app.url_path_for("create_docker_node", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_docker_node", project_id=compute_project.id),
|
||||
json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
return response.json()
|
||||
|
||||
|
||||
async def test_docker_create(app: FastAPI, client: AsyncClient, compute_project: Project, base_params: dict) -> None:
|
||||
async def test_docker_create(app: FastAPI, compute_client: AsyncClient, compute_project: Project, base_params: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}):
|
||||
response = await client.post(app.url_path_for("create_docker_node", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_docker_node", project_id=compute_project.id),
|
||||
json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
@ -85,68 +85,68 @@ async def test_docker_create(app: FastAPI, client: AsyncClient, compute_project:
|
||||
assert response.json()["extra_hosts"] == "test:127.0.0.1"
|
||||
|
||||
|
||||
async def test_docker_start(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_start(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.start", return_value=True) as mock:
|
||||
|
||||
response = await client.post(app.url_path_for("start_docker_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:start_docker_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_docker_stop(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_stop(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.stop", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("stop_docker_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:stop_docker_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_docker_reload(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_reload(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.restart", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("reload_docker_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:reload_docker_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_docker_delete(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_delete(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.delete", return_value=True) as mock:
|
||||
response = await client.delete(app.url_path_for("delete_docker_node",
|
||||
response = await compute_client.delete(app.url_path_for("compute:delete_docker_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_docker_pause(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_pause(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.pause", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("pause_docker_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:pause_docker_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_docker_unpause(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_unpause(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.unpause", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("unpause_docker_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:unpause_docker_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_docker_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_nio_create_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -154,17 +154,17 @@ async def test_docker_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict
|
||||
"rport": 4343,
|
||||
"rhost": "127.0.0.1"}
|
||||
|
||||
url = app.url_path_for("create_docker_node_nio",
|
||||
url = app.url_path_for("compute:create_docker_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_docker_update_nio(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_update_nio(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -173,37 +173,37 @@ async def test_docker_update_nio(app: FastAPI, client: AsyncClient, vm: dict) ->
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_docker_node_nio",
|
||||
url = app.url_path_for("compute:create_docker_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
url = app.url_path_for("update_docker_node_nio",
|
||||
url = app.url_path_for("compute:update_docker_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.adapter_update_nio_binding"):
|
||||
response = await client.put(url, json=params)
|
||||
response = await compute_client.put(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
|
||||
async def test_docker_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_delete_nio(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("delete_docker_node_nio",
|
||||
url = app.url_path_for("compute:delete_docker_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.adapter_remove_nio_binding"):
|
||||
response = await client.delete(url)
|
||||
response = await compute_client.delete(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_docker_update(app: FastAPI, client: AsyncClient, vm: dict, free_console_port: int) -> None:
|
||||
async def test_docker_update(app: FastAPI, compute_client: AsyncClient, vm: dict, free_console_port: int) -> None:
|
||||
|
||||
params = {
|
||||
"name": "test",
|
||||
@ -214,7 +214,7 @@ async def test_docker_update(app: FastAPI, client: AsyncClient, vm: dict, free_c
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.update") as mock:
|
||||
response = await client.put(app.url_path_for("update_docker_node",
|
||||
response = await compute_client.put(app.url_path_for("compute:update_docker_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
|
||||
@ -227,9 +227,9 @@ async def test_docker_update(app: FastAPI, client: AsyncClient, vm: dict, free_c
|
||||
assert response.json()["extra_hosts"] == "test:127.0.0.1"
|
||||
|
||||
|
||||
async def test_docker_start_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_start_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("start_docker_node_capture",
|
||||
url = app.url_path_for("compute:start_docker_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -238,15 +238,15 @@ async def test_docker_start_capture(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
with patch("gns3server.compute.docker.docker_vm.DockerVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.start_capture") as mock:
|
||||
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert mock.called
|
||||
assert "test.pcap" in response.json()["pcap_file_path"]
|
||||
|
||||
|
||||
async def test_docker_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_docker_stop_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("stop_docker_node_capture",
|
||||
url = app.url_path_for("compute:stop_docker_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -254,22 +254,22 @@ async def test_docker_stop_capture(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
|
||||
with patch("gns3server.compute.docker.docker_vm.DockerVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.stop_capture") as mock:
|
||||
response = await client.post(url)
|
||||
response = await compute_client.post(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
|
||||
async def test_docker_duplicate(app: FastAPI, client: AsyncClient, vm: dict, base_params: dict) -> None:
|
||||
async def test_docker_duplicate(app: FastAPI, compute_client: AsyncClient, vm: dict, base_params: dict) -> None:
|
||||
|
||||
# create destination node first
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}):
|
||||
response = await client.post(app.url_path_for("create_docker_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:create_docker_node",
|
||||
project_id=vm["project_id"]), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
params = {"destination_node_id": response.json()["node_id"]}
|
||||
response = await client.post(app.url_path_for("duplicate_docker_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:duplicate_docker_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
@ -162,10 +162,10 @@ def fake_file(tmpdir) -> str:
|
||||
return path
|
||||
|
||||
|
||||
async def test_images(app: FastAPI, client: AsyncClient, tmpdir, fake_image: str, fake_file: str) -> None:
|
||||
async def test_images(app: FastAPI, compute_client: AsyncClient, tmpdir, fake_image: str, fake_file: str) -> None:
|
||||
|
||||
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmpdir)):
|
||||
response = await client.get(app.url_path_for("get_dynamips_images"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_dynamips_images"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == [{"filename": "7200.bin",
|
||||
"path": "7200.bin",
|
||||
@ -173,9 +173,9 @@ async def test_images(app: FastAPI, client: AsyncClient, tmpdir, fake_image: str
|
||||
"md5sum": "b0d5aa897d937aced5a6b1046e8f7e2e"}]
|
||||
|
||||
|
||||
async def test_upload_image(app: FastAPI, client: AsyncClient, images_dir: str) -> None:
|
||||
async def test_upload_image(app: FastAPI, compute_client: AsyncClient, images_dir: str) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("upload_dynamips_image", filename="test2"), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_dynamips_image", filename="test2"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
with open(os.path.join(images_dir, "IOS", "test2")) as f:
|
||||
@ -186,36 +186,36 @@ async def test_upload_image(app: FastAPI, client: AsyncClient, images_dir: str)
|
||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||
|
||||
|
||||
async def test_upload_image_forbidden_location(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_upload_image_forbidden_location(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
file_path = "%2e%2e/hello"
|
||||
response = await client.post(app.url_path_for("upload_dynamips_image", filename=file_path), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_dynamips_image", filename=file_path), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
async def test_download_image(app: FastAPI, client: AsyncClient, images_dir: str) -> None:
|
||||
async def test_download_image(app: FastAPI, compute_client: AsyncClient, images_dir: str) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("upload_dynamips_image", filename="test3"), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_dynamips_image", filename="test3"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
response = await client.get(app.url_path_for("download_dynamips_image", filename="test3"))
|
||||
response = await compute_client.get(app.url_path_for("compute:download_dynamips_image", filename="test3"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
|
||||
|
||||
async def test_download_image_forbidden(app: FastAPI, client: AsyncClient, tmpdir) -> None:
|
||||
async def test_download_image_forbidden(app: FastAPI, compute_client: AsyncClient, tmpdir) -> None:
|
||||
|
||||
file_path = "foo/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"
|
||||
response = await client.get(app.url_path_for("download_dynamips_image", filename=file_path))
|
||||
response = await compute_client.get(app.url_path_for("compute:download_dynamips_image", filename=file_path))
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
@pytest.mark.skipif(not sys.platform.startswith("win") and os.getuid() == 0, reason="Root can delete any image")
|
||||
async def test_upload_image_permission_denied(app: FastAPI, client: AsyncClient, images_dir: str) -> None:
|
||||
async def test_upload_image_permission_denied(app: FastAPI, compute_client: AsyncClient, images_dir: str) -> None:
|
||||
|
||||
os.makedirs(os.path.join(images_dir, "IOS"), exist_ok=True)
|
||||
with open(os.path.join(images_dir, "IOS", "test2.tmp"), "w+") as f:
|
||||
f.write("")
|
||||
os.chmod(os.path.join(images_dir, "IOS", "test2.tmp"), 0)
|
||||
|
||||
response = await client.post(app.url_path_for("upload_dynamips_image", filename="test2"), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_dynamips_image", filename="test2"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_409_CONFLICT
|
||||
|
@ -51,9 +51,9 @@ def base_params(tmpdir, fake_iou_bin) -> dict:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def vm(app: FastAPI, client: AsyncClient, compute_project: Project, base_params: dict) -> dict:
|
||||
async def vm(app: FastAPI, compute_client: AsyncClient, compute_project: Project, base_params: dict) -> dict:
|
||||
|
||||
response = await client.post(app.url_path_for("create_iou_node", project_id=compute_project.id), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_iou_node", project_id=compute_project.id), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
return response.json()
|
||||
|
||||
@ -65,9 +65,9 @@ def startup_config_file(compute_project: Project, vm: dict) -> str:
|
||||
return os.path.join(directory, "startup-config.cfg")
|
||||
|
||||
|
||||
async def test_iou_create(app: FastAPI, client: AsyncClient, compute_project: Project, base_params: dict) -> None:
|
||||
async def test_iou_create(app: FastAPI, compute_client: AsyncClient, compute_project: Project, base_params: dict) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("create_iou_node", project_id=compute_project.id), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_iou_node", project_id=compute_project.id), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
@ -79,7 +79,7 @@ async def test_iou_create(app: FastAPI, client: AsyncClient, compute_project: Pr
|
||||
|
||||
|
||||
async def test_iou_create_with_params(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project,
|
||||
base_params: dict) -> None:
|
||||
|
||||
@ -92,7 +92,7 @@ async def test_iou_create_with_params(app: FastAPI,
|
||||
params["startup_config_content"] = "hostname test"
|
||||
params["use_default_iou_values"] = False
|
||||
|
||||
response = await client.post(app.url_path_for("create_iou_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_iou_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
@ -109,7 +109,7 @@ async def test_iou_create_with_params(app: FastAPI,
|
||||
|
||||
async def test_iou_create_startup_config_already_exist(
|
||||
app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project,
|
||||
base_params: dict) -> None:
|
||||
"""We don't erase a startup-config if already exist at project creation"""
|
||||
@ -123,16 +123,16 @@ async def test_iou_create_startup_config_already_exist(
|
||||
params["node_id"] = node_id
|
||||
params["startup_config_content"] = "hostname test"
|
||||
|
||||
response = await client.post(app.url_path_for("create_iou_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_iou_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
with open(startup_config_file(compute_project, response.json())) as f:
|
||||
assert f.read() == "echo hello"
|
||||
|
||||
|
||||
async def test_iou_get(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_iou_get(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_iou_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_iou_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
@ -143,58 +143,58 @@ async def test_iou_get(app: FastAPI, client: AsyncClient, compute_project: Proje
|
||||
assert response.json()["l1_keepalives"] is False
|
||||
|
||||
|
||||
async def test_iou_start(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_start(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.start", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("start_iou_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:start_iou_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json={})
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_iou_start_with_iourc(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_start_with_iourc(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {"iourc_content": "test"}
|
||||
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.start", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("start_iou_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:start_iou_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_iou_stop(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_stop(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.stop", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("stop_iou_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:stop_iou_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_iou_reload(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_reload(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.reload", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("reload_iou_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:reload_iou_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_iou_delete(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_delete(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.iou.IOU.delete_node", return_value=True) as mock:
|
||||
response = await client.delete(app.url_path_for("delete_iou_node",
|
||||
response = await compute_client.delete(app.url_path_for("compute:delete_iou_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_iou_update(app: FastAPI, client: AsyncClient, vm: dict, free_console_port: int) -> None:
|
||||
async def test_iou_update(app: FastAPI, compute_client: AsyncClient, vm: dict, free_console_port: int) -> None:
|
||||
|
||||
params = {
|
||||
"name": "test",
|
||||
@ -207,7 +207,7 @@ async def test_iou_update(app: FastAPI, client: AsyncClient, vm: dict, free_cons
|
||||
"use_default_iou_values": True,
|
||||
}
|
||||
|
||||
response = await client.put(app.url_path_for("update_iou_node",
|
||||
response = await compute_client.put(app.url_path_for("compute:update_iou_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
@ -221,70 +221,70 @@ async def test_iou_update(app: FastAPI, client: AsyncClient, vm: dict, free_cons
|
||||
assert response.json()["use_default_iou_values"] is True
|
||||
|
||||
|
||||
async def test_iou_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_nio_create_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {"type": "nio_udp",
|
||||
"lport": 4242,
|
||||
"rport": 4343,
|
||||
"rhost": "127.0.0.1"}
|
||||
|
||||
url = app.url_path_for("create_iou_node_nio",
|
||||
url = app.url_path_for("compute:create_iou_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_iou_nio_update_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_nio_update_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {"type": "nio_udp",
|
||||
"lport": 4242,
|
||||
"rport": 4343,
|
||||
"rhost": "127.0.0.1"}
|
||||
|
||||
url = app.url_path_for("create_iou_node_nio",
|
||||
url = app.url_path_for("compute:create_iou_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
params["filters"] = {}
|
||||
|
||||
url = app.url_path_for("update_iou_node_nio",
|
||||
url = app.url_path_for("compute:update_iou_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
response = await client.put(url, json=params)
|
||||
response = await compute_client.put(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_iou_nio_create_ethernet(app: FastAPI, client: AsyncClient, vm: dict, ethernet_device: str) -> None:
|
||||
async def test_iou_nio_create_ethernet(app: FastAPI, compute_client: AsyncClient, vm: dict, ethernet_device: str) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_ethernet",
|
||||
"ethernet_device": ethernet_device
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_iou_node_nio",
|
||||
url = app.url_path_for("compute:create_iou_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_ethernet"
|
||||
assert response.json()["ethernet_device"] == ethernet_device
|
||||
|
||||
|
||||
async def test_iou_nio_create_ethernet_different_port(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
vm: dict,
|
||||
ethernet_device: str) -> None:
|
||||
|
||||
@ -293,36 +293,36 @@ async def test_iou_nio_create_ethernet_different_port(app: FastAPI,
|
||||
"ethernet_device": ethernet_device
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_iou_node_nio",
|
||||
url = app.url_path_for("compute:create_iou_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="3")
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_ethernet"
|
||||
assert response.json()["ethernet_device"] == ethernet_device
|
||||
|
||||
|
||||
async def test_iou_nio_create_tap(app: FastAPI, client: AsyncClient, vm: dict, ethernet_device: str) -> None:
|
||||
async def test_iou_nio_create_tap(app: FastAPI, compute_client: AsyncClient, vm: dict, ethernet_device: str) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_tap",
|
||||
"tap_device": ethernet_device
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_iou_node_nio",
|
||||
url = app.url_path_for("compute:create_iou_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
with patch("gns3server.compute.base_manager.BaseManager.has_privileged_access", return_value=True):
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_tap"
|
||||
|
||||
|
||||
async def test_iou_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_delete_nio(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -331,32 +331,32 @@ async def test_iou_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> No
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_iou_node_nio",
|
||||
url = app.url_path_for("compute:create_iou_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
|
||||
url = app.url_path_for("delete_iou_node_nio",
|
||||
url = app.url_path_for("compute:delete_iou_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
|
||||
response = await client.delete(url)
|
||||
response = await compute_client.delete(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_iou_start_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_start_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"capture_file_name": "test.pcap",
|
||||
"data_link_type": "DLT_EN10MB"
|
||||
}
|
||||
|
||||
url = app.url_path_for("start_iou_node_capture",
|
||||
url = app.url_path_for("compute:start_iou_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -364,15 +364,15 @@ async def test_iou_start_capture(app: FastAPI, client: AsyncClient, vm: dict) ->
|
||||
|
||||
with patch("gns3server.compute.iou.iou_vm.IOUVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.start_capture") as mock:
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert mock.called
|
||||
assert "test.pcap" in response.json()["pcap_file_path"]
|
||||
|
||||
|
||||
async def test_iou_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_iou_stop_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("stop_iou_node_capture",
|
||||
url = app.url_path_for("compute:stop_iou_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -380,7 +380,7 @@ async def test_iou_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) ->
|
||||
|
||||
with patch("gns3server.compute.iou.iou_vm.IOUVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.stop_capture") as mock:
|
||||
response = await client.post(url)
|
||||
response = await compute_client.post(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
@ -390,21 +390,21 @@ async def test_iou_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) ->
|
||||
#
|
||||
# with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.get_nio"):
|
||||
# with asyncio_patch("gns3server.compute.iou.IOU.stream_pcap_file"):
|
||||
# response = await client.get("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# response = await compute_client.get("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# assert response.status_code == status.HTTP_200_OK
|
||||
|
||||
|
||||
async def test_images(app: FastAPI, client: AsyncClient, fake_iou_bin: str) -> None:
|
||||
async def test_images(app: FastAPI, compute_client: AsyncClient, fake_iou_bin: str) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_iou_images"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_iou_images"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == [{"filename": "iou.bin", "path": "iou.bin", "filesize": 7, "md5sum": "e573e8f5c93c6c00783f20c7a170aa6c"}]
|
||||
|
||||
|
||||
async def test_upload_image(app: FastAPI, client: AsyncClient, tmpdir) -> None:
|
||||
async def test_upload_image(app: FastAPI, compute_client: AsyncClient, tmpdir) -> None:
|
||||
|
||||
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir)):
|
||||
response = await client.post(app.url_path_for("upload_iou_image", filename="test2"), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_iou_image", filename="test2"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
with open(str(tmpdir / "test2")) as f:
|
||||
@ -415,38 +415,38 @@ async def test_upload_image(app: FastAPI, client: AsyncClient, tmpdir) -> None:
|
||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||
|
||||
|
||||
async def test_upload_image_forbidden_location(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_upload_image_forbidden_location(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
file_path = "%2e%2e/hello"
|
||||
response = await client.post(app.url_path_for("upload_dynamips_image", filename=file_path), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_dynamips_image", filename=file_path), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
async def test_download_image(app: FastAPI, client: AsyncClient, images_dir: str) -> None:
|
||||
async def test_download_image(app: FastAPI, compute_client: AsyncClient, images_dir: str) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("upload_dynamips_image", filename="test3"), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_dynamips_image", filename="test3"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
response = await client.get(app.url_path_for("download_dynamips_image", filename="test3"))
|
||||
response = await compute_client.get(app.url_path_for("compute:download_dynamips_image", filename="test3"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
|
||||
|
||||
async def test_download_image_forbidden(app: FastAPI, client: AsyncClient, tmpdir) -> None:
|
||||
async def test_download_image_forbidden(app: FastAPI, compute_client: AsyncClient, tmpdir) -> None:
|
||||
|
||||
file_path = "foo/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"
|
||||
response = await client.get(app.url_path_for("download_iou_image", filename=file_path))
|
||||
response = await compute_client.get(app.url_path_for("compute:download_iou_image", filename=file_path))
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
async def test_iou_duplicate(app: FastAPI, client: AsyncClient, vm: dict, base_params: dict) -> None:
|
||||
async def test_iou_duplicate(app: FastAPI, compute_client: AsyncClient, vm: dict, base_params: dict) -> None:
|
||||
|
||||
# create destination node first
|
||||
response = await client.post(app.url_path_for("create_iou_node", project_id=vm["project_id"]), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_iou_node", project_id=vm["project_id"]), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
params = {"destination_node_id": response.json()["node_id"]}
|
||||
|
||||
response = await client.post(app.url_path_for("duplicate_iou_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:duplicate_iou_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
@ -27,35 +27,35 @@ pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
async def vm(app: FastAPI, client: AsyncClient, compute_project: Project, ubridge_path: str, on_gns3vm) -> dict:
|
||||
async def vm(app: FastAPI, compute_client: AsyncClient, compute_project: Project, ubridge_path: str, on_gns3vm) -> dict:
|
||||
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat._start_ubridge"):
|
||||
response = await client.post(app.url_path_for("create_nat_node", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_nat_node", project_id=compute_project.id),
|
||||
json={"name": "Nat 1"})
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
return response.json()
|
||||
|
||||
|
||||
async def test_nat_create(app: FastAPI, client: AsyncClient, compute_project: Project, on_gns3vm) -> None:
|
||||
async def test_nat_create(app: FastAPI, compute_client: AsyncClient, compute_project: Project, on_gns3vm) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat._start_ubridge"):
|
||||
response = await client.post(app.url_path_for("create_nat_node", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_nat_node", project_id=compute_project.id),
|
||||
json={"name": "Nat 1"})
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "Nat 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
|
||||
|
||||
async def test_nat_get(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_nat_get(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_nat_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_nat_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["name"] == "Nat 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
assert response.json()["status"] == "started"
|
||||
|
||||
|
||||
async def test_nat_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_nat_nio_create_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -64,19 +64,19 @@ async def test_nat_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict) -
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_nat_node_nio",
|
||||
url = app.url_path_for("compute:create_nat_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.add_nio"):
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_nat_nio_update_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_nat_nio_update_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -85,26 +85,26 @@ async def test_nat_nio_update_udp(app: FastAPI, client: AsyncClient, vm: dict) -
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_nat_node_nio",
|
||||
url = app.url_path_for("compute:create_nat_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
params["filters"] = {}
|
||||
|
||||
url = app.url_path_for("update_nat_node_nio",
|
||||
url = app.url_path_for("compute:update_nat_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
response = await client.put(url, json=params)
|
||||
response = await compute_client.put(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_nat_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_nat_delete_nio(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -113,72 +113,72 @@ async def test_nat_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> No
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_nat_node_nio",
|
||||
url = app.url_path_for("compute:create_nat_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.add_nio"):
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
|
||||
url = app.url_path_for("delete_nat_node_nio",
|
||||
url = app.url_path_for("compute:delete_nat_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.remove_nio") as mock:
|
||||
response = await client.delete(url)
|
||||
response = await compute_client.delete(url)
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_nat_delete(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_nat_delete(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
response = await client.delete(app.url_path_for("delete_nat_node",
|
||||
response = await compute_client.delete(app.url_path_for("compute:delete_nat_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_nat_update(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_nat_update(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
response = await client.put(app.url_path_for("update_nat_node",
|
||||
response = await compute_client.put(app.url_path_for("compute:update_nat_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json={"name": "test"})
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["name"] == "test"
|
||||
|
||||
|
||||
async def test_nat_start_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_nat_start_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"capture_file_name": "test.pcap",
|
||||
"data_link_type": "DLT_EN10MB"
|
||||
}
|
||||
|
||||
url = app.url_path_for("start_nat_node_capture",
|
||||
url = app.url_path_for("compute:start_nat_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.start_capture") as mock:
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert mock.called
|
||||
assert "test.pcap" in response.json()["pcap_file_path"]
|
||||
|
||||
|
||||
async def test_nat_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_nat_stop_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("stop_nat_node_capture",
|
||||
url = app.url_path_for("compute:stop_nat_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.stop_capture") as mock:
|
||||
response = await client.post(url)
|
||||
response = await compute_client.post(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
@ -188,5 +188,5 @@ async def test_nat_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) ->
|
||||
#
|
||||
# with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.get_nio"):
|
||||
# with asyncio_patch("gns3server.compute.builtin.Builtin.stream_pcap_file"):
|
||||
# response = await client.get("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# response = await compute_client.get("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# assert response.status_code == status.HTTP_200_OK
|
||||
|
@ -42,40 +42,40 @@ def base_params(tmpdir) -> dict:
|
||||
return params
|
||||
|
||||
|
||||
async def test_create_project_with_path(app: FastAPI, client: AsyncClient, base_params: dict) -> None:
|
||||
async def test_create_project_with_path(app: FastAPI, compute_client: AsyncClient, base_params: dict) -> None:
|
||||
|
||||
with patch("gns3server.compute.project.Project.is_local", return_value=True):
|
||||
response = await client.post(app.url_path_for("create_compute_project"), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_compute_project"), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["project_id"] == base_params["project_id"]
|
||||
|
||||
|
||||
async def test_create_project_with_path_and_empty_variables(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
base_params: dict) -> None:
|
||||
|
||||
base_params["variables"] = None
|
||||
with patch("gns3server.compute.project.Project.is_local", return_value=True):
|
||||
|
||||
response = await client.post(app.url_path_for("create_compute_project"), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_compute_project"), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["project_id"] == base_params["project_id"]
|
||||
|
||||
|
||||
async def test_create_project_without_dir(app: FastAPI, client: AsyncClient, base_params: dict) -> None:
|
||||
async def test_create_project_without_dir(app: FastAPI, compute_client: AsyncClient, base_params: dict) -> None:
|
||||
|
||||
del base_params["path"]
|
||||
response = await client.post(app.url_path_for("create_compute_project"), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_compute_project"), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["project_id"] == base_params["project_id"]
|
||||
assert response.json()["name"] == base_params["name"]
|
||||
|
||||
|
||||
async def test_show_project(app: FastAPI, client: AsyncClient, base_params: dict) -> None:
|
||||
async def test_show_project(app: FastAPI, compute_client: AsyncClient, base_params: dict) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("create_compute_project"), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_compute_project"), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
response = await client.get(app.url_path_for("get_compute_project", project_id=base_params["project_id"]))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_compute_project", project_id=base_params["project_id"]))
|
||||
|
||||
#print(response.json().keys())
|
||||
#assert len(response.json().keys()) == 3
|
||||
@ -84,60 +84,60 @@ async def test_show_project(app: FastAPI, client: AsyncClient, base_params: dict
|
||||
assert response.json()["variables"] is None
|
||||
|
||||
|
||||
async def test_show_project_invalid_uuid(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_show_project_invalid_uuid(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_compute_project",
|
||||
response = await compute_client.get(app.url_path_for("compute:get_compute_project",
|
||||
project_id="50010203-0405-0607-0809-0a0b0c0d0e42"))
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
|
||||
async def test_list_projects(app: FastAPI, client: AsyncClient) -> dict:
|
||||
async def test_list_projects(app: FastAPI, compute_client: AsyncClient) -> dict:
|
||||
|
||||
ProjectManager.instance()._projects = {}
|
||||
|
||||
params = {"name": "test", "project_id": "51010203-0405-0607-0809-0a0b0c0d0e0f"}
|
||||
response = await client.post(app.url_path_for("create_compute_project"), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_compute_project"), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
params = {"name": "test", "project_id": "52010203-0405-0607-0809-0a0b0c0d0e0b"}
|
||||
response = await client.post(app.url_path_for("create_compute_project"), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_compute_project"), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
response = await client.get(app.url_path_for("get_compute_projects"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_compute_projects"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert len(response.json()) == 2
|
||||
assert "51010203-0405-0607-0809-0a0b0c0d0e0f" in [p["project_id"] for p in response.json()]
|
||||
|
||||
|
||||
async def test_delete_project(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def test_delete_project(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.project.Project.delete", return_value=True) as mock:
|
||||
response = await client.delete(app.url_path_for("delete_compute_project", project_id=compute_project.id))
|
||||
response = await compute_client.delete(app.url_path_for("compute:delete_compute_project", project_id=compute_project.id))
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
|
||||
async def test_update_project(app: FastAPI, client: AsyncClient, base_params: dict) -> None:
|
||||
async def test_update_project(app: FastAPI, compute_client: AsyncClient, base_params: dict) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("create_compute_project"), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_compute_project"), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
params = {"variables": [{"name": "TEST1", "value": "VAL1"}]}
|
||||
response = await client.put(app.url_path_for("update_compute_project", project_id=base_params["project_id"]),
|
||||
response = await compute_client.put(app.url_path_for("compute:update_compute_project", project_id=base_params["project_id"]),
|
||||
json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["variables"] == [{"name": "TEST1", "value": "VAL1"}]
|
||||
|
||||
|
||||
async def test_delete_project_invalid_uuid(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_delete_project_invalid_uuid(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
response = await client.delete(app.url_path_for("delete_compute_project", project_id=str(uuid.uuid4())))
|
||||
response = await compute_client.delete(app.url_path_for("compute:delete_compute_project", project_id=str(uuid.uuid4())))
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
|
||||
async def test_close_project(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def test_close_project(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.project.Project.close", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("close_compute_project", project_id=compute_project.id))
|
||||
response = await compute_client.post(app.url_path_for("compute:close_compute_project", project_id=compute_project.id))
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
@ -147,18 +147,18 @@ async def test_close_project(app: FastAPI, client: AsyncClient, compute_project:
|
||||
#
|
||||
# ProjectHandler._notifications_listening = {compute_project.id: 2}
|
||||
# with asyncio_patch("gns3server.compute.project.Project.close", return_value=True) as mock:
|
||||
# response = await client.post("/projects/{project_id}/close".format(project_id=compute_project.id))
|
||||
# response = await compute_client.post("/projects/{project_id}/close".format(project_id=compute_project.id))
|
||||
# assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
# assert not mock.called
|
||||
|
||||
|
||||
async def test_close_project_invalid_uuid(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_close_project_invalid_uuid(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("close_compute_project", project_id=str(uuid.uuid4())))
|
||||
response = await compute_client.post(app.url_path_for("compute:close_compute_project", project_id=str(uuid.uuid4())))
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
|
||||
async def test_get_file(app: FastAPI, client: AsyncClient, config, tmpdir) -> None:
|
||||
async def test_get_file(app: FastAPI, compute_client: AsyncClient, config, tmpdir) -> None:
|
||||
|
||||
config.settings.Server.projects_path = str(tmpdir)
|
||||
project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b")
|
||||
@ -166,27 +166,27 @@ async def test_get_file(app: FastAPI, client: AsyncClient, config, tmpdir) -> No
|
||||
with open(os.path.join(project.path, "hello"), "w+") as f:
|
||||
f.write("world")
|
||||
|
||||
response = await client.get(app.url_path_for("get_compute_project_file", project_id=project.id, file_path="hello"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_compute_project_file", project_id=project.id, file_path="hello"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.content == b"world"
|
||||
|
||||
response = await client.get(app.url_path_for("get_compute_project_file", project_id=project.id, file_path="false"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_compute_project_file", project_id=project.id, file_path="false"))
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
response = await client.get(app.url_path_for("get_compute_project_file",
|
||||
response = await compute_client.get(app.url_path_for("compute:get_compute_project_file",
|
||||
project_id=project.id,
|
||||
file_path="../hello"))
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
|
||||
async def test_get_file_forbidden_location(app: FastAPI, client: AsyncClient, config, tmpdir) -> None:
|
||||
async def test_get_file_forbidden_location(app: FastAPI, compute_client: AsyncClient, config, tmpdir) -> None:
|
||||
|
||||
config.settings.Server.projects_path = str(tmpdir)
|
||||
project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b")
|
||||
file_path = "foo/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"
|
||||
response = await client.get(
|
||||
response = await compute_client.get(
|
||||
app.url_path_for(
|
||||
"get_compute_project_file",
|
||||
"compute:get_compute_project_file",
|
||||
project_id=project.id,
|
||||
file_path=file_path
|
||||
)
|
||||
@ -194,12 +194,12 @@ async def test_get_file_forbidden_location(app: FastAPI, client: AsyncClient, co
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
async def test_write_file(app: FastAPI, client: AsyncClient, config, tmpdir) -> None:
|
||||
async def test_write_file(app: FastAPI, compute_client: AsyncClient, config, tmpdir) -> None:
|
||||
|
||||
config.settings.Server.projects_path = str(tmpdir)
|
||||
project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b")
|
||||
|
||||
response = await client.post(app.url_path_for("write_compute_project_file",
|
||||
response = await compute_client.post(app.url_path_for("compute:write_compute_project_file",
|
||||
project_id=project.id,
|
||||
file_path="hello"), content=b"world")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
@ -207,19 +207,19 @@ async def test_write_file(app: FastAPI, client: AsyncClient, config, tmpdir) ->
|
||||
with open(os.path.join(project.path, "hello")) as f:
|
||||
assert f.read() == "world"
|
||||
|
||||
response = await client.post(app.url_path_for("write_compute_project_file",
|
||||
response = await compute_client.post(app.url_path_for("compute:write_compute_project_file",
|
||||
project_id=project.id,
|
||||
file_path="../hello"))
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
|
||||
async def test_write_file_forbidden_location(app: FastAPI, client: AsyncClient, config, tmpdir) -> None:
|
||||
async def test_write_file_forbidden_location(app: FastAPI, compute_client: AsyncClient, config, tmpdir) -> None:
|
||||
|
||||
config.settings.Server.projects_path = str(tmpdir)
|
||||
project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b")
|
||||
|
||||
file_path = "%2e%2e/hello"
|
||||
response = await client.post(app.url_path_for("write_compute_project_file",
|
||||
response = await compute_client.post(app.url_path_for("compute:write_compute_project_file",
|
||||
project_id=project.id,
|
||||
file_path=file_path), content=b"world")
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
@ -64,20 +64,20 @@ def base_params(tmpdir, fake_qemu_bin) -> dict:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def vm(app: FastAPI, client: AsyncClient, compute_project: Project, base_params: dict) -> None:
|
||||
async def vm(app: FastAPI, compute_client: AsyncClient, compute_project: Project, base_params: dict) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("create_qemu_node", project_id=compute_project.id), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
return response.json()
|
||||
|
||||
|
||||
async def test_qemu_create(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project,
|
||||
base_params: dict,
|
||||
fake_qemu_bin: str) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("create_qemu_node", project_id=compute_project.id), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
@ -86,14 +86,14 @@ async def test_qemu_create(app: FastAPI,
|
||||
|
||||
|
||||
async def test_qemu_create_platform(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project,
|
||||
base_params: dict,
|
||||
fake_qemu_bin: str):
|
||||
|
||||
base_params["qemu_path"] = None
|
||||
base_params["platform"] = "x86_64"
|
||||
response = await client.post(app.url_path_for("create_qemu_node", project_id=compute_project.id), json=base_params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=base_params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
@ -103,7 +103,7 @@ async def test_qemu_create_platform(app: FastAPI,
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_qemu_create_with_params(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project,
|
||||
base_params: dict,
|
||||
fake_qemu_vm: str):
|
||||
@ -111,7 +111,7 @@ async def test_qemu_create_with_params(app: FastAPI,
|
||||
params = base_params
|
||||
params["ram"] = 1024
|
||||
params["hda_disk_image"] = "linux载.img"
|
||||
response = await client.post(app.url_path_for("create_qemu_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
@ -122,26 +122,26 @@ async def test_qemu_create_with_params(app: FastAPI,
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
|
||||
async def test_qemu_create_with_project_file(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project,
|
||||
base_params: dict,
|
||||
fake_qemu_vm: str) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("write_compute_project_file",
|
||||
response = await compute_client.post(app.url_path_for("compute:write_compute_project_file",
|
||||
project_id=compute_project.id,
|
||||
file_path="hello.img"), content=b"world")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
params = base_params
|
||||
params["hda_disk_image"] = "hello.img"
|
||||
response = await client.post(app.url_path_for("create_qemu_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["hda_disk_image"] == "hello.img"
|
||||
assert response.json()["hda_disk_image_md5sum"] == "7d793037a0760186574b0282f2f435e7"
|
||||
|
||||
|
||||
async def test_qemu_get(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict):
|
||||
async def test_qemu_get(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict):
|
||||
|
||||
response = await client.get(app.url_path_for("get_qemu_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_qemu_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
@ -151,60 +151,60 @@ async def test_qemu_get(app: FastAPI, client: AsyncClient, compute_project: Proj
|
||||
vm["node_id"])
|
||||
|
||||
|
||||
async def test_qemu_start(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_start(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.start", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("start_qemu_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:start_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_qemu_stop(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_stop(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.stop", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("stop_qemu_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:stop_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_qemu_reload(app: FastAPI, client: AsyncClient, vm) -> None:
|
||||
async def test_qemu_reload(app: FastAPI, compute_client: AsyncClient, vm) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.reload", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("reload_qemu_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:reload_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_qemu_suspend(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_suspend(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.suspend", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("suspend_qemu_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:suspend_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_qemu_resume(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_resume(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.resume", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("resume_qemu_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:resume_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_qemu_delete(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_delete(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.Qemu.delete_node", return_value=True) as mock:
|
||||
response = await client.delete(app.url_path_for("delete_qemu_node",
|
||||
response = await compute_client.delete(app.url_path_for("compute:delete_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
@ -212,7 +212,7 @@ async def test_qemu_delete(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
|
||||
async def test_qemu_update(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
vm: dict,
|
||||
free_console_port: int,
|
||||
fake_qemu_vm: str) -> None:
|
||||
@ -224,7 +224,7 @@ async def test_qemu_update(app: FastAPI,
|
||||
"hdb_disk_image": "linux载.img"
|
||||
}
|
||||
|
||||
response = await client.put(app.url_path_for("update_qemu_node",
|
||||
response = await compute_client.put(app.url_path_for("compute:update_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
@ -234,7 +234,7 @@ async def test_qemu_update(app: FastAPI,
|
||||
assert response.json()["ram"] == 1024
|
||||
|
||||
|
||||
async def test_qemu_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_nio_create_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -244,21 +244,21 @@ async def test_qemu_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.add_ubridge_udp_connection"):
|
||||
await client.put(app.url_path_for("update_qemu_node",
|
||||
await compute_client.put(app.url_path_for("compute:update_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json={"adapters": 2})
|
||||
|
||||
url = app.url_path_for("create_qemu_node_nio",
|
||||
url = app.url_path_for("compute:create_qemu_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_qemu_nio_update_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_nio_update_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -267,31 +267,31 @@ async def test_qemu_nio_update_udp(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
await client.put(app.url_path_for("update_qemu_node",
|
||||
await compute_client.put(app.url_path_for("compute:update_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json={"adapters": 2})
|
||||
|
||||
url = app.url_path_for("create_qemu_node_nio",
|
||||
url = app.url_path_for("compute:create_qemu_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
|
||||
params["filters"] = {}
|
||||
|
||||
url = app.url_path_for("update_qemu_node_nio",
|
||||
url = app.url_path_for("compute:update_qemu_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
response = await client.put(url, json=params)
|
||||
response = await compute_client.put(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_qemu_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_delete_nio(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -301,39 +301,39 @@ async def test_qemu_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> N
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM._ubridge_send"):
|
||||
await client.put(app.url_path_for("update_qemu_node",
|
||||
await compute_client.put(app.url_path_for("compute:update_qemu_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json={"adapters": 2})
|
||||
|
||||
url = app.url_path_for("create_qemu_node_nio",
|
||||
url = app.url_path_for("compute:create_qemu_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
|
||||
url = app.url_path_for("delete_qemu_node_nio",
|
||||
url = app.url_path_for("compute:delete_qemu_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="1",
|
||||
port_number="0")
|
||||
response = await client.delete(url)
|
||||
response = await compute_client.delete(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_qemu_list_binaries(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_qemu_list_binaries(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
ret = [{"path": "/tmp/1", "version": "2.2.0"},
|
||||
{"path": "/tmp/2", "version": "2.1.0"}]
|
||||
|
||||
with asyncio_patch("gns3server.compute.qemu.Qemu.binary_list", return_value=ret) as mock:
|
||||
response = await client.get(app.url_path_for("get_qemu_binaries"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_qemu_binaries"))
|
||||
assert mock.called_with(None)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == ret
|
||||
|
||||
|
||||
# async def test_qemu_list_binaries_filter(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
# async def test_qemu_list_binaries_filter(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
#
|
||||
# ret = [
|
||||
# {"path": "/tmp/x86_64", "version": "2.2.0"},
|
||||
@ -342,25 +342,25 @@ async def test_qemu_list_binaries(app: FastAPI, client: AsyncClient, vm: dict) -
|
||||
# ]
|
||||
#
|
||||
# with asyncio_patch("gns3server.compute.qemu.Qemu.binary_list", return_value=ret) as mock:
|
||||
# response = await client.get(app.url_path_for("get_qemu_binaries"),
|
||||
# response = await compute_client.get(app.url_path_for("compute:get_qemu_binaries"),
|
||||
# json={"archs": ["i386"]})
|
||||
# assert response.status_code == status.HTTP_200_OK
|
||||
# assert mock.called_with(["i386"])
|
||||
# assert response.json() == ret
|
||||
|
||||
|
||||
async def test_images(app: FastAPI, client: AsyncClient, fake_qemu_vm) -> None:
|
||||
async def test_images(app: FastAPI, compute_client: AsyncClient, fake_qemu_vm) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_qemu_images"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_qemu_images"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert {"filename": "linux载.img", "path": "linux载.img", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1} in response.json()
|
||||
|
||||
|
||||
async def test_upload_image(app: FastAPI, client: AsyncClient, tmpdir: str) -> None:
|
||||
async def test_upload_image(app: FastAPI, compute_client: AsyncClient, tmpdir: str) -> None:
|
||||
|
||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)):
|
||||
|
||||
response = await client.post(app.url_path_for("upload_qemu_image",
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_qemu_image",
|
||||
filename="test2使"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
@ -372,11 +372,11 @@ async def test_upload_image(app: FastAPI, client: AsyncClient, tmpdir: str) -> N
|
||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||
|
||||
|
||||
async def test_upload_image_ova(app: FastAPI, client: AsyncClient, tmpdir:str) -> None:
|
||||
async def test_upload_image_ova(app: FastAPI, compute_client: AsyncClient, tmpdir:str) -> None:
|
||||
|
||||
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)):
|
||||
|
||||
response = await client.post(app.url_path_for("upload_qemu_image",
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_qemu_image",
|
||||
filename="test2.ova/test2.vmdk"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
@ -388,42 +388,42 @@ async def test_upload_image_ova(app: FastAPI, client: AsyncClient, tmpdir:str) -
|
||||
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
|
||||
|
||||
|
||||
async def test_upload_image_forbidden_location(app: FastAPI, client: AsyncClient, tmpdir: str) -> None:
|
||||
async def test_upload_image_forbidden_location(app: FastAPI, compute_client: AsyncClient, tmpdir: str) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("upload_qemu_image",
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_qemu_image",
|
||||
filename="/qemu/images/../../test2"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
async def test_download_image(app: FastAPI, client: AsyncClient, images_dir: str) -> None:
|
||||
async def test_download_image(app: FastAPI, compute_client: AsyncClient, images_dir: str) -> None:
|
||||
|
||||
response = await client.post(app.url_path_for("upload_qemu_image", filename="test3"), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_qemu_image", filename="test3"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
response = await client.get(app.url_path_for("download_qemu_image", filename="test3"))
|
||||
response = await compute_client.get(app.url_path_for("compute:download_qemu_image", filename="test3"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
|
||||
|
||||
async def test_download_image_forbidden_location(app: FastAPI, client: AsyncClient, tmpdir) -> None:
|
||||
async def test_download_image_forbidden_location(app: FastAPI, compute_client: AsyncClient, tmpdir) -> None:
|
||||
|
||||
file_path = "foo/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"
|
||||
response = await client.get(app.url_path_for("download_qemu_image", filename=file_path))
|
||||
response = await compute_client.get(app.url_path_for("compute:download_qemu_image", filename=file_path))
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
@pytest.mark.skipif(not sys.platform.startswith("win") and os.getuid() == 0, reason="Root can delete any image")
|
||||
async def test_upload_image_permission_denied(app: FastAPI, client: AsyncClient, images_dir: str) -> None:
|
||||
async def test_upload_image_permission_denied(app: FastAPI, compute_client: AsyncClient, images_dir: str) -> None:
|
||||
|
||||
with open(os.path.join(images_dir, "QEMU", "test2.tmp"), "w+") as f:
|
||||
f.write("")
|
||||
os.chmod(os.path.join(images_dir, "QEMU", "test2.tmp"), 0)
|
||||
|
||||
response = await client.post(app.url_path_for("upload_qemu_image", filename="test2"), content=b"TEST")
|
||||
response = await compute_client.post(app.url_path_for("compute:upload_qemu_image", filename="test2"), content=b"TEST")
|
||||
assert response.status_code == status.HTTP_409_CONFLICT
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_img_relative(app: FastAPI, client: AsyncClient):
|
||||
async def test_create_img_relative(app: FastAPI, compute_client: AsyncClient):
|
||||
|
||||
params = {
|
||||
"qemu_img": "/tmp/qemu-img",
|
||||
@ -436,11 +436,11 @@ async def test_create_img_relative(app: FastAPI, client: AsyncClient):
|
||||
"size": 100
|
||||
}
|
||||
with asyncio_patch("gns3server.compute.Qemu.create_disk"):
|
||||
response = await client.post(app.url_path_for("create_qemu_image"), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_image"), json=params)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_create_img_absolute_non_local(app: FastAPI, client: AsyncClient, config) -> None:
|
||||
async def test_create_img_absolute_non_local(app: FastAPI, compute_client: AsyncClient, config) -> None:
|
||||
|
||||
config.settings.Server.local = False
|
||||
params = {
|
||||
@ -454,11 +454,11 @@ async def test_create_img_absolute_non_local(app: FastAPI, client: AsyncClient,
|
||||
"size": 100
|
||||
}
|
||||
with asyncio_patch("gns3server.compute.Qemu.create_disk"):
|
||||
response = await client.post(app.url_path_for("create_qemu_image"), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_image"), json=params)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
async def test_create_img_absolute_local(app: FastAPI, client: AsyncClient, config) -> None:
|
||||
async def test_create_img_absolute_local(app: FastAPI, compute_client: AsyncClient, config) -> None:
|
||||
|
||||
params = {
|
||||
"qemu_img": "/tmp/qemu-img",
|
||||
@ -471,43 +471,43 @@ async def test_create_img_absolute_local(app: FastAPI, client: AsyncClient, conf
|
||||
"size": 100
|
||||
}
|
||||
with asyncio_patch("gns3server.compute.Qemu.create_disk"):
|
||||
response = await client.post(app.url_path_for("create_qemu_image"), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_image"), json=params)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_capabilities(app: FastAPI, client: AsyncClient) -> None:
|
||||
async def test_capabilities(app: FastAPI, compute_client: AsyncClient) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.Qemu.get_kvm_archs", return_value=["x86_64"]):
|
||||
response = await client.get(app.url_path_for("get_qemu_capabilities"))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_qemu_capabilities"))
|
||||
assert response.json()["kvm"] == ["x86_64"]
|
||||
|
||||
|
||||
async def test_qemu_duplicate(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project,
|
||||
vm: dict,
|
||||
base_params: dict) -> None:
|
||||
|
||||
# create destination node first
|
||||
response = await client.post(app.url_path_for("create_qemu_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:create_qemu_node",
|
||||
project_id=vm["project_id"]), json=base_params)
|
||||
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
params = {"destination_node_id": response.json()["node_id"]}
|
||||
response = await client.post(app.url_path_for("duplicate_qemu_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:duplicate_qemu_node",
|
||||
project_id=vm["project_id"], node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_qemu_start_capture(app: FastAPI, client: AsyncClient, vm):
|
||||
async def test_qemu_start_capture(app: FastAPI, compute_client: AsyncClient, vm):
|
||||
|
||||
params = {
|
||||
"capture_file_name": "test.pcap",
|
||||
"data_link_type": "DLT_EN10MB"
|
||||
}
|
||||
|
||||
url = app.url_path_for("start_qemu_node_capture",
|
||||
url = app.url_path_for("compute:start_qemu_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -515,16 +515,16 @@ async def test_qemu_start_capture(app: FastAPI, client: AsyncClient, vm):
|
||||
|
||||
with patch("gns3server.compute.qemu.qemu_vm.QemuVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.start_capture") as mock:
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert mock.called
|
||||
assert "test.pcap" in response.json()["pcap_file_path"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_qemu_stop_capture(app: FastAPI, client: AsyncClient, vm):
|
||||
async def test_qemu_stop_capture(app: FastAPI, compute_client: AsyncClient, vm):
|
||||
|
||||
url = app.url_path_for("stop_qemu_node_capture",
|
||||
url = app.url_path_for("compute:stop_qemu_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -532,15 +532,15 @@ async def test_qemu_stop_capture(app: FastAPI, client: AsyncClient, vm):
|
||||
|
||||
with patch("gns3server.compute.qemu.qemu_vm.QemuVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.stop_capture") as mock:
|
||||
response = await client.post(url)
|
||||
response = await compute_client.post(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_qemu_pcap(app: FastAPI, client: AsyncClient, vm, compute_project):
|
||||
# async def test_qemu_pcap(app: FastAPI, compute_client: AsyncClient, vm, compute_project):
|
||||
#
|
||||
# with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.get_nio"):
|
||||
# with asyncio_patch("gns3server.compute.qemu.Qemu.stream_pcap_file"):
|
||||
# response = await client.get("/projects/{project_id}/qemu/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# response = await compute_client.get("/projects/{project_id}/qemu/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# assert response.status_code == status.HTTP_200_OK
|
||||
|
@ -28,7 +28,7 @@ pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
async def vm(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def vm(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
vboxmanage_path = "/fake/VboxManage"
|
||||
params = {
|
||||
@ -38,7 +38,7 @@ async def vm(app: FastAPI, client: AsyncClient, compute_project: Project) -> Non
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.create", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("create_virtualbox_node", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_virtualbox_node", project_id=compute_project.id),
|
||||
json=params)
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
@ -47,7 +47,7 @@ async def vm(app: FastAPI, client: AsyncClient, compute_project: Project) -> Non
|
||||
return response.json()
|
||||
|
||||
|
||||
async def test_vbox_create(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def test_vbox_create(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
params = {
|
||||
"name": "VM1",
|
||||
@ -56,16 +56,16 @@ async def test_vbox_create(app: FastAPI, client: AsyncClient, compute_project: P
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.create", return_value=True):
|
||||
response = await client.post(app.url_path_for("create_virtualbox_node", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_virtualbox_node", project_id=compute_project.id),
|
||||
json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "VM1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
|
||||
|
||||
async def test_vbox_get(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_vbox_get(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_virtualbox_node",
|
||||
response = await compute_client.get(app.url_path_for("compute:get_virtualbox_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
@ -73,58 +73,58 @@ async def test_vbox_get(app: FastAPI, client: AsyncClient, compute_project: Proj
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
|
||||
|
||||
async def test_vbox_start(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vbox_start(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.start", return_value=True) as mock:
|
||||
|
||||
response = await client.post(app.url_path_for("start_virtualbox_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:start_virtualbox_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vbox_stop(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vbox_stop(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.stop", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("stop_virtualbox_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:stop_virtualbox_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vbox_suspend(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vbox_suspend(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.suspend", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("suspend_virtualbox_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:suspend_virtualbox_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vbox_resume(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vbox_resume(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.resume", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("resume_virtualbox_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:resume_virtualbox_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vbox_reload(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vbox_reload(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.reload", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("reload_virtualbox_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:reload_virtualbox_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vbox_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vbox_nio_create_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -133,14 +133,14 @@ async def test_vbox_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_virtualbox_node_nio",
|
||||
url = app.url_path_for("compute:create_virtualbox_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_add_nio_binding') as mock:
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert mock.called
|
||||
args, kwgars = mock.call_args
|
||||
assert args[0] == 0
|
||||
@ -150,7 +150,7 @@ async def test_vbox_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_vbox_nio_update_udp(app: FastAPI, client: AsyncClient, vm):
|
||||
# async def test_vbox_nio_update_udp(app: FastAPI, compute_client: AsyncClient, vm):
|
||||
#
|
||||
# params = {
|
||||
# "type": "nio_udp",
|
||||
@ -162,22 +162,22 @@ async def test_vbox_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
#
|
||||
# with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.ethernet_adapters'):
|
||||
# with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_remove_nio_binding'):
|
||||
# response = await client.put("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
|
||||
# response = await compute_client.put("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
|
||||
#
|
||||
# assert response.status_code == status.HTTP_201_CREATED
|
||||
# assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_vbox_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vbox_delete_nio(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("delete_virtualbox_node_nio",
|
||||
url = app.url_path_for("compute:delete_virtualbox_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_remove_nio_binding') as mock:
|
||||
response = await client.delete(url)
|
||||
response = await compute_client.delete(url)
|
||||
assert mock.called
|
||||
args, kwgars = mock.call_args
|
||||
assert args[0] == 0
|
||||
@ -185,14 +185,14 @@ async def test_vbox_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> N
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_vbox_update(app: FastAPI, client: AsyncClient, vm, free_console_port):
|
||||
async def test_vbox_update(app: FastAPI, compute_client: AsyncClient, vm, free_console_port):
|
||||
|
||||
params = {
|
||||
"name": "test",
|
||||
"console": free_console_port
|
||||
}
|
||||
|
||||
response = await client.put(app.url_path_for("update_virtualbox_node",
|
||||
response = await compute_client.put(app.url_path_for("compute:update_virtualbox_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
@ -201,14 +201,14 @@ async def test_vbox_update(app: FastAPI, client: AsyncClient, vm, free_console_p
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_virtualbox_start_capture(app: FastAPI, client: AsyncClient, vm):
|
||||
async def test_virtualbox_start_capture(app: FastAPI, compute_client: AsyncClient, vm):
|
||||
|
||||
params = {
|
||||
"capture_file_name": "test.pcap",
|
||||
"data_link_type": "DLT_EN10MB"
|
||||
}
|
||||
|
||||
url = app.url_path_for("start_virtualbox_node_capture",
|
||||
url = app.url_path_for("compute:start_virtualbox_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -216,16 +216,16 @@ async def test_virtualbox_start_capture(app: FastAPI, client: AsyncClient, vm):
|
||||
|
||||
with patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.start_capture") as mock:
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert mock.called
|
||||
assert "test.pcap" in response.json()["pcap_file_path"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_virtualbox_stop_capture(app: FastAPI, client: AsyncClient, vm):
|
||||
async def test_virtualbox_stop_capture(app: FastAPI, compute_client: AsyncClient, vm):
|
||||
|
||||
url = app.url_path_for("stop_virtualbox_node_capture",
|
||||
url = app.url_path_for("compute:stop_virtualbox_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -233,15 +233,15 @@ async def test_virtualbox_stop_capture(app: FastAPI, client: AsyncClient, vm):
|
||||
|
||||
with patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.stop_capture") as mock:
|
||||
response = await client.post(url)
|
||||
response = await compute_client.post(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_virtualbox_pcap(app: FastAPI, client: AsyncClient, vm, compute_project):
|
||||
# async def test_virtualbox_pcap(app: FastAPI, compute_client: AsyncClient, vm, compute_project):
|
||||
#
|
||||
# with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.get_nio"):
|
||||
# with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.stream_pcap_file"):
|
||||
# response = await client.get("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# response = await compute_client.get("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# assert response.status_code == status.HTTP_200_OK
|
||||
|
@ -28,7 +28,7 @@ pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
async def vm(app: FastAPI, client: AsyncClient, compute_project: Project, vmx_path: str) -> dict:
|
||||
async def vm(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vmx_path: str) -> dict:
|
||||
|
||||
params = {
|
||||
"name": "VMTEST",
|
||||
@ -37,7 +37,7 @@ async def vm(app: FastAPI, client: AsyncClient, compute_project: Project, vmx_pa
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.create", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("create_vmware_node", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_vmware_node", project_id=compute_project.id),
|
||||
json=params)
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
@ -56,7 +56,7 @@ def vmx_path(tmpdir: str) -> str:
|
||||
return path
|
||||
|
||||
|
||||
async def test_vmware_create(app: FastAPI, client: AsyncClient, compute_project: Project, vmx_path: str) -> None:
|
||||
async def test_vmware_create(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vmx_path: str) -> None:
|
||||
|
||||
params = {
|
||||
"name": "VM1",
|
||||
@ -65,72 +65,72 @@ async def test_vmware_create(app: FastAPI, client: AsyncClient, compute_project:
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.create", return_value=True):
|
||||
response = await client.post(app.url_path_for("create_vmware_node", project_id=compute_project.id),
|
||||
response = await compute_client.post(app.url_path_for("compute:create_vmware_node", project_id=compute_project.id),
|
||||
json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "VM1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
|
||||
|
||||
async def test_vmware_get(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_vmware_get(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_vmware_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_vmware_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["name"] == "VMTEST"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
|
||||
|
||||
async def test_vmware_start(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_start(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.start", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("start_vmware_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:start_vmware_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vmware_stop(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_stop(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.stop", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("stop_vmware_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:stop_vmware_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vmware_suspend(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_suspend(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.suspend", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("suspend_vmware_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:suspend_vmware_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vmware_resume(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_resume(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.resume", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("resume_vmware_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:resume_vmware_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vmware_reload(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_reload(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.reload", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("reload_vmware_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:reload_vmware_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vmware_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_nio_create_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -139,14 +139,14 @@ async def test_vmware_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_vmware_node_nio",
|
||||
url = app.url_path_for("compute:create_vmware_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM.adapter_add_nio_binding') as mock:
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert mock.called
|
||||
args, kwgars = mock.call_args
|
||||
assert args[0] == 0
|
||||
@ -156,7 +156,7 @@ async def test_vmware_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict
|
||||
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_vmware_nio_update_udp(app: FastAPI, client: AsyncClient, vm):
|
||||
# async def test_vmware_nio_update_udp(app: FastAPI, compute_client: AsyncClient, vm):
|
||||
#
|
||||
# params = {
|
||||
# "type": "nio_udp",
|
||||
@ -169,21 +169,21 @@ async def test_vmware_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict
|
||||
# with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM._ubridge_send'):
|
||||
# with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM.ethernet_adapters'):
|
||||
# with patch('gns3server.compute.vmware.vmware_vm.VMwareVM._get_vnet') as mock:
|
||||
# response = await client.put("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
|
||||
# response = await compute_client.put("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
|
||||
# assert response.status_code == status.HTTP_201_CREATED
|
||||
# assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_vmware_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_delete_nio(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("delete_vmware_node_nio",
|
||||
url = app.url_path_for("compute:delete_vmware_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM.adapter_remove_nio_binding') as mock:
|
||||
response = await client.delete(url)
|
||||
response = await compute_client.delete(url)
|
||||
assert mock.called
|
||||
args, kwgars = mock.call_args
|
||||
assert args[0] == 0
|
||||
@ -191,14 +191,14 @@ async def test_vmware_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) ->
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vmware_update(app: FastAPI, client: AsyncClient, vm: dict, free_console_port: int) -> None:
|
||||
async def test_vmware_update(app: FastAPI, compute_client: AsyncClient, vm: dict, free_console_port: int) -> None:
|
||||
|
||||
params = {
|
||||
"name": "test",
|
||||
"console": free_console_port
|
||||
}
|
||||
|
||||
response = await client.put(app.url_path_for("update_vmware_node",
|
||||
response = await compute_client.put(app.url_path_for("compute:update_vmware_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
@ -206,14 +206,14 @@ async def test_vmware_update(app: FastAPI, client: AsyncClient, vm: dict, free_c
|
||||
assert response.json()["console"] == free_console_port
|
||||
|
||||
|
||||
async def test_vmware_start_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_start_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"capture_file_name": "test.pcap",
|
||||
"data_link_type": "DLT_EN10MB"
|
||||
}
|
||||
|
||||
url = app.url_path_for("start_vmware_node_capture",
|
||||
url = app.url_path_for("compute:start_vmware_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -222,15 +222,15 @@ async def test_vmware_start_capture(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
with patch("gns3server.compute.vmware.vmware_vm.VMwareVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.start_capture") as mock:
|
||||
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert mock.called
|
||||
assert "test.pcap" in response.json()["pcap_file_path"]
|
||||
|
||||
|
||||
async def test_vmware_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vmware_stop_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("stop_vmware_node_capture",
|
||||
url = app.url_path_for("compute:stop_vmware_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -238,15 +238,15 @@ async def test_vmware_stop_capture(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
|
||||
with patch("gns3server.compute.vmware.vmware_vm.VMwareVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.stop_capture") as mock:
|
||||
response = await client.post(url)
|
||||
response = await compute_client.post(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_vmware_pcap(app: FastAPI, client: AsyncClient, vm, compute_project):
|
||||
# async def test_vmware_pcap(app: FastAPI, compute_client: AsyncClient, vm, compute_project):
|
||||
#
|
||||
# with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.get_nio"):
|
||||
# with asyncio_patch("gns3server.compute.vmware.VMware.stream_pcap_file"):
|
||||
# response = await client.get("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# response = await compute_client.get("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# assert response.status_code == status.HTTP_200_OK
|
||||
|
@ -28,47 +28,47 @@ pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def vm(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def vm(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
params = {"name": "PC TEST 1"}
|
||||
response = await client.post(app.url_path_for("create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
return response.json()
|
||||
|
||||
|
||||
async def test_vpcs_create(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def test_vpcs_create(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
params = {"name": "PC TEST 1"}
|
||||
response = await client.post(app.url_path_for("create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
|
||||
|
||||
async def test_vpcs_get(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_vpcs_get(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_vpcs_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
response = await compute_client.get(app.url_path_for("compute:get_vpcs_node", project_id=vm["project_id"], node_id=vm["node_id"]))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
assert response.json()["status"] == "stopped"
|
||||
|
||||
|
||||
async def test_vpcs_create_startup_script(app: FastAPI, client: AsyncClient, compute_project: Project) -> None:
|
||||
async def test_vpcs_create_startup_script(app: FastAPI, compute_client: AsyncClient, compute_project: Project) -> None:
|
||||
|
||||
params = {
|
||||
"name": "PC TEST 1",
|
||||
"startup_script": "ip 192.168.1.2\necho TEST"
|
||||
}
|
||||
|
||||
response = await client.post(app.url_path_for("create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
|
||||
|
||||
async def test_vpcs_create_port(app: FastAPI,
|
||||
client: AsyncClient,
|
||||
compute_client: AsyncClient,
|
||||
compute_project: Project,
|
||||
free_console_port: int) -> None:
|
||||
|
||||
@ -77,14 +77,14 @@ async def test_vpcs_create_port(app: FastAPI,
|
||||
"console": free_console_port
|
||||
}
|
||||
|
||||
response = await client.post(app.url_path_for("create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["name"] == "PC TEST 1"
|
||||
assert response.json()["project_id"] == compute_project.id
|
||||
assert response.json()["console"] == free_console_port
|
||||
|
||||
|
||||
async def test_vpcs_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_nio_create_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -93,19 +93,19 @@ async def test_vpcs_nio_create_udp(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_vpcs_node_nio",
|
||||
url = app.url_path_for("compute:create_vpcs_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.add_ubridge_udp_connection"):
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_vpcs_nio_update_udp(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_nio_update_udp(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -114,28 +114,28 @@ async def test_vpcs_nio_update_udp(app: FastAPI, client: AsyncClient, vm: dict)
|
||||
"rhost": "127.0.0.1"
|
||||
}
|
||||
|
||||
url = app.url_path_for("create_vpcs_node_nio",
|
||||
url = app.url_path_for("compute:create_vpcs_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.add_ubridge_udp_connection"):
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
params["filters"] = {}
|
||||
url = app.url_path_for("update_vpcs_node_nio",
|
||||
url = app.url_path_for("compute:update_vpcs_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
response = await client.put(url, json=params)
|
||||
response = await compute_client.put(url, json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
assert response.json()["type"] == "nio_udp"
|
||||
|
||||
|
||||
async def test_vpcs_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_delete_nio(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"type": "nio_udp",
|
||||
@ -145,78 +145,78 @@ async def test_vpcs_delete_nio(app: FastAPI, client: AsyncClient, vm: dict) -> N
|
||||
}
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._ubridge_send"):
|
||||
url = app.url_path_for("create_vpcs_node_nio",
|
||||
url = app.url_path_for("compute:create_vpcs_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
await client.post(url, json=params)
|
||||
await compute_client.post(url, json=params)
|
||||
|
||||
url = app.url_path_for("delete_vpcs_node_nio",
|
||||
url = app.url_path_for("compute:delete_vpcs_node_nio",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
port_number="0")
|
||||
response = await client.delete(url)
|
||||
response = await compute_client.delete(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vpcs_start(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_start(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("start_vpcs_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:start_vpcs_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vpcs_stop(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_stop(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.stop", return_value=True) as mock:
|
||||
|
||||
response = await client.post(app.url_path_for("stop_vpcs_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:stop_vpcs_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vpcs_reload(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_reload(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.reload", return_value=True) as mock:
|
||||
response = await client.post(app.url_path_for("reload_vpcs_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:reload_vpcs_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vpcs_delete(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_delete(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
with asyncio_patch("gns3server.compute.vpcs.VPCS.delete_node", return_value=True) as mock:
|
||||
response = await client.delete(app.url_path_for("delete_vpcs_node",
|
||||
response = await compute_client.delete(app.url_path_for("compute:delete_vpcs_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]))
|
||||
assert mock.called
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
|
||||
async def test_vpcs_duplicate(app: FastAPI, client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
async def test_vpcs_duplicate(app: FastAPI, compute_client: AsyncClient, compute_project: Project, vm: dict) -> None:
|
||||
|
||||
# create destination node first
|
||||
params = {"name": "PC TEST 1"}
|
||||
response = await client.post(app.url_path_for("create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
response = await compute_client.post(app.url_path_for("compute:create_vpcs_node", project_id=compute_project.id), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
params = {"destination_node_id": response.json()["node_id"]}
|
||||
response = await client.post(app.url_path_for("duplicate_vpcs_node",
|
||||
response = await compute_client.post(app.url_path_for("compute:duplicate_vpcs_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
|
||||
async def test_vpcs_update(app: FastAPI, client: AsyncClient, vm: dict, free_console_port: int) -> None:
|
||||
async def test_vpcs_update(app: FastAPI, compute_client: AsyncClient, vm: dict, free_console_port: int) -> None:
|
||||
|
||||
console_port = free_console_port
|
||||
params = {
|
||||
@ -224,7 +224,7 @@ async def test_vpcs_update(app: FastAPI, client: AsyncClient, vm: dict, free_con
|
||||
"console": console_port
|
||||
}
|
||||
|
||||
response = await client.put(app.url_path_for("update_vpcs_node",
|
||||
response = await compute_client.put(app.url_path_for("compute:update_vpcs_node",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"]), json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
@ -232,14 +232,14 @@ async def test_vpcs_update(app: FastAPI, client: AsyncClient, vm: dict, free_con
|
||||
assert response.json()["console"] == console_port
|
||||
|
||||
|
||||
async def test_vpcs_start_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_start_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
params = {
|
||||
"capture_file_name": "test.pcap",
|
||||
"data_link_type": "DLT_EN10MB"
|
||||
}
|
||||
|
||||
url = app.url_path_for("start_vpcs_node_capture",
|
||||
url = app.url_path_for("compute:start_vpcs_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -247,15 +247,15 @@ async def test_vpcs_start_capture(app: FastAPI, client: AsyncClient, vm: dict) -
|
||||
|
||||
with patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_capture") as mock:
|
||||
response = await client.post(url, json=params)
|
||||
response = await compute_client.post(url, json=params)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert mock.called
|
||||
assert "test.pcap" in response.json()["pcap_file_path"]
|
||||
|
||||
|
||||
async def test_vpcs_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) -> None:
|
||||
async def test_vpcs_stop_capture(app: FastAPI, compute_client: AsyncClient, vm: dict) -> None:
|
||||
|
||||
url = app.url_path_for("stop_vpcs_node_capture",
|
||||
url = app.url_path_for("compute:stop_vpcs_node_capture",
|
||||
project_id=vm["project_id"],
|
||||
node_id=vm["node_id"],
|
||||
adapter_number="0",
|
||||
@ -263,15 +263,15 @@ async def test_vpcs_stop_capture(app: FastAPI, client: AsyncClient, vm: dict) ->
|
||||
|
||||
with patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.is_running", return_value=True):
|
||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.stop_capture") as mock:
|
||||
response = await client.post(url)
|
||||
response = await compute_client.post(url)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert mock.called
|
||||
|
||||
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_vpcs_pcap(app: FastAPI, client: AsyncClient, vm, compute_project: Project):
|
||||
# async def test_vpcs_pcap(app: FastAPI, compute_client: AsyncClient, vm, compute_project: Project):
|
||||
#
|
||||
# with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.get_nio"):
|
||||
# with asyncio_patch("gns3server.compute.vpcs.VPCS.stream_pcap_file"):
|
||||
# response = await client.get("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# response = await compute_client.get("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
|
||||
# assert response.status_code == status.HTTP_200_OK
|
||||
|
@ -190,24 +190,3 @@ class TestComputeFeatures:
|
||||
# response = await client.post(app.url_path_for("autoidlepc", compute_id=compute_id) + "/auto_idlepc", json=params)
|
||||
# assert mock.called
|
||||
# assert response.status_code == status.HTTP_200_OK
|
||||
|
||||
|
||||
# FIXME
|
||||
# @pytest.mark.asyncio
|
||||
# async def test_compute_endpoint(controller_api):
|
||||
#
|
||||
# params = {
|
||||
# "compute_id": "my_compute",
|
||||
# "protocol": "http",
|
||||
# "host": "localhost",
|
||||
# "port": 84,
|
||||
# "user": "julien",
|
||||
# "password": "secure"
|
||||
# }
|
||||
#
|
||||
# response = await controller_api.post("/computes", params)
|
||||
# assert response.status_code == 201
|
||||
#
|
||||
# response = await controller_api.get("/computes/endpoint/my_compute/qemu/images")
|
||||
# assert response.status_code == 200
|
||||
# assert response.json['endpoint'] == 'http://localhost:84/v2/compute/qemu/images'
|
||||
|
@ -273,7 +273,7 @@ class TestImageRoutes:
|
||||
image_data = f.read()
|
||||
response = await client.post(
|
||||
app.url_path_for("upload_image", image_path=image_name),
|
||||
params={"image_type": "qemu"},
|
||||
params={"image_type": "qemu", "install_appliances": "true"},
|
||||
content=image_data)
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
|
||||
|
@ -92,7 +92,7 @@ class TestPermissionRoutes:
|
||||
|
||||
response = await client.get(app.url_path_for("get_permissions"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert len(response.json()) == 10 # 5 default permissions + 5 custom permissions
|
||||
assert len(response.json()) == 11 # 6 default permissions + 5 custom permissions
|
||||
|
||||
async def test_update_permission(self, app: FastAPI, client: AsyncClient, db_session: AsyncSession, project: Project) -> None:
|
||||
|
||||
@ -132,4 +132,4 @@ class TestPermissionRoutes:
|
||||
|
||||
rbac_repo = RbacRepository(db_session)
|
||||
permissions_in_db = await rbac_repo.get_permissions()
|
||||
assert len(permissions_in_db) == 9 # 5 default permissions + 4 custom permissions
|
||||
assert len(permissions_in_db) == 10 # 6 default permissions + 4 custom permissions
|
||||
|
@ -142,7 +142,7 @@ class TestRolesPermissionsRoutes:
|
||||
)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
permissions = await rbac_repo.get_role_permissions(role_in_db.role_id)
|
||||
assert len(permissions) == 5 # 4 default permissions + 1 custom permission
|
||||
assert len(permissions) == 6 # 5 default permissions + 1 custom permission
|
||||
|
||||
async def test_get_role_permissions(
|
||||
self,
|
||||
@ -160,7 +160,7 @@ class TestRolesPermissionsRoutes:
|
||||
role_id=role_in_db.role_id)
|
||||
)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert len(response.json()) == 5 # 4 default permissions + 1 custom permission
|
||||
assert len(response.json()) == 6 # 5 default permissions + 1 custom permission
|
||||
|
||||
async def test_remove_role_from_group(
|
||||
self,
|
||||
@ -182,4 +182,4 @@ class TestRolesPermissionsRoutes:
|
||||
)
|
||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||
permissions = await rbac_repo.get_role_permissions(role_in_db.role_id)
|
||||
assert len(permissions) == 4 # 4 default permissions
|
||||
assert len(permissions) == 5 # 5 default permissions
|
||||
|
@ -29,7 +29,7 @@ async def test_version_output(app: FastAPI, client: AsyncClient) -> None:
|
||||
|
||||
response = await client.get(app.url_path_for("get_version"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json() == {'local': True, 'version': __version__}
|
||||
assert response.json() == {'controller_host': '127.0.0.1', 'local': True, 'version': __version__}
|
||||
|
||||
|
||||
async def test_version_input(app: FastAPI, client: AsyncClient) -> None:
|
||||
|
@ -1015,6 +1015,7 @@ async def test_stop(vm):
|
||||
|
||||
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="running"):
|
||||
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query:
|
||||
vm._permissions_fixed = False
|
||||
await vm.stop()
|
||||
mock_query.assert_called_with("POST", "containers/e90e34656842/stop", params={"t": 5})
|
||||
assert mock.stop.called
|
||||
|
@ -6,6 +6,7 @@ import sys
|
||||
import os
|
||||
import uuid
|
||||
import configparser
|
||||
import base64
|
||||
|
||||
from fastapi import FastAPI
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
@ -180,6 +181,18 @@ async def client(base_client: AsyncClient) -> AsyncClient:
|
||||
return base_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def compute_client(base_client: AsyncClient) -> AsyncClient:
|
||||
|
||||
# default compute username is 'admin'
|
||||
base64_credentials = base64.b64encode(b"admin:").decode("ascii")
|
||||
base_client.headers = {
|
||||
**base_client.headers,
|
||||
"Authorization": f"Basic {base64_credentials}",
|
||||
}
|
||||
return base_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def controller_config_path(tmpdir):
|
||||
|
||||
@ -394,7 +407,6 @@ def run_around_tests(monkeypatch, config, port_manager):#port_manager, controlle
|
||||
|
||||
config.settings.Server.ubridge_path = os.path.join(tmppath, 'bin', 'ubridge')
|
||||
config.settings.Server.local = True
|
||||
config.settings.Server.enable_http_auth = False
|
||||
|
||||
# Prevent executions of the VM if we forgot to mock something
|
||||
config.settings.VirtualBox.vboxmanage_path = tmppath
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user