mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-27 12:30:13 +03:00
Merge branch '2.2' into bugfix/2838
This commit is contained in:
commit
668169d1cc
40
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
40
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
name: Bug report
|
||||||
|
description: Report a bug so we can fix it.
|
||||||
|
title: "[Bug]: "
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: A clear description of the bug.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: reproduce
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: How can we reproduce this? Numbered steps if possible.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: Expected behavior
|
||||||
|
description: What did you expect to happen instead?
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Version / commit
|
||||||
|
description: Which version or commit hash are you on?
|
||||||
|
- type: textarea
|
||||||
|
id: environment
|
||||||
|
attributes:
|
||||||
|
label: Environment
|
||||||
|
description: OS, runtime version, anything else that might be relevant.
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Relevant logs
|
||||||
|
description: Paste any relevant log output. This is automatically rendered as code.
|
||||||
|
render: shell
|
||||||
11
.github/workflows/docker-build.yml
vendored
11
.github/workflows/docker-build.yml
vendored
@ -28,6 +28,13 @@ jobs:
|
|||||||
echo "stable=false" >> $GITHUB_OUTPUT
|
echo "stable=false" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Set lowercase image name vars
|
||||||
|
if: steps.ver.outputs.stable == 'true'
|
||||||
|
id: names
|
||||||
|
run: |
|
||||||
|
echo "owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "repo=$(echo '${{ github.event.repository.name }}' | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
if: steps.ver.outputs.stable == 'true'
|
if: steps.ver.outputs.stable == 'true'
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
@ -57,5 +64,5 @@ jobs:
|
|||||||
tags: |
|
tags: |
|
||||||
${{ env.DOCKERHUB_ORG }}/${{ github.event.repository.name }}:${{ steps.ver.outputs.tag }}
|
${{ env.DOCKERHUB_ORG }}/${{ github.event.repository.name }}:${{ steps.ver.outputs.tag }}
|
||||||
${{ env.DOCKERHUB_ORG }}/${{ github.event.repository.name }}:latest
|
${{ env.DOCKERHUB_ORG }}/${{ github.event.repository.name }}:latest
|
||||||
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ steps.ver.outputs.tag }}
|
ghcr.io/${{ steps.names.outputs.owner }}/${{ steps.names.outputs.repo }}:${{ steps.ver.outputs.tag }}
|
||||||
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest
|
ghcr.io/${{ steps.names.outputs.owner }}/${{ steps.names.outputs.repo }}:latest
|
||||||
|
|||||||
@ -869,7 +869,7 @@ class DockerVM(BaseNode):
|
|||||||
await self._fix_permissions()
|
await self._fix_permissions()
|
||||||
|
|
||||||
state = await self._get_container_state()
|
state = await self._get_container_state()
|
||||||
if state != "stopped" or state != "exited":
|
if state != "stopped" and state != "exited":
|
||||||
# t=5 number of seconds to wait before killing the container
|
# t=5 number of seconds to wait before killing the container
|
||||||
try:
|
try:
|
||||||
await self.manager.query("POST", "containers/{}/stop".format(self._cid), params={"t": 5})
|
await self.manager.query("POST", "containers/{}/stop".format(self._cid), params={"t": 5})
|
||||||
|
|||||||
@ -917,7 +917,7 @@ class Project:
|
|||||||
|
|
||||||
if self._status != "opened":
|
if self._status != "opened":
|
||||||
try:
|
try:
|
||||||
await self.open()
|
await self.open(auto_start=False)
|
||||||
except aiohttp.web.HTTPConflict as e:
|
except aiohttp.web.HTTPConflict as e:
|
||||||
# ignore missing images or other conflicts when deleting a project
|
# ignore missing images or other conflicts when deleting a project
|
||||||
log.warning(f"Conflict while deleting project: {e}")
|
log.warning(f"Conflict while deleting project: {e}")
|
||||||
@ -998,9 +998,12 @@ class Project:
|
|||||||
return os.path.join(self.path, self._filename)
|
return os.path.join(self.path, self._filename)
|
||||||
|
|
||||||
@locking
|
@locking
|
||||||
async def open(self):
|
async def open(self, auto_start=True):
|
||||||
"""
|
"""
|
||||||
Load topology elements
|
Load topology elements
|
||||||
|
|
||||||
|
:param auto_start: whether the nodes may be started when the project
|
||||||
|
has auto start enabled
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self._closing:
|
if self._closing:
|
||||||
@ -1114,7 +1117,7 @@ class Project:
|
|||||||
self._loading = False
|
self._loading = False
|
||||||
self.emit_controller_notification("project.opened", self.__json__())
|
self.emit_controller_notification("project.opened", self.__json__())
|
||||||
# Should we start the nodes when project is open
|
# Should we start the nodes when project is open
|
||||||
if self._auto_start:
|
if self._auto_start and auto_start:
|
||||||
# Start all in the background without waiting for completion
|
# Start all in the background without waiting for completion
|
||||||
# we ignore errors because we want to let the user open
|
# we ignore errors because we want to let the user open
|
||||||
# their project and fix it
|
# their project and fix it
|
||||||
|
|||||||
@ -1503,3 +1503,19 @@ async def test_read_console_output_with_binary_mode(vm):
|
|||||||
with asyncio_patch('gns3server.compute.docker.docker_vm.DockerVM.stop'):
|
with asyncio_patch('gns3server.compute.docker.docker_vm.DockerVM.stop'):
|
||||||
await vm._read_console_output(input_stream, output_stream)
|
await vm._read_console_output(input_stream, output_stream)
|
||||||
output_stream.feed_data.assert_called_once_with(b"test")
|
output_stream.feed_data.assert_called_once_with(b"test")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_stop_exited_container_no_stop_query(vm):
|
||||||
|
|
||||||
|
vm._ubridge_hypervisor = None
|
||||||
|
vm._fix_permissions = MagicMock()
|
||||||
|
|
||||||
|
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="exited"):
|
||||||
|
with asyncio_patch("gns3server.compute.docker.Docker.query") as mock_query:
|
||||||
|
vm._permissions_fixed = False
|
||||||
|
await vm.stop()
|
||||||
|
assert not any(
|
||||||
|
call.args[:2] == ("POST", "containers/e90e34656842/stop")
|
||||||
|
for call in mock_query.mock_calls
|
||||||
|
)
|
||||||
|
assert vm.status == "stopped"
|
||||||
|
|||||||
@ -655,6 +655,19 @@ async def test_delete(project):
|
|||||||
assert not os.path.exists(project.path)
|
assert not os.path.exists(project.path)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_delete_does_not_start_nodes(project):
|
||||||
|
"""
|
||||||
|
Deleting a project must not start its nodes, even when auto_start is enabled.
|
||||||
|
"""
|
||||||
|
|
||||||
|
project.auto_start = True
|
||||||
|
project.dump()
|
||||||
|
await project.close()
|
||||||
|
project.start_all = AsyncioMagicMock()
|
||||||
|
await project.delete()
|
||||||
|
assert not project.start_all.called
|
||||||
|
|
||||||
|
|
||||||
async def test_dump(projects_dir):
|
async def test_dump(projects_dir):
|
||||||
|
|
||||||
directory = projects_dir
|
directory = projects_dir
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user