[release] v0.5.12-unstable
This commit is contained in:
parent
95fe730985
commit
3a228a9831
19 changed files with 262 additions and 200 deletions
|
@ -11,39 +11,8 @@ jobs:
|
|||
name: install dependencies
|
||||
command: sudo apt-get install bash curl
|
||||
|
||||
- run:
|
||||
name: download Go
|
||||
command: wget https://golang.org/dl/go1.20.2.linux-amd64.tar.gz
|
||||
|
||||
- run:
|
||||
name: install Go
|
||||
command: sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.20.2.linux-amd64.tar.gz
|
||||
|
||||
- run:
|
||||
name: set Go path
|
||||
command: echo 'export PATH=$PATH:/usr/local/go/bin' >> $BASH_ENV
|
||||
|
||||
- run: |
|
||||
echo 'export NVM_DIR="/opt/circleci/.nvm"' >> $BASH_ENV
|
||||
echo ' [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
|
||||
|
||||
- run: |
|
||||
node -v
|
||||
|
||||
- run: |
|
||||
nvm install v16
|
||||
node -v
|
||||
nvm alias default v16
|
||||
|
||||
- run: |
|
||||
node -v
|
||||
|
||||
- run: docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
|
||||
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: npm install
|
||||
|
||||
- run:
|
||||
name: Download GeoLite2-Country database
|
||||
command: |
|
||||
|
@ -70,49 +39,14 @@ jobs:
|
|||
name: install dependencies
|
||||
command: sudo apt-get install bash curl
|
||||
|
||||
- run:
|
||||
name: download Go
|
||||
command: wget https://golang.org/dl/go1.20.2.linux-arm64.tar.gz
|
||||
|
||||
- run:
|
||||
name: install Go
|
||||
command: sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.20.2.linux-arm64.tar.gz
|
||||
|
||||
- run:
|
||||
name: set Go path
|
||||
command: echo 'export PATH=$PATH:/usr/local/go/bin' >> $BASH_ENV
|
||||
|
||||
- run: |
|
||||
echo 'export NVM_DIR="/opt/circleci/.nvm"' >> $BASH_ENV
|
||||
echo ' [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
|
||||
|
||||
- run: |
|
||||
node -v
|
||||
|
||||
- run: |
|
||||
nvm install v16
|
||||
node -v
|
||||
nvm alias default v16
|
||||
|
||||
- run: |
|
||||
node -v
|
||||
|
||||
- run: docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
|
||||
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: npm install
|
||||
|
||||
- run:
|
||||
name: Download GeoLite2-Country database
|
||||
command: |
|
||||
curl -s -L "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=$MAX_TOKEN&suffix=tar.gz" -o GeoLite2-Country.tar.gz
|
||||
tar -xzf GeoLite2-Country.tar.gz --strip-components 1 --wildcards "*.mmdb"
|
||||
|
||||
- run:
|
||||
name: Build UI
|
||||
command: npm run client-build
|
||||
|
||||
- run:
|
||||
name: Build and publish dockerfiles
|
||||
command: sh docker.arm64.sh
|
||||
|
|
3
.dockerignore
Normal file
3
.dockerignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
node_modules
|
||||
static
|
||||
build
|
|
@ -39,12 +39,19 @@ const GetActions = ({
|
|||
|
||||
let actions = [
|
||||
{
|
||||
t: 'Update Available',
|
||||
t: 'Update Available, Click to Update',
|
||||
if: ['update_available'],
|
||||
e: <IconButton className="shinyButton" color='primary' onClick={() => {doTo('update')}} size={isMiniMobile ? 'medium' : 'large'}>
|
||||
<UpCircleOutlined />
|
||||
</IconButton>
|
||||
},
|
||||
{
|
||||
t: 'No Update Available. Click to Force Pull',
|
||||
if: ['update_not_available'],
|
||||
e: <IconButton onClick={() => {doTo('update')}} size={isMiniMobile ? 'medium' : 'large'}>
|
||||
<UpCircleOutlined />
|
||||
</IconButton>
|
||||
},
|
||||
{
|
||||
t: 'Start',
|
||||
if: ['exited', 'created'],
|
||||
|
@ -117,7 +124,7 @@ const GetActions = ({
|
|||
/>
|
||||
|
||||
{!isUpdating && actions.filter((action) => {
|
||||
return action.if.includes(state) || (updateAvailable && action.if.includes('update_available'));
|
||||
return action.if.includes(state) || (updateAvailable && action.if.includes('update_available')) || (!updateAvailable && action.if.includes('update_not_available'));
|
||||
}).map((action) => {
|
||||
return <Tooltip title={action.t}>{action.e}</Tooltip>
|
||||
})}
|
||||
|
|
|
@ -22,6 +22,8 @@ const ContainerIndex = () => {
|
|||
const { containerName } = useParams();
|
||||
const [container, setContainer] = React.useState(null);
|
||||
const [config, setConfig] = React.useState(null);
|
||||
const [selfName, setSelfName] = React.useState("");
|
||||
const [updatesAvailable, setUpdatesAvailable] = React.useState(null);
|
||||
|
||||
const refreshContainer = () => {
|
||||
return Promise.all([API.docker.get(containerName).then((res) => {
|
||||
|
@ -29,6 +31,8 @@ const ContainerIndex = () => {
|
|||
}),
|
||||
API.config.get().then((res) => {
|
||||
setConfig(res.data);
|
||||
setUpdatesAvailable(res.updates);
|
||||
setSelfName(res.hostname);
|
||||
})]);
|
||||
};
|
||||
|
||||
|
@ -49,7 +53,7 @@ const ContainerIndex = () => {
|
|||
tabs={[
|
||||
{
|
||||
title: 'Overview',
|
||||
children: <ContainerOverview refresh={refreshContainer} containerInfo={container} config={config}/>
|
||||
children: <ContainerOverview updatesAvailable={updatesAvailable} selfName={selfName} refresh={refreshContainer} containerInfo={container} config={config}/>
|
||||
},
|
||||
{
|
||||
title: 'Logs',
|
||||
|
|
|
@ -15,7 +15,7 @@ const info = {
|
|||
borderRadius: '5px',
|
||||
}
|
||||
|
||||
const ContainerOverview = ({ containerInfo, config, refresh }) => {
|
||||
const ContainerOverview = ({ containerInfo, config, refresh, updatesAvailable, selfName }) => {
|
||||
const isMobile = useMediaQuery((theme) => theme.breakpoints.down('sm'));
|
||||
const [openModal, setOpenModal] = React.useState(false);
|
||||
const [openRestartModal, setOpenRestartModal] = React.useState(false);
|
||||
|
@ -99,6 +99,7 @@ const ContainerOverview = ({ containerInfo, config, refresh }) => {
|
|||
setIsUpdatingId={() => {
|
||||
setIsUpdating(true);
|
||||
}}
|
||||
updateAvailable={updatesAvailable && updatesAvailable[Name]}
|
||||
/>
|
||||
</Stack>
|
||||
{containerInfo.State.Status !== 'running' && (
|
||||
|
@ -133,7 +134,8 @@ const ContainerOverview = ({ containerInfo, config, refresh }) => {
|
|||
</Stack>
|
||||
<Stack style={{ fontSize: '80%' }} direction={"row"} alignItems="center">
|
||||
<Checkbox
|
||||
checked={Config.Labels['cosmos-auto-update'] === 'true'}
|
||||
checked={Config.Labels['cosmos-auto-update'] === 'true' ||
|
||||
(selfName && Name.replace('/', '') == selfName && config.AutoUpdate)}
|
||||
disabled={isUpdating}
|
||||
onChange={(e) => {
|
||||
setIsUpdating(true);
|
||||
|
|
|
@ -45,6 +45,7 @@ const ServeApps = () => {
|
|||
const [newRoute, setNewRoute] = useState(null);
|
||||
const [submitErrors, setSubmitErrors] = useState([]);
|
||||
const [openRestartModal, setOpenRestartModal] = useState(false);
|
||||
const [selfName, setSelfName] = useState("");
|
||||
|
||||
const refreshServeApps = () => {
|
||||
API.docker.list().then((res) => {
|
||||
|
@ -53,6 +54,7 @@ const ServeApps = () => {
|
|||
API.config.get().then((res) => {
|
||||
setConfig(res.data);
|
||||
setUpdatesAvailable(res.updates);
|
||||
setSelfName(res.hostname);
|
||||
});
|
||||
setIsUpdating({});
|
||||
};
|
||||
|
@ -194,7 +196,7 @@ const ServeApps = () => {
|
|||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2} width='100%'>
|
||||
<Stack direction="row" spacing={1} width='100%'>
|
||||
<GetActions
|
||||
Id={app.Names[0].replace('/', '')}
|
||||
image={app.Image}
|
||||
|
@ -256,7 +258,8 @@ const ServeApps = () => {
|
|||
</Stack>
|
||||
<Stack style={{ fontSize: '80%' }} direction={"row"} alignItems="center">
|
||||
<Checkbox
|
||||
checked={app.Labels['cosmos-auto-update'] === 'true'}
|
||||
checked={app.Labels['cosmos-auto-update'] === 'true' ||
|
||||
(selfName && app.Names[0].replace('/', '') == selfName && config.AutoUpdate)}
|
||||
disabled={app.State !== 'running'}
|
||||
onChange={(e) => {
|
||||
const name = app.Names[0].replace('/', '');
|
||||
|
|
|
@ -12,8 +12,6 @@ fi
|
|||
|
||||
echo "Pushing azukaar/cosmos-server:$VERSION and azukaar/cosmos-server:$LATEST"
|
||||
|
||||
sh build.arm64.sh
|
||||
|
||||
docker build \
|
||||
-t azukaar/cosmos-server:$VERSION-arm64 \
|
||||
-t azukaar/cosmos-server:$LATEST-arm64 \
|
||||
|
|
|
@ -12,8 +12,6 @@ fi
|
|||
|
||||
echo "Pushing azukaar/cosmos-server:$VERSION and azukaar/cosmos-server:$LATEST"
|
||||
|
||||
sh build.sh
|
||||
|
||||
docker build \
|
||||
-t azukaar/cosmos-server:$VERSION \
|
||||
-t azukaar/cosmos-server:$LATEST \
|
||||
|
|
30
dockerfile
30
dockerfile
|
@ -10,11 +10,29 @@ RUN apt-get update && apt-get install -y ca-certificates openssl
|
|||
|
||||
WORKDIR /app
|
||||
|
||||
COPY build/cosmos .
|
||||
COPY build/cosmos_gray.png .
|
||||
COPY build/Logo.png .
|
||||
COPY build/GeoLite2-Country.mmdb .
|
||||
COPY build/meta.json .
|
||||
COPY static ./static
|
||||
# install go 1.20.2
|
||||
RUN apt-get install -y wget curl
|
||||
RUN wget https://golang.org/dl/go1.20.2.linux-amd64.tar.gz
|
||||
RUN tar -C /usr/local -xzf go1.20.2.linux-amd64.tar.gz
|
||||
ENV PATH=$PATH:/usr/local/go/bin
|
||||
|
||||
# install nodejs 18.16.0
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
|
||||
RUN apt-get install -y nodejs
|
||||
|
||||
COPY go.mod ./
|
||||
COPY go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY package.json ./
|
||||
COPY package-lock.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
RUN ls
|
||||
RUN npm run client-build
|
||||
RUN ./build.sh
|
||||
|
||||
WORKDIR /app/build
|
||||
|
||||
CMD ["./cosmos"]
|
||||
|
|
|
@ -6,17 +6,33 @@ EXPOSE 443 80
|
|||
|
||||
VOLUME /config
|
||||
|
||||
RUN apt-get clean
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y ca-certificates openssl
|
||||
RUN apt-get update && apt-get install -y ca-certificates openssl
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY build/cosmos .
|
||||
COPY build/cosmos_gray.png .
|
||||
COPY build/Logo.png .
|
||||
COPY build/GeoLite2-Country.mmdb .
|
||||
COPY build/meta.json .
|
||||
COPY static ./static
|
||||
# install go 1.20.2
|
||||
RUN apt-get install -y wget curl
|
||||
RUN wget https://golang.org/dl/go1.20.2.linux-amd64.tar.gz
|
||||
RUN tar -C /usr/local -xzf go1.20.2.linux-amd64.tar.gz
|
||||
ENV PATH=$PATH:/usr/local/go/bin
|
||||
|
||||
# install nodejs 18.16.0
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
|
||||
RUN apt-get install -y nodejs
|
||||
|
||||
COPY go.mod ./
|
||||
COPY go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY package.json ./
|
||||
COPY package-lock.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
RUN ls
|
||||
RUN npm run client-build
|
||||
RUN ./build.sh
|
||||
|
||||
WORKDIR /app/build
|
||||
|
||||
CMD ["./cosmos"]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "cosmos-server",
|
||||
"version": "0.5.11",
|
||||
"version": "0.5.12-unstable",
|
||||
"description": "",
|
||||
"main": "test-server.js",
|
||||
"bugs": {
|
||||
|
@ -61,6 +61,7 @@
|
|||
"dockerdevbuild": "sh build.sh && docker build --tag cosmos-dev .",
|
||||
"dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run -d -p 80:80 -p 443:443 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev",
|
||||
"dockerdev": "npm run dockerdevbuild && npm run dockerdevrun",
|
||||
"dockerdevclient": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun",
|
||||
"demo": "vite build --base=/ui/ --mode demo",
|
||||
"devdemo": "vite --mode demo"
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ package configapi
|
|||
import (
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
)
|
||||
|
||||
|
@ -40,6 +41,7 @@ func ConfigApiGet(w http.ResponseWriter, req *http.Request) {
|
|||
"status": "OK",
|
||||
"data": config,
|
||||
"updates": utils.UpdateAvailable,
|
||||
"hostname": os.Getenv("HOSTNAME"),
|
||||
})
|
||||
} else {
|
||||
utils.Error("SettingGet: Method not allowed" + req.Method, nil)
|
||||
|
|
|
@ -20,8 +20,13 @@ func AutoUpdateContainerRoute(w http.ResponseWriter, req *http.Request) {
|
|||
status := utils.Sanitize(vars["status"])
|
||||
|
||||
if os.Getenv("HOSTNAME") != "" && containerName == os.Getenv("HOSTNAME") {
|
||||
utils.Error("AutoUpdateContainerRoute - Container cannot update itself", nil)
|
||||
utils.HTTPError(w, "Container cannot update itself", http.StatusBadRequest, "DS003")
|
||||
config := utils.ReadConfigFromFile()
|
||||
config.AutoUpdate = status == "true"
|
||||
utils.SaveConfigTofile(config)
|
||||
utils.Log("API: Set Auto Update "+status+" : " + containerName)
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"status": "OK",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ type DockerServiceCreateRollback struct {
|
|||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func Rollback(actions []DockerServiceCreateRollback , w http.ResponseWriter, flusher http.Flusher) {
|
||||
func Rollback(actions []DockerServiceCreateRollback , OnLog func(string)) {
|
||||
for i := len(actions) - 1; i >= 0; i-- {
|
||||
action := actions[i]
|
||||
switch action.Type {
|
||||
|
@ -126,8 +126,7 @@ func Rollback(actions []DockerServiceCreateRollback , w http.ResponseWriter, flu
|
|||
utils.Error("Rollback: Container", err)
|
||||
} else {
|
||||
utils.Log(fmt.Sprintf("Rolled back container %s", action.Name))
|
||||
fmt.Fprintf(w, "Rolled back container %s\n", action.Name)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Rolled back container %s\n", action.Name))
|
||||
}
|
||||
case "volume":
|
||||
err := DockerClient.VolumeRemove(DockerContext, action.Name, true)
|
||||
|
@ -135,8 +134,7 @@ func Rollback(actions []DockerServiceCreateRollback , w http.ResponseWriter, flu
|
|||
utils.Error("Rollback: Volume", err)
|
||||
} else {
|
||||
utils.Log(fmt.Sprintf("Rolled back volume %s", action.Name))
|
||||
fmt.Fprintf(w, "Rolled back volume %s\n", action.Name)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Rolled back volume %s\n", action.Name))
|
||||
}
|
||||
case "network":
|
||||
if os.Getenv("HOSTNAME") != "" {
|
||||
|
@ -147,16 +145,14 @@ func Rollback(actions []DockerServiceCreateRollback , w http.ResponseWriter, flu
|
|||
utils.Error("Rollback: Network", err)
|
||||
} else {
|
||||
utils.Log(fmt.Sprintf("Rolled back network %s", action.Name))
|
||||
fmt.Fprintf(w, "Rolled back network %s\n", action.Name)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Rolled back network %s\n", action.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After all operations
|
||||
utils.Error("CreateService", fmt.Errorf("Operation failed. Changes have been rolled back."))
|
||||
fmt.Fprintf(w, "[OPERATION FAILED]. CHANGES HAVE BEEN ROLLEDBACK.\n")
|
||||
flusher.Flush()
|
||||
OnLog("[OPERATION FAILED]. CHANGES HAVE BEEN ROLLEDBACK.\n")
|
||||
}
|
||||
|
||||
func CreateServiceRoute(w http.ResponseWriter, req *http.Request) {
|
||||
|
@ -192,7 +188,12 @@ func CreateServiceRoute(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
CreateService(w, req, serviceRequest)
|
||||
CreateService(serviceRequest,
|
||||
func (msg string) {
|
||||
fmt.Fprintf(w, msg)
|
||||
flusher.Flush()
|
||||
},
|
||||
)
|
||||
} else {
|
||||
utils.Error("CreateService: Method not allowed" + req.Method, nil)
|
||||
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
||||
|
@ -201,23 +202,12 @@ func CreateServiceRoute(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
|
||||
func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest DockerServiceCreateRequest) error {
|
||||
// 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 errors.New("Streaming unsupported!")
|
||||
}
|
||||
|
||||
func CreateService(serviceRequest DockerServiceCreateRequest, OnLog func(string)) error {
|
||||
utils.ConfigLock.Lock()
|
||||
defer utils.ConfigLock.Unlock()
|
||||
|
||||
utils.Log("Starting creation of new service...")
|
||||
fmt.Fprintf(w, "Starting creation of new service...\n")
|
||||
flusher.Flush()
|
||||
OnLog("Starting creation of new service...\n")
|
||||
|
||||
config := utils.ReadConfigFromFile()
|
||||
configRoutes := config.HTTPConfig.ProxyConfig.Routes
|
||||
|
@ -228,20 +218,17 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
// check if services have the cosmos-force-network-secured label
|
||||
for serviceName, service := range serviceRequest.Services {
|
||||
utils.Log(fmt.Sprintf("Checking service %s...", serviceName))
|
||||
fmt.Fprintf(w, "Checking service %s...\n", serviceName)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Checking service %s...\n", serviceName))
|
||||
|
||||
if service.Labels["cosmos-force-network-secured"] == "true" {
|
||||
utils.Log(fmt.Sprintf("Forcing secure %s...", serviceName))
|
||||
fmt.Fprintf(w, "Forcing secure %s...\n", serviceName)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Forcing secure %s...\n", serviceName))
|
||||
|
||||
newNetwork, errNC := CreateCosmosNetwork()
|
||||
if errNC != nil {
|
||||
utils.Error("CreateService: Network", err)
|
||||
fmt.Fprintf(w, "[ERROR] Network %s cant be created\n", newNetwork)
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Network %s cant be created\n", newNetwork))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -262,24 +249,21 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
})
|
||||
|
||||
utils.Log(fmt.Sprintf("Created secure network %s", newNetwork))
|
||||
fmt.Fprintf(w, "Created secure network %s\n", newNetwork)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Created secure network %s\n", newNetwork))
|
||||
}
|
||||
}
|
||||
|
||||
// Create networks
|
||||
for networkToCreateName, networkToCreate := range serviceRequest.Networks {
|
||||
utils.Log(fmt.Sprintf("Creating network %s...", networkToCreateName))
|
||||
fmt.Fprintf(w, "Creating network %s...\n", networkToCreateName)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Creating network %s...\n", networkToCreateName))
|
||||
|
||||
// check if network already exists
|
||||
_, err = DockerClient.NetworkInspect(DockerContext, networkToCreateName, doctype.NetworkInspectOptions{})
|
||||
if err == nil {
|
||||
utils.Error("CreateService: Network", err)
|
||||
fmt.Fprintf(w, "[ERROR] Network %s already exists\n", networkToCreateName)
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Network %s already exists\n", networkToCreateName))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -305,9 +289,8 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
|
||||
if err != nil {
|
||||
utils.Error("CreateService: Rolling back changes because of -- Network", err)
|
||||
fmt.Fprintf(w, "[ERROR] Rolling back changes because of -- Network creation error: "+err.Error())
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Rolling back changes because of -- Network creation error: %s\n", err.Error()))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -319,15 +302,13 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
|
||||
// Write a response to the client
|
||||
utils.Log(fmt.Sprintf("Network %s created", networkToCreateName))
|
||||
fmt.Fprintf(w, "Network %s created\n", networkToCreateName)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Network %s created\n", networkToCreateName))
|
||||
}
|
||||
|
||||
// Create volumes
|
||||
for _, volume := range serviceRequest.Volumes {
|
||||
utils.Log(fmt.Sprintf("Creating volume %s...", volume.Name))
|
||||
fmt.Fprintf(w, "Creating volume %s...\n", volume.Name)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Creating volume %s...\n", volume.Name))
|
||||
|
||||
_, err = DockerClient.VolumeCreate(DockerContext, volumetype.CreateOptions{
|
||||
Driver: volume.Driver,
|
||||
|
@ -336,9 +317,8 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
|
||||
if err != nil {
|
||||
utils.Error("CreateService: Rolling back changes because of -- Volume", err)
|
||||
fmt.Fprintf(w, "[ERROR] Rolling back changes because of -- Volume creation error: "+err.Error())
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Rolling back changes because of -- Volume creation error: %s\n", err.Error()))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -350,23 +330,20 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
|
||||
// Write a response to the client
|
||||
utils.Log(fmt.Sprintf("Volume %s created", volume.Name))
|
||||
fmt.Fprintf(w, "Volume %s created\n", volume.Name)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Volume %s created\n", volume.Name))
|
||||
}
|
||||
|
||||
// pull images
|
||||
for _, container := range serviceRequest.Services {
|
||||
// Write a response to the client
|
||||
utils.Log(fmt.Sprintf("Pulling image %s", container.Image))
|
||||
fmt.Fprintf(w, "Pulling image %s\n", container.Image)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Pulling image %s\n", container.Image))
|
||||
|
||||
out, err := DockerClient.ImagePull(DockerContext, container.Image, doctype.ImagePullOptions{})
|
||||
if err != nil {
|
||||
utils.Error("CreateService: Rolling back changes because of -- Image pull", err)
|
||||
fmt.Fprintf(w, "[ERROR] Rolling back changes because of -- Image pull error: "+err.Error())
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Rolling back changes because of -- Image pull error: %s\n", err.Error()))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
@ -374,21 +351,18 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
// wait for image pull to finish
|
||||
scanner := bufio.NewScanner(out)
|
||||
for scanner.Scan() {
|
||||
fmt.Fprintf(w, "%s\n", scanner.Text())
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("%s\n", scanner.Text()))
|
||||
}
|
||||
|
||||
// Write a response to the client
|
||||
utils.Log(fmt.Sprintf("Image %s pulled", container.Image))
|
||||
fmt.Fprintf(w, "Image %s pulled\n", container.Image)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Image %s pulled\n", container.Image))
|
||||
}
|
||||
|
||||
// Create containers
|
||||
for _, container := range serviceRequest.Services {
|
||||
utils.Log(fmt.Sprintf("Creating container %s...", container.Name))
|
||||
fmt.Fprintf(w, "Creating container %s...\n", container.Name)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Creating container %s...\n", container.Name))
|
||||
|
||||
containerConfig := &conttype.Config{
|
||||
Image: container.Image,
|
||||
|
@ -443,29 +417,25 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
if os.Getenv("HOSTNAME") != "" {
|
||||
if _, err := os.Stat("/mnt/host"); os.IsNotExist(err) {
|
||||
utils.Error("CreateService: Unable to create directory for bind mount in the host directory. Please mount the host / in Cosmos with -v /:/mnt/host to enable folder creations, or create the bind folder yourself", err)
|
||||
fmt.Fprintf(w, "[ERROR] Unable to create directory for bind mount in the host directory. Please mount the host / in Cosmos with -v /:/mnt/host to enable folder creations, or create the bind folder yourself: "+err.Error())
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Unable to create directory for bind mount in the host directory. Please mount the host / in Cosmos with -v /:/mnt/host to enable folder creations, or create the bind folder yourself: %s\n", err.Error()))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
newSource = "/mnt/host" + newSource
|
||||
}
|
||||
|
||||
utils.Log(fmt.Sprintf("Checking directory %s for bind mount", newSource))
|
||||
fmt.Fprintf(w, "Checking directory %s for bind mount\n", newSource)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Checking directory %s for bind mount\n", newSource))
|
||||
|
||||
if _, err := os.Stat(newSource); os.IsNotExist(err) {
|
||||
utils.Log(fmt.Sprintf("Not found. Creating directory %s for bind mount", newSource))
|
||||
fmt.Fprintf(w, "Not found. Creating directory %s for bind mount\n", newSource)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Not found. Creating directory %s for bind mount\n", newSource))
|
||||
|
||||
err := os.MkdirAll(newSource, 0755)
|
||||
if err != nil {
|
||||
utils.Error("CreateService: Unable to create directory for bind mount. Make sure parent directories exist, and that Cosmos has permissions to create directories in the host directory", err)
|
||||
fmt.Fprintf(w, "[ERROR] Unable to create directory for bind mount. Make sure parent directories exist, and that Cosmos has permissions to create directories in the host directory for bind mount: "+err.Error())
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Unable to create directory for bind mount. Make sure parent directories exist, and that Cosmos has permissions to create directories in the host directory: %s\n", err.Error()))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -474,16 +444,14 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
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 " + container.User + "." +err.Error())
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("[ERROR] Unable to lookup user " + container.User + "." +err.Error()))
|
||||
} else {
|
||||
uid, _ := strconv.Atoi(userInfo.Uid)
|
||||
gid, _ := strconv.Atoi(userInfo.Gid)
|
||||
err = os.Chown(newSource, 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()
|
||||
OnLog(fmt.Sprintf("[ERROR] Unable to change ownership of directory: " + err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -553,9 +521,8 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
|
||||
if err != nil {
|
||||
utils.Error("CreateService: Rolling back changes because of -- Container", err)
|
||||
fmt.Fprintf(w, "[ERROR] Rolling back changes because of -- Container creation error: "+err.Error())
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Rolling back changes because of -- Container creation error: "+err.Error()))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -579,26 +546,23 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
configRoutes = append([]utils.ProxyRouteConfig{(utils.ProxyRouteConfig)(route)}, configRoutes...)
|
||||
} else {
|
||||
utils.Error("CreateService: Rolling back changes because of -- Route already exist", nil)
|
||||
fmt.Fprintf(w, "[ERROR] Rolling back changes because of -- Route already exist")
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Rolling back changes because of -- Route already exist"))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return errors.New("Route already exist")
|
||||
}
|
||||
}
|
||||
|
||||
// Write a response to the client
|
||||
utils.Log(fmt.Sprintf("Container %s created", container.Name))
|
||||
fmt.Fprintf(w, "Container %s created\n", container.Name)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Container %s created", container.Name))
|
||||
}
|
||||
|
||||
// re-order containers dpeneding on depends_on
|
||||
startOrder, err := ReOrderServices(serviceRequest.Services)
|
||||
if err != nil {
|
||||
utils.Error("CreateService: Rolling back changes because of -- Container", err)
|
||||
fmt.Fprintf(w, "[ERROR] Rolling back changes because of -- Container creation error: "+err.Error())
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Rolling back changes because of -- Container creation error: "+err.Error()))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -607,16 +571,14 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
err = DockerClient.ContainerStart(DockerContext, container.Name, doctype.ContainerStartOptions{})
|
||||
if err != nil {
|
||||
utils.Error("CreateService: Start Container", err)
|
||||
fmt.Fprintf(w, "[ERROR] Rolling back changes because of -- Container start error: "+err.Error())
|
||||
flusher.Flush()
|
||||
Rollback(rollbackActions, w, flusher)
|
||||
OnLog(fmt.Sprintf("[ERROR] Rolling back changes because of -- Container start error: "+err.Error()))
|
||||
Rollback(rollbackActions, OnLog)
|
||||
return err
|
||||
}
|
||||
|
||||
// Write a response to the client
|
||||
utils.Log(fmt.Sprintf("Container %s started", container.Name))
|
||||
fmt.Fprintf(w, "Container %s started\n", container.Name)
|
||||
flusher.Flush()
|
||||
OnLog(fmt.Sprintf("Container %s started", container.Name))
|
||||
}
|
||||
|
||||
// Save the route configs
|
||||
|
@ -626,8 +588,7 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock
|
|||
|
||||
// After all operations
|
||||
utils.Log("CreateService: Operation succeeded. SERVICE STARTED")
|
||||
fmt.Fprintf(w, "[OPERATION SUCCEEDED]. SERVICE STARTED\n")
|
||||
flusher.Flush()
|
||||
OnLog("[OPERATION SUCCEEDED]. SERVICE STARTED\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ func ManageContainerRoute(w http.ResponseWriter, req *http.Request) {
|
|||
// stop, start, restart, kill, remove, pause, unpause, recreate
|
||||
action := utils.Sanitize(vars["action"])
|
||||
|
||||
if os.Getenv("HOSTNAME") != "" && containerName == os.Getenv("HOSTNAME") {
|
||||
if os.Getenv("HOSTNAME") != "" && containerName == os.Getenv("HOSTNAME") && action != "update" && action != "recreate" {
|
||||
utils.Error("ManageContainer - Container cannot update itself", nil)
|
||||
utils.HTTPError(w, "Container cannot update itself", http.StatusBadRequest, "DS003")
|
||||
return
|
||||
|
@ -68,7 +68,7 @@ func ManageContainerRoute(w http.ResponseWriter, req *http.Request) {
|
|||
case "unpause":
|
||||
err = DockerClient.ContainerUnpause(DockerContext, container.ID)
|
||||
case "recreate":
|
||||
_, err = EditContainer(container.ID, container, false)
|
||||
_, err = RecreateContainer(container.Name, container)
|
||||
case "update":
|
||||
out, errPull := DockerClient.ImagePull(DockerContext, imagename, doctype.ImagePullOptions{})
|
||||
if errPull != nil {
|
||||
|
@ -100,7 +100,7 @@ func ManageContainerRoute(w http.ResponseWriter, req *http.Request) {
|
|||
|
||||
utils.Log("Container Update - Image pulled " + imagename)
|
||||
|
||||
_, err = EditContainer(container.ID, container, false)
|
||||
_, err = RecreateContainer(container.Name, container)
|
||||
|
||||
if err != nil {
|
||||
utils.Error("Container Update - EditContainer", err)
|
||||
|
|
|
@ -10,8 +10,10 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
"strconv"
|
||||
"runtime"
|
||||
"github.com/azukaar/cosmos-server/src/utils"
|
||||
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
// natting "github.com/docker/go-connections/nat"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
@ -86,6 +88,19 @@ func Connect() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func RecreateContainer(containerID string, containerConfig types.ContainerJSON) (string, error) {
|
||||
if os.Getenv("HOSTNAME") != "" && os.Getenv("HOSTNAME") == containerID[1:] {
|
||||
err := SelfRecreate()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
return EditContainer(containerID, containerConfig, false)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func EditContainer(oldContainerID string, newConfig types.ContainerJSON, noLock bool) (string, error) {
|
||||
if(oldContainerID != "" && !noLock) {
|
||||
// no need to re-lock if we are reverting
|
||||
|
@ -424,6 +439,19 @@ func Test() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func HasAutoUpdateOn(containerConfig types.ContainerJSON) bool {
|
||||
if containerConfig.Config.Labels["cosmos-auto-update"] == "true" {
|
||||
return true
|
||||
}
|
||||
|
||||
config := utils.ReadConfigFromFile()
|
||||
|
||||
if os.Getenv("HOSTNAME") == containerConfig.Name[1:] && config.AutoUpdate {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func CheckUpdatesAvailable() map[string]bool {
|
||||
result := make(map[string]bool)
|
||||
|
@ -468,7 +496,7 @@ func CheckUpdatesAvailable() map[string]bool {
|
|||
utils.Log("Updates available for " + container.Image)
|
||||
|
||||
result[container.Names[0]] = true
|
||||
if !IsLabel(fullContainer, "cosmos-auto-update") {
|
||||
if !HasAutoUpdateOn(fullContainer) {
|
||||
rc.Close()
|
||||
break
|
||||
} else {
|
||||
|
@ -477,7 +505,7 @@ func CheckUpdatesAvailable() map[string]bool {
|
|||
} else if strings.Contains(newStr, "\"status\":\"Status: Image is up to date") {
|
||||
utils.Log("No updates available for " + container.Image)
|
||||
|
||||
if !IsLabel(fullContainer, "cosmos-auto-update") {
|
||||
if !HasAutoUpdateOn(fullContainer) {
|
||||
rc.Close()
|
||||
break
|
||||
}
|
||||
|
@ -505,9 +533,9 @@ func CheckUpdatesAvailable() map[string]bool {
|
|||
}
|
||||
}
|
||||
|
||||
if needsUpdate && IsLabel(fullContainer, "cosmos-auto-update") {
|
||||
if needsUpdate && HasAutoUpdateOn(fullContainer) {
|
||||
utils.Log("Downlaoded new update for " + container.Image + " ready to install")
|
||||
_, err := EditContainer(container.ID, fullContainer, false)
|
||||
_, err := RecreateContainer(container.Names[0], fullContainer)
|
||||
if err != nil {
|
||||
utils.Error("CheckUpdatesAvailable - Failed to update - ", err)
|
||||
} else {
|
||||
|
@ -518,3 +546,82 @@ func CheckUpdatesAvailable() map[string]bool {
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
func RemoveSelfUpdater() error {
|
||||
utils.Log("Checking for self updater agent")
|
||||
|
||||
// look for a container with the name cosmos-self-updater-agent
|
||||
containers, err := ListContainers()
|
||||
if err != nil {
|
||||
utils.Error("RemoveSelfUpdater", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, container := range containers {
|
||||
if container.Names[0] == "/cosmos-self-updater-agent" {
|
||||
utils.Log("Found. Removing self updater agent")
|
||||
err := DockerClient.ContainerKill(DockerContext, container.ID, "SIGKILL")
|
||||
if err != nil {
|
||||
utils.Error("RemoveSelfUpdater", err)
|
||||
}
|
||||
err = DockerClient.ContainerRemove(DockerContext, container.ID, types.ContainerRemoveOptions{
|
||||
Force: true,
|
||||
})
|
||||
if err != nil {
|
||||
utils.Error("RemoveSelfUpdater", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SelfRecreate() error {
|
||||
if os.Getenv("HOSTNAME") == "" {
|
||||
utils.Error("SelfRecreate - not using Docker", nil)
|
||||
return errors.New("SelfRecreate - not using Docker")
|
||||
}
|
||||
|
||||
// make sure to remove resiude of old self updater
|
||||
RemoveSelfUpdater()
|
||||
|
||||
containerName := os.Getenv("HOSTNAME")
|
||||
|
||||
version := "latest"
|
||||
|
||||
// if arm
|
||||
if runtime.GOARCH == "arm" {
|
||||
version = "latest-arm64"
|
||||
}
|
||||
|
||||
service := DockerServiceCreateRequest{
|
||||
Services: map[string]ContainerCreateRequestContainer {},
|
||||
}
|
||||
|
||||
service.Services["cosmos-self-updater-agent"] = ContainerCreateRequestContainer{
|
||||
Name: "cosmos-self-updater-agent",
|
||||
Image: "azukaar/docker-self-updater:" + version,
|
||||
RestartPolicy: "no",
|
||||
Environment: []string{
|
||||
"CONTAINER_NAME=" + containerName,
|
||||
"ACTION=recreate",
|
||||
"DOCKER_HOST=" + os.Getenv("DOCKER_HOST"),
|
||||
},
|
||||
Volumes: []mountType.Mount{
|
||||
{
|
||||
Type: mountType.TypeBind,
|
||||
Source: "/var/run/docker.sock",
|
||||
Target: "/var/run/docker.sock",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
err := CreateService(service, func (msg string) {})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -29,8 +29,13 @@ func NewDB(w http.ResponseWriter, req *http.Request) (string, error) {
|
|||
|
||||
imageName := "mongo:latest"
|
||||
|
||||
//if ARM use amd64/mongo
|
||||
if runtime.GOARCH == "arm64" {
|
||||
utils.Warn("ARM64 detected. Using ARM mongo 4.4")
|
||||
imageName = "amd64/mongo:4.4"
|
||||
|
||||
// if CPU is missing AVX, use 4.4
|
||||
if runtime.GOARCH == "amd64" && !cpu.X86.HasAVX {
|
||||
} else if runtime.GOARCH == "amd64" && !cpu.X86.HasAVX {
|
||||
utils.Warn("CPU does not support AVX. Using mongo 4.4")
|
||||
imageName = "mongo:4.4"
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ func main() {
|
|||
|
||||
docker.BootstrapAllContainersFromTags()
|
||||
|
||||
docker.RemoveSelfUpdater()
|
||||
|
||||
version, err := docker.DockerClient.ServerVersion(context.Background())
|
||||
if err == nil {
|
||||
utils.Log("Docker API version: " + version.APIVersion)
|
||||
|
|
|
@ -15,10 +15,6 @@ export default defineConfig({
|
|||
secure: false,
|
||||
ws: true,
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
usePolling: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue