feat: start / stop container fix #3
All checks were successful
pilotwings / python (push) Successful in 1m47s
pilotwings / node (push) Successful in 1m11s
pilotwings / docker (push) Successful in 2m53s

This commit is contained in:
Michel Roux 2024-11-05 23:45:23 +01:00
parent 5988f8ad89
commit d45299a983
5 changed files with 73 additions and 29 deletions

View File

@ -107,6 +107,7 @@ def get_containers(
return [ return [
serialize_container(container) serialize_container(container)
for container in client.containers.list( for container in client.containers.list(
all=True,
filters={"label": ["engine=pilotwings"]} filters={"label": ["engine=pilotwings"]}
) )
] ]
@ -114,6 +115,7 @@ def get_containers(
return [ return [
serialize_container(container) serialize_container(container)
for container in client.containers.list( for container in client.containers.list(
all=True,
filters={"label": ["engine=pilotwings", f"owner={credentials.username}"]}, filters={"label": ["engine=pilotwings", f"owner={credentials.username}"]},
) )
] ]
@ -187,6 +189,29 @@ def restart_container(
) -> SerializedContainer: ) -> SerializedContainer:
container = select_container(container_name, credentials) container = select_container(container_name, credentials)
container.restart() container.restart()
container.reload()
return serialize_container(container)
@app.post("/api/container/{container_name}/start")
def start_container(
container_name: str,
credentials: Annotated[HTTPBasicCredentials, Depends(security)],
) -> SerializedContainer:
container = select_container(container_name, credentials)
container.start()
container.reload()
return serialize_container(container)
@app.post("/api/container/{container_name}/stop")
def stop_container(
container_name: str,
credentials: Annotated[HTTPBasicCredentials, Depends(security)],
) -> SerializedContainer:
container = select_container(container_name, credentials)
container.stop()
container.reload()
return serialize_container(container) return serialize_container(container)

16
frontend/utils.ts Normal file
View File

@ -0,0 +1,16 @@
export const get_status_icon = (
status: string,
): { name: string; type: string } => {
switch (status) {
case 'running':
return { name: 'play', type: 'success' }
case 'restarting':
return { name: 'refresh', type: 'danger' }
case 'paused':
return { name: 'pause', type: 'warning' }
case 'exited':
return { name: 'stop', type: 'danger' }
default:
return { name: 'question-circle', type: 'warning' }
}
}

View File

@ -34,9 +34,27 @@
> >
{{ container?.status }} {{ container?.status }}
</Icon> </Icon>
<button class="button ml-2" @click="restart"> <button
v-if="container?.status == 'running'"
class="button ml-2"
@click="restart"
>
<Icon name="refresh">Restart</Icon> <Icon name="refresh">Restart</Icon>
</button> </button>
<button
v-if="container?.status == 'running'"
class="button ml-2"
@click="stop"
>
<Icon name="stop">Stop</Icon>
</button>
<button
v-if="container?.status != 'running'"
class="button ml-2"
@click="start"
>
<Icon name="play">Start</Icon>
</button>
</div> </div>
<div class="block is-flex is-align-items-baseline"> <div class="block is-flex is-align-items-baseline">
<Icon name="image"><b>Logs:</b></Icon> <Icon name="image"><b>Logs:</b></Icon>
@ -58,6 +76,7 @@ import axios, { AxiosError } from 'axios'
import type { Container } from '../types' import type { Container } from '../types'
import Icon from '../components/Icon.vue' import Icon from '../components/Icon.vue'
import Loading from '../components/Loading.vue' import Loading from '../components/Loading.vue'
import { get_status_icon } from '../utils'
export default { export default {
name: 'Container', name: 'Container',
@ -77,19 +96,7 @@ export default {
return this.$route.params.name as string return this.$route.params.name as string
}, },
status_icon(): { name: string; type: string } { status_icon(): { name: string; type: string } {
if (!this.container) return { name: 'question-circle', type: 'warning' } return get_status_icon(this.container?.status ?? 'unknown')
switch (this.container.status) {
case 'running':
return { name: 'play', type: 'success' }
case 'restarting':
return { name: 'refresh', type: 'danger' }
case 'paused':
return { name: 'pause', type: 'warning' }
case 'exited':
return { name: 'stop', type: 'danger' }
default:
return { name: 'question-circle', type: 'warning' }
}
}, },
}, },
async mounted() { async mounted() {
@ -125,6 +132,12 @@ export default {
async restart() { async restart() {
this.request('post', `/api/container/${this.container_name}/restart`) this.request('post', `/api/container/${this.container_name}/restart`)
}, },
async start() {
this.request('post', `/api/container/${this.container_name}/start`)
},
async stop() {
this.request('post', `/api/container/${this.container_name}/stop`)
},
}, },
} }
</script> </script>

View File

@ -26,6 +26,7 @@ import axios, { AxiosError } from 'axios'
import type { Container } from '../types' import type { Container } from '../types'
import Icon from '../components/Icon.vue' import Icon from '../components/Icon.vue'
import Loading from '../components/Loading.vue' import Loading from '../components/Loading.vue'
import { get_status_icon } from '../utils'
export default { export default {
name: 'Home', name: 'Home',
@ -54,18 +55,7 @@ export default {
}, },
methods: { methods: {
status_icon(container: Container): { name: string; type: string } { status_icon(container: Container): { name: string; type: string } {
switch (container.status) { return get_status_icon(container.status)
case 'running':
return { name: 'play', type: 'success' }
case 'restarting':
return { name: 'refresh', type: 'danger' }
case 'paused':
return { name: 'pause', type: 'warning' }
case 'exited':
return { name: 'stop', type: 'danger' }
default:
return { name: 'question-circle', type: 'warning' }
}
}, },
}, },
} }

6
package-lock.json generated
View File

@ -676,9 +676,9 @@
} }
}, },
"node_modules/@humanwhocodes/retry": { "node_modules/@humanwhocodes/retry": {
"version": "0.4.0", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.0.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz",
"integrity": "sha512-xnRgu9DxZbkWak/te3fcytNyp8MTbuiZIaueg2rgEvBuN55n04nwLYLU9TX/VVlusc9L2ZNXi99nUFNkHXtr5g==", "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {