From 3cbd88f4a64dbd607cd3142201d2132bcfc29d43 Mon Sep 17 00:00:00 2001 From: Yann Stepienik Date: Sun, 14 May 2023 13:11:59 +0100 Subject: [PATCH] [release] version 0.5.0-unstable3 --- changelog.md | 8 ++++ .../servapps/containers/docker-compose.jsx | 27 ++++++++---- .../pages/servapps/containers/newService.jsx | 17 +++----- .../servapps/containers/newServiceForm.jsx | 2 +- .../pages/servapps/containers/terminal.jsx | 27 +++++++++++- client/src/utils/docker.js | 42 +++++++++++++++++++ package.json | 2 +- src/docker/api_blueprint.go | 37 ++++++++++++++++ src/docker/api_updateContainer.go | 29 +++++++++++++ src/docker/docker.go | 2 +- 10 files changed, 171 insertions(+), 22 deletions(-) create mode 100644 client/src/utils/docker.js diff --git a/changelog.md b/changelog.md index cab0aef..aa19178 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,11 @@ +## Version 0.5.0 + - Add Terminal to containers + - Add Create Container + - Add support for importing Docker Compose + - Fixed 2 bugs with the smart shield, that made it too strict + - Added more infoon the shield when blocking someone + - Fixed home background image + ## Version 0.4.3 - Fix for exposing routes from the details page diff --git a/client/src/pages/servapps/containers/docker-compose.jsx b/client/src/pages/servapps/containers/docker-compose.jsx index f4f6883..a8cd632 100644 --- a/client/src/pages/servapps/containers/docker-compose.jsx +++ b/client/src/pages/servapps/containers/docker-compose.jsx @@ -61,10 +61,6 @@ const preStyle = { marginTop: '10px', marginLeft: '0', marginRight: '0', - display: 'block', - textAlign: 'left', - verticalAlign: 'baseline', - opacity: '1', } const DockerComposeImport = () => { @@ -73,14 +69,22 @@ const DockerComposeImport = () => { const [openModal, setOpenModal] = useState(false); const [dockerCompose, setDockerCompose] = useState(''); const [service, setService] = useState({}); + const [ymlError, setYmlError] = useState(''); useEffect(() => { if(dockerCompose === '') { return; } + let doc; let newService = {}; - let doc = yaml.load(dockerCompose); + try { + doc = yaml.load(dockerCompose); + } catch (e) { + console.log(e); + setYmlError(e.message); + return; + } // convert to the proper format if(doc.services) { @@ -110,7 +114,6 @@ const DockerComposeImport = () => { } setService(doc); - console.log(doc); }, [dockerCompose]); return <> @@ -134,6 +137,10 @@ const DockerComposeImport = () => { reader.readAsText(file); }} /> + +
+ {ymlError} +
{ fullWidth value={dockerCompose} onChange={(e) => setDockerCompose(e.target.value)} - style={preStyle} + sx={preStyle} + InputProps={{ + sx: { + color: '#EEE', + } + }} rows={20}> } {step === 1 && @@ -154,6 +166,7 @@ const DockerComposeImport = () => { setOpenModal(false); setStep(0); setDockerCompose(''); + setYmlError(''); }}>Close } - - - } -
+      
         {!log.length && JSON.stringify(service, false ,2)}
         {log.map((l) => {
-          return 
{l}
+ return
{tryParseProgressLog(l)}
})}
diff --git a/client/src/pages/servapps/containers/newServiceForm.jsx b/client/src/pages/servapps/containers/newServiceForm.jsx index a4bbdb5..d62f9bd 100644 --- a/client/src/pages/servapps/containers/newServiceForm.jsx +++ b/client/src/pages/servapps/containers/newServiceForm.jsx @@ -205,7 +205,7 @@ const NewDockerServiceForm = () => { { title: 'Storage', disabled: maxTab < 2, - children: { + children: { console.log(values) const newValues = { ...containerInfo, diff --git a/client/src/pages/servapps/containers/terminal.jsx b/client/src/pages/servapps/containers/terminal.jsx index 4718d13..dc6049f 100644 --- a/client/src/pages/servapps/containers/terminal.jsx +++ b/client/src/pages/servapps/containers/terminal.jsx @@ -12,6 +12,8 @@ const DockerTerminal = ({containerInfo, refresh}) => { const isInteractive = Config.Tty; const theme = useTheme(); const isMobile = useMediaQuery((theme) => theme.breakpoints.down('sm')) + const [history, setHistory] = useState([]); + const [historyCursor, setHistoryCursor] = useState(0); const [message, setMessage] = useState(''); const [output, setOutput] = useState([ @@ -24,10 +26,31 @@ const DockerTerminal = ({containerInfo, refresh}) => { const [isConnected, setIsConnected] = useState(false); const handleKeyDown = (e) => { - if (e.key === 'Enter' && e.ctrlKey) { + if (e.key === 'Enter') { + // shift + enter for new line + if (e.shiftKey) { + return; + } e.preventDefault(); sendMessage(); } + if (e.key === 'ArrowUp') { + e.preventDefault(); + if (historyCursor > 0) { + setHistoryCursor(historyCursor - 1); + setMessage(history[historyCursor - 1]); + } + } + if (e.key === 'ArrowDown') { + e.preventDefault(); + if (historyCursor < history.length - 1) { + setHistoryCursor(historyCursor + 1); + setMessage(history[historyCursor + 1]); + } else { + setHistoryCursor(history.length); + setMessage(''); + } + } }; const makeInteractive = () => { @@ -85,7 +108,9 @@ const DockerTerminal = ({containerInfo, refresh}) => { const sendMessage = () => { if (ws.current) { ws.current.send(message); + setHistoryCursor(history.length + 1); setMessage(''); + setHistory((prevHistory) => [...prevHistory, message]); } }; diff --git a/client/src/utils/docker.js b/client/src/utils/docker.js new file mode 100644 index 0000000..fe290a6 --- /dev/null +++ b/client/src/utils/docker.js @@ -0,0 +1,42 @@ +export const smartDockerLogConcat = (log, newLogRaw) => { + const containsId = (log, id) => { + try { + const parsedLog = JSON.parse(log); + return parsedLog.id === id; + } + catch (e) { + return false; + } + } + + try { + const newLog = JSON.parse(newLogRaw); + if (newLog.id) { + if (log.find((l) => containsId(l, newLog.id))) { + return log.map((l) => (containsId(l, newLog.id) ? newLogRaw : l)); + } else { + return [...log, newLogRaw]; + } + } + return [...log, newLogRaw]; + } catch (e) { + console.log(e); + return [...log, newLogRaw]; + } +} + +export const tryParseProgressLog = (log) => { + try { + const parsedLog = JSON.parse(log); + if (parsedLog.status && parsedLog.progress) { + return `${parsedLog.id} ${parsedLog.status} ${parsedLog.progress}` + } else if (parsedLog.status && parsedLog.progressDetail && parsedLog.progressDetail.current) { + return `${parsedLog.id} ${parsedLog.status} ${parsedLog.progressDetail.current}/${parsedLog.progressDetail.total}` + } else if (parsedLog.status) { + return `${parsedLog.id} ${parsedLog.status} ${parsedLog.sha256 || ""}` + } + return log; + } catch (e) { + return log; + } +} diff --git a/package.json b/package.json index 5e4f735..51df295 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.5.0-unstable2", + "version": "0.5.0-unstable3", "description": "", "main": "test-server.js", "bugs": { diff --git a/src/docker/api_blueprint.go b/src/docker/api_blueprint.go index bc22ea8..e94131a 100644 --- a/src/docker/api_blueprint.go +++ b/src/docker/api_blueprint.go @@ -7,6 +7,9 @@ import ( "strings" "time" "bufio" + "strconv" + "os" + "os/user" "errors" "github.com/docker/go-connections/nat" "github.com/docker/docker/api/types/mount" @@ -311,6 +314,7 @@ func CreateServiceRoute(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "Image %s pulled\n", container.Image) flusher.Flush() } + // Create containers for _, container := range serviceRequest.Services { utils.Log(fmt.Sprintf("Creating container %s...", container.Name)) @@ -362,6 +366,39 @@ func CreateServiceRoute(w http.ResponseWriter, req *http.Request) { } } + // Create missing folders for bind mounts + for _, newmount := range container.Volumes { + if newmount.Type == mount.TypeBind { + if _, err := os.Stat(newmount.Source); os.IsNotExist(err) { + err := os.MkdirAll(newmount.Source, 0755) + if err != nil { + utils.Error("CreateService: Unable to create directory for bind mount", err) + fmt.Fprintf(w, "[ERROR] Unable to create directory for bind mount: "+err.Error()) + flusher.Flush() + Rollback(rollbackActions, w, flusher) + return + } + + // Change the ownership of the directory to the container.User + userInfo, err := user.Lookup(container.User) + if err != nil { + utils.Error("CreateService: Unable to lookup user", err) + fmt.Fprintf(w, "[ERROR] Unable to lookup user: "+err.Error()) + flusher.Flush() + } else { + uid, _ := strconv.Atoi(userInfo.Uid) + gid, _ := strconv.Atoi(userInfo.Gid) + err = os.Chown(newmount.Source, uid, gid) + if err != nil { + utils.Error("CreateService: Unable to change ownership of directory", err) + fmt.Fprintf(w, "[ERROR] Unable to change ownership of directory: "+err.Error()) + flusher.Flush() + } + } + } + } + } + hostConfig := &conttype.HostConfig{ PortBindings: PortBindings, Mounts: container.Volumes, diff --git a/src/docker/api_updateContainer.go b/src/docker/api_updateContainer.go index 9c20bc7..929af71 100644 --- a/src/docker/api_updateContainer.go +++ b/src/docker/api_updateContainer.go @@ -4,6 +4,8 @@ import ( "encoding/json" "net/http" "os" + "os/user" + "strconv" "github.com/azukaar/cosmos-server/src/utils" containerType "github.com/docker/docker/api/types/container" @@ -83,6 +85,33 @@ func UpdateContainerRoute(w http.ResponseWriter, req *http.Request) { } } if(form.Volumes != nil) { + // Create missing folders for bind mounts + for _, newmount := range form.Volumes { + if newmount.Type == mount.TypeBind { + if _, err := os.Stat(newmount.Source); os.IsNotExist(err) { + err := os.MkdirAll(newmount.Source, 0755) + if err != nil { + utils.Error("UpdateService: Unable to create directory for bind mount", err) + utils.HTTPError(w, "Unable to create directory for bind mount: "+err.Error(), http.StatusInternalServerError, "DS004") + return + } + + // Change the ownership of the directory to the container.User + userInfo, err := user.Lookup(container.Config.User) + if err != nil { + utils.Error("UpdateService: Unable to lookup user", err) + } else { + uid, _ := strconv.Atoi(userInfo.Uid) + gid, _ := strconv.Atoi(userInfo.Gid) + err = os.Chown(newmount.Source, uid, gid) + if err != nil { + utils.Error("UpdateService: Unable to change ownership of directory", err) + } + } + } + } + } + container.HostConfig.Mounts = form.Volumes container.HostConfig.Binds = []string{} } diff --git a/src/docker/docker.go b/src/docker/docker.go index 76d9bb0..c53e6fe 100644 --- a/src/docker/docker.go +++ b/src/docker/docker.go @@ -292,4 +292,4 @@ func Test() error { // fmt.Println(jellyfin.NetworkSettings) return nil -} \ No newline at end of file +}