[release] version 0.5.0-unstable6
This commit is contained in:
parent
1ffbb8b39b
commit
5545163768
|
@ -220,6 +220,54 @@ function createService(serviceData, onProgress) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pullImage(imageName, onProgress, ifMissing) {
|
||||||
|
const requestOptions = {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const imageNameEncoded = encodeURIComponent(imageName);
|
||||||
|
|
||||||
|
return fetch(`/cosmos/api/images/${ifMissing ? 'pull-if-missing' : 'pull'}?imageName=${imageNameEncoded}`, requestOptions)
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The response body is a ReadableStream. This code reads the stream and passes chunks to the callback.
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
|
||||||
|
// Read the stream and pass chunks to the callback as they arrive
|
||||||
|
return new ReadableStream({
|
||||||
|
start(controller) {
|
||||||
|
function read() {
|
||||||
|
return reader.read().then(({ done, value }) => {
|
||||||
|
if (done) {
|
||||||
|
controller.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Decode the UTF-8 text
|
||||||
|
let text = new TextDecoder().decode(value);
|
||||||
|
// Split by lines in case there are multiple lines in one chunk
|
||||||
|
let lines = text.split('\n');
|
||||||
|
for (let line of lines) {
|
||||||
|
if (line) {
|
||||||
|
// Call the progress callback
|
||||||
|
onProgress(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.enqueue(value);
|
||||||
|
return read();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return read();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
list,
|
list,
|
||||||
get,
|
get,
|
||||||
|
@ -240,4 +288,5 @@ export {
|
||||||
attachTerminal,
|
attachTerminal,
|
||||||
createTerminal,
|
createTerminal,
|
||||||
createService,
|
createService,
|
||||||
|
pullImage,
|
||||||
};
|
};
|
88
client/src/components/logsInModal.jsx
Normal file
88
client/src/components/logsInModal.jsx
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// material-ui
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Alert, Button, Stack, Typography } from '@mui/material';
|
||||||
|
import { WarningOutlined, PlusCircleOutlined, CopyOutlined, ExclamationCircleOutlined , SyncOutlined, UserOutlined, KeyOutlined, ArrowUpOutlined, FileZipOutlined } from '@ant-design/icons';
|
||||||
|
import Dialog from '@mui/material/Dialog';
|
||||||
|
import DialogActions from '@mui/material/DialogActions';
|
||||||
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
|
import DialogContentText from '@mui/material/DialogContentText';
|
||||||
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { smartDockerLogConcat, tryParseProgressLog } from '../utils/docker';
|
||||||
|
|
||||||
|
const preStyle = {
|
||||||
|
backgroundColor: '#000',
|
||||||
|
color: '#fff',
|
||||||
|
padding: '10px',
|
||||||
|
borderRadius: '5px',
|
||||||
|
overflow: 'auto',
|
||||||
|
maxHeight: '500px',
|
||||||
|
maxWidth: '100%',
|
||||||
|
width: '100%',
|
||||||
|
margin: '0',
|
||||||
|
position: 'relative',
|
||||||
|
fontSize: '12px',
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
wordWrap: 'break-word',
|
||||||
|
wordBreak: 'break-all',
|
||||||
|
lineHeight: '1.5',
|
||||||
|
boxShadow: '0 0 10px rgba(0,0,0,0.5)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.1)',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
marginBottom: '10px',
|
||||||
|
marginTop: '10px',
|
||||||
|
marginLeft: '0',
|
||||||
|
marginRight: '0',
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogsInModal = ({title, request, OnSuccess, OnError, closeAnytime, initialLogs = [], }) => {
|
||||||
|
const [openModal, setOpenModal] = useState(false);
|
||||||
|
const [logs, setLogs] = useState(initialLogs);
|
||||||
|
const [done, setDone] = useState(closeAnytime);
|
||||||
|
const preRef = React.useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLogs(initialLogs);
|
||||||
|
setDone(closeAnytime);
|
||||||
|
|
||||||
|
if(request === null) return;
|
||||||
|
|
||||||
|
request((newlog) => {
|
||||||
|
setLogs((old) => smartDockerLogConcat(old, newlog));
|
||||||
|
|
||||||
|
if(preRef.current)
|
||||||
|
preRef.current.scrollTop = preRef.current.scrollHeight;
|
||||||
|
|
||||||
|
if (newlog.includes('[OPERATION SUCCEEDED]')) {
|
||||||
|
setDone(true);
|
||||||
|
setOpenModal(false);
|
||||||
|
OnSuccess && OnSuccess();
|
||||||
|
} else if (newlog.includes('[OPERATION FAILED]')) {
|
||||||
|
setDone(true);
|
||||||
|
OnError && OnError(newlog);
|
||||||
|
} else {
|
||||||
|
setOpenModal(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [request]);
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<Dialog open={openModal} onClose={() => setOpenModal(false)}>
|
||||||
|
<DialogTitle>{title}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText>
|
||||||
|
<pre style={preStyle} ref={preRef}>
|
||||||
|
{logs.map((l) => {
|
||||||
|
return <div>{tryParseProgressLog(l)}</div>
|
||||||
|
})}
|
||||||
|
</pre>
|
||||||
|
</DialogContentText>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LogsInModal;
|
|
@ -7,6 +7,7 @@ import { CosmosCheckbox, CosmosFormDivider, CosmosInputText, CosmosSelect }
|
||||||
import { DeleteOutlined, PlusCircleOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, PlusCircleOutlined } from '@ant-design/icons';
|
||||||
import * as API from '../../../api';
|
import * as API from '../../../api';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
|
import LogsInModal from '../../../components/logsInModal';
|
||||||
|
|
||||||
const containerInfoFrom = (values) => {
|
const containerInfoFrom = (values) => {
|
||||||
const labels = {};
|
const labels = {};
|
||||||
|
@ -33,9 +34,11 @@ const DockerContainerSetup = ({config, containerInfo, OnChange, refresh, newCont
|
||||||
['on-failure', 'Restart On Failure'],
|
['on-failure', 'Restart On Failure'],
|
||||||
['unless-stopped', 'Restart Unless Stopped'],
|
['unless-stopped', 'Restart Unless Stopped'],
|
||||||
];
|
];
|
||||||
|
const [pullRequest, setPullRequest] = React.useState(null);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
const padding = isMobile ? '6px 4px' : '12px 10px';
|
const padding = isMobile ? '6px 4px' : '12px 10px';
|
||||||
|
const [latestImage, setLatestImage] = React.useState(containerInfo.Config.Image);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ maxWidth: '1000px', width: '100%', margin: '', position: 'relative' }}>
|
<div style={{ maxWidth: '1000px', width: '100%', margin: '', position: 'relative' }}>
|
||||||
|
@ -73,6 +76,11 @@ const DockerContainerSetup = ({config, containerInfo, OnChange, refresh, newCont
|
||||||
return errors;
|
return errors;
|
||||||
}}
|
}}
|
||||||
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
|
onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => {
|
||||||
|
if(values.image !== latestImage) {
|
||||||
|
setPullRequest(() => ((cb) => API.docker.pullImage(values.image,cb, true)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(newContainer) return false;
|
if(newContainer) return false;
|
||||||
delete values.name;
|
delete values.name;
|
||||||
|
|
||||||
|
@ -95,6 +103,14 @@ const DockerContainerSetup = ({config, containerInfo, OnChange, refresh, newCont
|
||||||
>
|
>
|
||||||
{(formik) => (
|
{(formik) => (
|
||||||
<form noValidate onSubmit={formik.handleSubmit}>
|
<form noValidate onSubmit={formik.handleSubmit}>
|
||||||
|
<LogsInModal
|
||||||
|
request={pullRequest}
|
||||||
|
title="Pulling New Image..."
|
||||||
|
OnSuccess={() => {
|
||||||
|
setPullRequest(null);
|
||||||
|
setLatestImage(formik.values.image);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
<MainCard title={'Docker Container Setup'}>
|
<MainCard title={'Docker Container Setup'}>
|
||||||
{containerInfo.State && containerInfo.State.Status !== 'running' && (
|
{containerInfo.State && containerInfo.State.Status !== 'running' && (
|
||||||
|
@ -268,6 +284,9 @@ const DockerContainerSetup = ({config, containerInfo, OnChange, refresh, newCont
|
||||||
<FormHelperText error>{formik.errors.submit}</FormHelperText>
|
<FormHelperText error>{formik.errors.submit}</FormHelperText>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
{formik.values.image !== latestImage && <Alert severity="warning" style={{ marginBottom: '15px' }}>
|
||||||
|
You have updated the image. Clicking the button below will pull the new image, and then only can you update the container.
|
||||||
|
</Alert>}
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
fullWidth
|
fullWidth
|
||||||
disableElevation
|
disableElevation
|
||||||
|
@ -278,7 +297,7 @@ const DockerContainerSetup = ({config, containerInfo, OnChange, refresh, newCont
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
Update
|
{formik.values.image !== latestImage ? 'Pull New Image' : 'Update Container'}
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</Stack>
|
</Stack>
|
||||||
</MainCard>}
|
</MainCard>}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cosmos-server",
|
"name": "cosmos-server",
|
||||||
"version": "0.5.0-unstable5",
|
"version": "0.5.0-unstable6",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "test-server.js",
|
"main": "test-server.js",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"github.com/azukaar/cosmos-server/src/utils"
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func InspectImageRoute(w http.ResponseWriter, req *http.Request) {
|
func InspectImageRoute(w http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -21,8 +20,7 @@ func InspectImageRoute(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
vars := mux.Vars(req)
|
imageName := utils.SanitizeSafe(req.URL.Query().Get("imageName"))
|
||||||
imageName := utils.SanitizeSafe(vars["imageName"])
|
|
||||||
|
|
||||||
utils.Log("InspectImage " + imageName)
|
utils.Log("InspectImage " + imageName)
|
||||||
|
|
||||||
|
|
182
src/docker/api_update.go
Normal file
182
src/docker/api_update.go
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"fmt"
|
||||||
|
"bufio"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PullImageIfMissing(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if utils.AdminOnly(w, req) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
imageName := utils.SanitizeSafe(req.URL.Query().Get("imageName"))
|
||||||
|
|
||||||
|
if req.Method == "GET" {
|
||||||
|
errD := Connect()
|
||||||
|
if errD != nil {
|
||||||
|
utils.Error("PullImageIfMissing", errD)
|
||||||
|
utils.HTTPError(w, "Internal server error: "+errD.Error(), http.StatusInternalServerError, "LN001")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable streaming of response by setting appropriate headers
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("Transfer-Encoding", "chunked")
|
||||||
|
|
||||||
|
flusher, ok := w.(http.Flusher)
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "Streaming unsupported!", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, errImage := DockerClient.ImageInspectWithRaw(DockerContext, imageName)
|
||||||
|
if errImage != nil {
|
||||||
|
utils.Log("PullImageIfMissing - Image not found, pulling " + imageName)
|
||||||
|
fmt.Fprintf(w, "PullImageIfMissing - Image not found, pulling " + imageName + "\n")
|
||||||
|
flusher.Flush()
|
||||||
|
out, errPull := DockerClient.ImagePull(DockerContext, imageName, types.ImagePullOptions{})
|
||||||
|
if errPull != nil {
|
||||||
|
utils.Error("PullImageIfMissing - Image not found.", errPull)
|
||||||
|
fmt.Fprintf(w, "[OPERATION FAILED] PullImageIfMissing - Image not found. " + errPull.Error() + "\n")
|
||||||
|
flusher.Flush()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
// wait for image pull to finish
|
||||||
|
scanner := bufio.NewScanner(out)
|
||||||
|
for scanner.Scan() {
|
||||||
|
utils.Log(scanner.Text())
|
||||||
|
fmt.Fprintf(w, scanner.Text() + "\n")
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.Log("PullImageIfMissing - Image pulled " + imageName)
|
||||||
|
fmt.Fprintf(w, "[OPERATION SUCCEEDED]")
|
||||||
|
flusher.Flush()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.Log("PullImageIfMissing - Image found, skipping " + imageName)
|
||||||
|
fmt.Fprintf(w, "[OPERATION SUCCEEDED]")
|
||||||
|
flusher.Flush()
|
||||||
|
} else {
|
||||||
|
utils.Error("PullImageIfMissing: Method not allowed " + req.Method, nil)
|
||||||
|
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PullImage(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if utils.AdminOnly(w, req) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
imageName := utils.SanitizeSafe(req.URL.Query().Get("imageName"))
|
||||||
|
|
||||||
|
if req.Method == "GET" {
|
||||||
|
errD := Connect()
|
||||||
|
if errD != nil {
|
||||||
|
utils.Error("PullImageIfMissing", errD)
|
||||||
|
utils.HTTPError(w, "Internal server error: "+errD.Error(), http.StatusInternalServerError, "LN001")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable streaming of response by setting appropriate headers
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("Transfer-Encoding", "chunked")
|
||||||
|
|
||||||
|
flusher, ok := w.(http.Flusher)
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "Streaming unsupported!", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.Log("PullImageIfMissing - Image not found, pulling " + imageName)
|
||||||
|
fmt.Fprintf(w, "PullImageIfMissing - Image not found, pulling " + imageName + "\n")
|
||||||
|
flusher.Flush()
|
||||||
|
out, errPull := DockerClient.ImagePull(DockerContext, imageName, types.ImagePullOptions{})
|
||||||
|
if errPull != nil {
|
||||||
|
utils.Error("PullImageIfMissing - Image not found.", errPull)
|
||||||
|
fmt.Fprintf(w, "[OPERATION FAILED] PullImageIfMissing - Image not found. " + errPull.Error() + "\n")
|
||||||
|
flusher.Flush()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
// wait for image pull to finish
|
||||||
|
scanner := bufio.NewScanner(out)
|
||||||
|
for scanner.Scan() {
|
||||||
|
utils.Log(scanner.Text())
|
||||||
|
fmt.Fprintf(w, scanner.Text() + "\n")
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.Log("PullImageIfMissing - Image pulled " + imageName)
|
||||||
|
fmt.Fprintf(w, "[OPERATION SUCCEEDED]")
|
||||||
|
flusher.Flush()
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
utils.Error("PullImageIfMissing: Method not allowed " + req.Method, nil)
|
||||||
|
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CanUpdateImageRoute(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if utils.AdminOnly(w, req) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
containerId := vars["containerId"]
|
||||||
|
|
||||||
|
if req.Method == "GET" {
|
||||||
|
errD := Connect()
|
||||||
|
if errD != nil {
|
||||||
|
utils.Error("CanUpdateImageRoute", errD)
|
||||||
|
utils.HTTPError(w, "Internal server error: "+errD.Error(), http.StatusInternalServerError, "LN001")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// get Docker container
|
||||||
|
container, err := DockerClient.ContainerInspect(context.Background(), containerId)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("CanUpdateImageRoute: Error while getting container", err)
|
||||||
|
utils.HTTPError(w, "Container Get Error: " + err.Error(), http.StatusInternalServerError, "LN002")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the container's image can be updated
|
||||||
|
canUpdate := false
|
||||||
|
imageName := container.Image
|
||||||
|
image, _, err := DockerClient.ImageInspectWithRaw(context.Background(), imageName)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("CanUpdateImageRoute: Error while inspecting image", err)
|
||||||
|
utils.HTTPError(w, "Image Inspection Error: " + err.Error(), http.StatusInternalServerError, "LN003")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(image.RepoDigests) > 0 {
|
||||||
|
canUpdate = true
|
||||||
|
}
|
||||||
|
|
||||||
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
|
"status": "OK",
|
||||||
|
"data": canUpdate,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
utils.Error("CanUpdateImageRoute: Method not allowed " + req.Method, nil)
|
||||||
|
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"bufio"
|
||||||
"github.com/azukaar/cosmos-server/src/utils"
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
|
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
@ -116,6 +117,24 @@ func EditContainer(oldContainerID string, newConfig types.ContainerJSON) (string
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if new image exists, if not, pull it
|
||||||
|
_, _, errImage := DockerClient.ImageInspectWithRaw(DockerContext, newConfig.Config.Image)
|
||||||
|
if errImage != nil {
|
||||||
|
utils.Log("EditContainer - Image not found, pulling " + newConfig.Config.Image)
|
||||||
|
out, errPull := DockerClient.ImagePull(DockerContext, newConfig.Config.Image, types.ImagePullOptions{})
|
||||||
|
if errPull != nil {
|
||||||
|
utils.Error("EditContainer - Image not found.", errPull)
|
||||||
|
return "", errors.New("Image not found. " + errPull.Error())
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
// wait for image pull to finish
|
||||||
|
scanner := bufio.NewScanner(out)
|
||||||
|
for scanner.Scan() {
|
||||||
|
utils.Log(scanner.Text())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if no name, use the same one, that will force Docker to create a hostname if not set
|
// if no name, use the same one, that will force Docker to create a hostname if not set
|
||||||
newName = oldContainer.Name
|
newName = oldContainer.Name
|
||||||
newConfig.Config.Hostname = newName
|
newConfig.Config.Hostname = newName
|
||||||
|
@ -147,7 +166,7 @@ func EditContainer(oldContainerID string, newConfig types.ContainerJSON) (string
|
||||||
} else {
|
} else {
|
||||||
utils.Log("EditContainer - Revert started")
|
utils.Log("EditContainer - Revert started")
|
||||||
}
|
}
|
||||||
|
|
||||||
// recreate container with new informations
|
// recreate container with new informations
|
||||||
createResponse, createError := DockerClient.ContainerCreate(
|
createResponse, createError := DockerClient.ContainerCreate(
|
||||||
DockerContext,
|
DockerContext,
|
||||||
|
|
|
@ -218,7 +218,9 @@ func StartServer() {
|
||||||
srapi.HandleFunc("/api/users/{nickname}", user.UsersIdRoute)
|
srapi.HandleFunc("/api/users/{nickname}", user.UsersIdRoute)
|
||||||
srapi.HandleFunc("/api/users", user.UsersRoute)
|
srapi.HandleFunc("/api/users", user.UsersRoute)
|
||||||
|
|
||||||
srapi.HandleFunc("/api/images/{imageName}", docker.InspectImageRoute)
|
srapi.HandleFunc("/api/images/pull-if-missing", docker.PullImageIfMissing)
|
||||||
|
srapi.HandleFunc("/api/images/pull", docker.PullImage)
|
||||||
|
srapi.HandleFunc("/api/images", docker.InspectImageRoute)
|
||||||
|
|
||||||
srapi.HandleFunc("/api/volume/{volumeName}", docker.DeleteVolumeRoute)
|
srapi.HandleFunc("/api/volume/{volumeName}", docker.DeleteVolumeRoute)
|
||||||
srapi.HandleFunc("/api/volumes", docker.VolumesRoute)
|
srapi.HandleFunc("/api/volumes", docker.VolumesRoute)
|
||||||
|
@ -234,6 +236,7 @@ func StartServer() {
|
||||||
srapi.HandleFunc("/api/servapps/{containerId}/", docker.GetContainerRoute)
|
srapi.HandleFunc("/api/servapps/{containerId}/", docker.GetContainerRoute)
|
||||||
srapi.HandleFunc("/api/servapps/{containerId}/network/{networkId}", docker.NetworkContainerRoutes)
|
srapi.HandleFunc("/api/servapps/{containerId}/network/{networkId}", docker.NetworkContainerRoutes)
|
||||||
srapi.HandleFunc("/api/servapps/{containerId}/networks", docker.NetworkContainerRoutes)
|
srapi.HandleFunc("/api/servapps/{containerId}/networks", docker.NetworkContainerRoutes)
|
||||||
|
srapi.HandleFunc("/api/servapps/{containerId}/check-update", docker.CanUpdateImageRoute)
|
||||||
srapi.HandleFunc("/api/servapps", docker.ContainersRoute)
|
srapi.HandleFunc("/api/servapps", docker.ContainersRoute)
|
||||||
|
|
||||||
srapi.HandleFunc("/api/docker-service", docker.CreateServiceRoute)
|
srapi.HandleFunc("/api/docker-service", docker.CreateServiceRoute)
|
||||||
|
@ -250,7 +253,7 @@ func StartServer() {
|
||||||
PerUserRequestLimit: 5000,
|
PerUserRequestLimit: 5000,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
srapi.Use(utils.MiddlewareTimeout(30 * time.Second))
|
srapi.Use(utils.MiddlewareTimeout(45 * time.Second))
|
||||||
srapi.Use(utils.BlockPostWithoutReferer)
|
srapi.Use(utils.BlockPostWithoutReferer)
|
||||||
srapi.Use(proxy.BotDetectionMiddleware)
|
srapi.Use(proxy.BotDetectionMiddleware)
|
||||||
srapi.Use(httprate.Limit(120, 1*time.Minute,
|
srapi.Use(httprate.Limit(120, 1*time.Minute,
|
||||||
|
|
Loading…
Reference in a new issue