underpost 2.81.1 → 2.85.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.production +1 -0
- package/.github/workflows/npmpkg.ci.yml +3 -15
- package/.github/workflows/release.cd.yml +3 -4
- package/Dockerfile +3 -1
- package/README.md +2 -2
- package/bin/deploy.js +1 -1
- package/bin/zed.js +5 -2
- package/cli.md +25 -14
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/manifests/deployment/mongo-express/deployment.yaml +2 -0
- package/package.json +2 -2
- package/scripts/rocky-setup.sh +144 -0
- package/src/cli/cluster.js +4 -1
- package/src/cli/deploy.js +113 -18
- package/src/cli/env.js +4 -2
- package/src/cli/image.js +3 -2
- package/src/cli/index.js +8 -1
- package/src/cli/repository.js +66 -9
- package/src/cli/run.js +208 -23
- package/src/client/components/core/Router.js +6 -1
- package/src/client/services/core/core.service.js +4 -2
- package/src/index.js +1 -1
package/.env.production
CHANGED
|
@@ -10,7 +10,9 @@ permissions:
|
|
|
10
10
|
id-token: write
|
|
11
11
|
jobs:
|
|
12
12
|
pwa-microservices-template:
|
|
13
|
-
if:
|
|
13
|
+
if: |
|
|
14
|
+
github.repository == 'underpostnet/engine'
|
|
15
|
+
&& startsWith(github.event.head_commit.message, 'ci(package-pwa-microservices-template')
|
|
14
16
|
name: Update npm repo package Jobs
|
|
15
17
|
runs-on: ubuntu-latest
|
|
16
18
|
container:
|
|
@@ -56,17 +58,3 @@ jobs:
|
|
|
56
58
|
git config user.email 'fcoverdugoa@underpost.net'
|
|
57
59
|
underpost cmt . ci package-pwa-microservices-template-ghpkg 'Update npm repo package'
|
|
58
60
|
underpost push . underpostnet/pwa-microservices-template
|
|
59
|
-
# cd ../engine
|
|
60
|
-
# git commit --allow-empty -m "ci(engine-core-repo-build): ⚙️ Update engine core repository"
|
|
61
|
-
# git commit --allow-empty -m "ci(engine-cyberia-repo-build): ⚙️ Update engine cyberia repository"
|
|
62
|
-
# git commit --allow-empty -m "ci(engine-lampp-repo-build): ⚙️ Update engine lampp repository"
|
|
63
|
-
# git push https://${{ secrets.GIT_AUTH_TOKEN }}@github.com/underpostnet/engine.git
|
|
64
|
-
|
|
65
|
-
# git clone --bare https://github.com/underpostnet/engine.git
|
|
66
|
-
# mkdir engine
|
|
67
|
-
# mv ./engine.git ./engine/.git
|
|
68
|
-
# cd engine
|
|
69
|
-
# git init
|
|
70
|
-
|
|
71
|
-
# git push -u origin https://${{ secrets.GIT_AUTH_TOKEN }}@github.com/underpostnet/pwa-microservices-template-ghpkg.git
|
|
72
|
-
# git push -u origin master
|
|
@@ -28,10 +28,9 @@ jobs:
|
|
|
28
28
|
script: |
|
|
29
29
|
set -e
|
|
30
30
|
echo "Starting remote release deploy"
|
|
31
|
-
cd /home/dd/engine
|
|
32
|
-
npm install -g underpost
|
|
33
|
-
underpost run secret
|
|
34
31
|
underpost run pull
|
|
32
|
+
underpost run git-conf
|
|
35
33
|
underpost run secret
|
|
36
|
-
|
|
34
|
+
cd /home/dd/engine
|
|
35
|
+
underpost run template-deploy-image
|
|
37
36
|
underpost run ssh-deploy sync-engine-test
|
package/Dockerfile
CHANGED
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<!-- badges -->
|
|
20
20
|
|
|
21
|
-
[](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [](https://www.npmjs.com/package/underpost) [](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [](https://www.npmjs.com/package/underpost) [](https://socket.dev/npm/package/underpost/overview/2.85.1) [](https://coveralls.io/github/underpostnet/engine?branch=master) [](https://www.npmjs.org/package/underpost) [](https://www.npmjs.com/package/underpost)
|
|
22
22
|
|
|
23
23
|
<!-- end-badges -->
|
|
24
24
|
|
|
@@ -66,7 +66,7 @@ Run dev client server
|
|
|
66
66
|
npm run dev
|
|
67
67
|
```
|
|
68
68
|
<!-- -->
|
|
69
|
-
## underpost ci/cd cli v2.
|
|
69
|
+
## underpost ci/cd cli v2.85.1
|
|
70
70
|
|
|
71
71
|
### Usage: `underpost [options] [command]`
|
|
72
72
|
```
|
package/bin/deploy.js
CHANGED
|
@@ -499,7 +499,7 @@ try {
|
|
|
499
499
|
shellExec(`node bin/deploy sync-deploy-envs`);
|
|
500
500
|
shellExec(`node bin/build dd conf`);
|
|
501
501
|
shellExec(`git add . && cd ./engine-private && git add .`);
|
|
502
|
-
shellExec(`node bin cmt . ci package-pwa-microservices-template`);
|
|
502
|
+
shellExec(`node bin cmt . ci package-pwa-microservices-template 'New release v:${process.argv[3]}'`);
|
|
503
503
|
shellExec(`node bin cmt ./engine-private ci package-pwa-microservices-template`);
|
|
504
504
|
shellExec(`node bin push . ${process.env.GITHUB_USERNAME}/engine`);
|
|
505
505
|
shellExec(`cd ./engine-private && node ../bin push . ${process.env.GITHUB_USERNAME}/engine-private`);
|
package/bin/zed.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { shellExec } from '../src/server/process.js';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import { loggerFactory } from '../src/server/logger.js';
|
|
4
|
+
import { getUnderpostRootPath } from '../src/server/conf.js';
|
|
4
5
|
|
|
5
6
|
const logger = loggerFactory(import.meta);
|
|
7
|
+
const underpostRoot = getUnderpostRootPath();
|
|
6
8
|
|
|
7
|
-
fs.
|
|
8
|
-
fs.copyFileSync(
|
|
9
|
+
if (!fs.existsSync('/root/.config/zed')) fs.mkdirSync('/root/.config/zed', { recursive: true });
|
|
10
|
+
fs.copyFileSync(`${underpostRoot}/.vscode/zed.settings.json`, `/root/.config/zed/settings.json`);
|
|
11
|
+
fs.copyFileSync(`${underpostRoot}/.vscode/zed.keymap.json`, `/root/.config/zed/keymap.json`);
|
|
9
12
|
|
|
10
13
|
shellExec(`ZED_ALLOW_ROOT=true zed ${process.argv[2] ? process.argv[2] : '.'}`);
|
|
11
14
|
|
package/cli.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## underpost ci/cd cli v2.
|
|
1
|
+
## underpost ci/cd cli v2.85.1
|
|
2
2
|
|
|
3
3
|
### Usage: `underpost [options] [command]`
|
|
4
4
|
```
|
|
@@ -123,20 +123,30 @@ Manages commits to a GitHub repository, supporting various commit types and
|
|
|
123
123
|
options.
|
|
124
124
|
|
|
125
125
|
Arguments:
|
|
126
|
-
path
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
path The absolute or relative directory path of the
|
|
127
|
+
repository.
|
|
128
|
+
commit-type The type of commit to perform. Options: feat, fix,
|
|
129
|
+
docs, style, refactor, perf, ci, cd, infra, build,
|
|
130
|
+
test, chore, revert, backup.
|
|
131
|
+
module-tag Optional: Sets a specific module tag for the commit.
|
|
132
|
+
message Optional: Provides an additional custom message for
|
|
133
|
+
the commit.
|
|
132
134
|
|
|
133
135
|
Options:
|
|
134
|
-
--log
|
|
135
|
-
|
|
136
|
-
--
|
|
137
|
-
--
|
|
138
|
-
--
|
|
139
|
-
|
|
136
|
+
--log <latest-n> Shows commit history from the specified number of
|
|
137
|
+
latest n path commits.
|
|
138
|
+
--last-msg <latest-n> Displays the last n commit message.
|
|
139
|
+
--empty Allows committing with empty files.
|
|
140
|
+
--copy Copies the generated commit message to the
|
|
141
|
+
clipboard.
|
|
142
|
+
--info Displays information about available commit types.
|
|
143
|
+
--diff Shows the current git diff changes.
|
|
144
|
+
--edit Edit last commit.
|
|
145
|
+
--msg <msg> Sets a custom commit message.
|
|
146
|
+
--deploy-id <deploy-id> Sets the deployment configuration ID for the commit
|
|
147
|
+
context.
|
|
148
|
+
--cached Commit staged changes only or context.
|
|
149
|
+
-h, --help display help for command
|
|
140
150
|
|
|
141
151
|
```
|
|
142
152
|
|
|
@@ -613,7 +623,7 @@ Options:
|
|
|
613
623
|
Runs a script from the specified path.
|
|
614
624
|
|
|
615
625
|
Arguments:
|
|
616
|
-
runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, underpost-config, gpu-env, tf-gpu-test, dev-cluster, ssh-cluster-info, dev-hosts-expose, dev-hosts-restore, cyberia-ide, engine-ide, cluster-build, template-deploy, clean, pull, release-deploy, ssh-deploy, ide, sync, ls-deployments, monitor, db-client, promote, metrics, cluster, deploy, sync-replica, tf-vae-test, deploy-job.
|
|
626
|
+
runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, underpost-config, gpu-env, tf-gpu-test, dev-cluster, ssh-cluster-info, dev-hosts-expose, dev-hosts-restore, cyberia-ide, engine-ide, cluster-build, template-deploy, template-deploy-image, clean, pull, release-deploy, ssh-deploy, ide, sync, ls-deployments, host-update, dev-container, monitor, db-client, git-conf, promote, metrics, cluster, deploy, service, sync-replica, tf-vae-test, deploy-job.
|
|
617
627
|
path The absolute or relative directory path where the script is located.
|
|
618
628
|
|
|
619
629
|
Options:
|
|
@@ -631,6 +641,7 @@ Options:
|
|
|
631
641
|
--namespace <namespace> Optional: Specifies the namespace for test execution.
|
|
632
642
|
--kubeadm Flag to indicate Kubeadm cluster type context
|
|
633
643
|
--k3s Flag to indicate K3s cluster type context
|
|
644
|
+
--force Forces operation, overriding any warnings or conflicts.
|
|
634
645
|
-h, --help display help for command
|
|
635
646
|
|
|
636
647
|
```
|
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-default-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v2.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v2.85.1
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "124Ki"
|
|
@@ -100,7 +100,7 @@ spec:
|
|
|
100
100
|
spec:
|
|
101
101
|
containers:
|
|
102
102
|
- name: dd-default-development-green
|
|
103
|
-
image: localhost/rockylinux9-underpost:v2.
|
|
103
|
+
image: localhost/rockylinux9-underpost:v2.85.1
|
|
104
104
|
# resources:
|
|
105
105
|
# requests:
|
|
106
106
|
# memory: "124Ki"
|
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-test-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v2.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v2.85.1
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "96294Ki"
|
|
@@ -104,7 +104,7 @@ spec:
|
|
|
104
104
|
spec:
|
|
105
105
|
containers:
|
|
106
106
|
- name: dd-test-development-green
|
|
107
|
-
image: localhost/rockylinux9-underpost:v2.
|
|
107
|
+
image: localhost/rockylinux9-underpost:v2.85.1
|
|
108
108
|
# resources:
|
|
109
109
|
# requests:
|
|
110
110
|
# memory: "96294Ki"
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"type": "module",
|
|
3
3
|
"main": "src/index.js",
|
|
4
4
|
"name": "underpost",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.85.1",
|
|
6
6
|
"description": "pwa api rest template",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"proxy": "node src/proxy proxy",
|
|
19
19
|
"docs": "jsdoc -c jsdoc.json",
|
|
20
20
|
"install-global": "npm install -g pm2 && npm install -g jsdoc && npm install -g prettier && npm install -g env-cmd",
|
|
21
|
-
"install-test": "npm install -g mocha && npm install -g c8 && npm install -g
|
|
21
|
+
"install-test": "npm install -g mocha && npm install -g c8 && npm install -g coveralls",
|
|
22
22
|
"install-underpost": "cp -a $(npm root -g)/underpost/node_modules ./node_modules && npm install --only=dev --ignore-scripts",
|
|
23
23
|
"install": "npm run install-global && npm run install-test",
|
|
24
24
|
"prettier": "prettier --write .",
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# Script to install a recommended base package set on Rocky Linux.
|
|
6
|
+
# Usage examples:
|
|
7
|
+
# sudo ./scripts/rocky-setup.sh # interactive (will prompt about Development Tools)
|
|
8
|
+
# sudo ./scripts/rocky-setup.sh --install-dev # non-interactive: install Development Tools
|
|
9
|
+
# INSTALL_DEV=1 sudo ./scripts/rocky-setup.sh # same as --install-dev
|
|
10
|
+
# sudo ./scripts/rocky-setup.sh --yes # skip prompts and assume defaults
|
|
11
|
+
|
|
12
|
+
PACKAGES=(
|
|
13
|
+
dnf-plugins-core
|
|
14
|
+
epel-release
|
|
15
|
+
vim
|
|
16
|
+
nano
|
|
17
|
+
bash-completion
|
|
18
|
+
curl
|
|
19
|
+
wget
|
|
20
|
+
unzip
|
|
21
|
+
zip
|
|
22
|
+
tar
|
|
23
|
+
gzip
|
|
24
|
+
bzip2
|
|
25
|
+
rsync
|
|
26
|
+
git
|
|
27
|
+
python3
|
|
28
|
+
python3-pip
|
|
29
|
+
openssh-server
|
|
30
|
+
openssh-clients
|
|
31
|
+
firewalld
|
|
32
|
+
chrony
|
|
33
|
+
NetworkManager
|
|
34
|
+
which
|
|
35
|
+
net-tools
|
|
36
|
+
bind-utils
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Defaults
|
|
40
|
+
INSTALL_DEV=0
|
|
41
|
+
ASSUME_YES=0
|
|
42
|
+
|
|
43
|
+
# Parse CLI args (simple)
|
|
44
|
+
while [[ $# -gt 0 ]]; do
|
|
45
|
+
case "$1" in
|
|
46
|
+
--install-dev|--yes-dev)
|
|
47
|
+
INSTALL_DEV=1
|
|
48
|
+
shift
|
|
49
|
+
;;
|
|
50
|
+
--no-install-dev)
|
|
51
|
+
INSTALL_DEV=0
|
|
52
|
+
shift
|
|
53
|
+
;;
|
|
54
|
+
--yes|-y|--assume-yes)
|
|
55
|
+
ASSUME_YES=1
|
|
56
|
+
shift
|
|
57
|
+
;;
|
|
58
|
+
--help|-h)
|
|
59
|
+
cat <<EOF
|
|
60
|
+
Usage: sudo ./scripts/rocky-setup.sh [options]
|
|
61
|
+
|
|
62
|
+
Options:
|
|
63
|
+
--install-dev, --yes-dev Install Development Tools group (gcc, make, etc.)
|
|
64
|
+
--no-install-dev Explicitly skip Development Tools
|
|
65
|
+
--yes, -y, --assume-yes Assume defaults / non-interactive
|
|
66
|
+
--help, -h Show this help and exit
|
|
67
|
+
|
|
68
|
+
You can also set the environment variable INSTALL_DEV=1 to enable development tools.
|
|
69
|
+
EOF
|
|
70
|
+
exit 0
|
|
71
|
+
;;
|
|
72
|
+
*)
|
|
73
|
+
echo "Unknown argument: $1" >&2
|
|
74
|
+
exit 1
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
# Environment variable overrides (if set)
|
|
80
|
+
if [[ "${INSTALL_DEV:-}" =~ ^(1|y|yes|true)$ ]]; then
|
|
81
|
+
INSTALL_DEV=1
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Helper: prompt unless ASSUME_YES
|
|
85
|
+
prompt_install_dev() {
|
|
86
|
+
if [[ $ASSUME_YES -eq 1 ]]; then
|
|
87
|
+
return 1 # means do NOT prompt (we treat ASSUME_YES as 'no' for optional install unless INSTALL_DEV set)
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
read -r -p "Do you want to install the 'Development Tools' group (gcc, make, etc.)? [y/N]: " answer
|
|
91
|
+
if [[ "${answer,,}" == "y" || "${answer,,}" == "yes" ]]; then
|
|
92
|
+
return 0
|
|
93
|
+
fi
|
|
94
|
+
return 1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# Refresh cache and install basic packages
|
|
98
|
+
echo "[+] Refreshing DNF cache..."
|
|
99
|
+
sudo dnf makecache --refresh
|
|
100
|
+
|
|
101
|
+
echo "[+] Installing dnf-plugins-core and epel-release (if not present)..."
|
|
102
|
+
sudo dnf -y install dnf-plugins-core epel-release
|
|
103
|
+
|
|
104
|
+
echo "[+] Refreshing DNF cache after enabling repositories..."
|
|
105
|
+
sudo dnf makecache --refresh
|
|
106
|
+
|
|
107
|
+
echo "[+] Installing base packages: ${#PACKAGES[@]} packages"
|
|
108
|
+
sudo dnf -y install "${PACKAGES[@]}"
|
|
109
|
+
|
|
110
|
+
# Decide on Development Tools
|
|
111
|
+
if [[ $INSTALL_DEV -eq 1 ]]; then
|
|
112
|
+
echo "[+] Installing Development Tools (requested)..."
|
|
113
|
+
sudo dnf -y groupinstall "Development Tools"
|
|
114
|
+
else
|
|
115
|
+
if prompt_install_dev; then
|
|
116
|
+
echo "[+] Installing Development Tools (prompt confirmed)..."
|
|
117
|
+
sudo dnf -y groupinstall "Development Tools"
|
|
118
|
+
else
|
|
119
|
+
echo "[+] Skipping Development Tools. To auto-enable, run with --install-dev or set INSTALL_DEV=1"
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
echo "[+] Updating all packages to latest versions..."
|
|
124
|
+
sudo dnf -y update
|
|
125
|
+
|
|
126
|
+
# Cleanup
|
|
127
|
+
echo "[+] Cleanup: remove unnecessary packages and old metadata"
|
|
128
|
+
sudo dnf -y autoremove || true
|
|
129
|
+
sudo dnf clean all || true
|
|
130
|
+
|
|
131
|
+
cat <<EOF
|
|
132
|
+
|
|
133
|
+
Installation complete.
|
|
134
|
+
- To allow SSH access (if this is a VM or server), open port 22 in firewalld:
|
|
135
|
+
sudo firewall-cmd --add-service=ssh --permanent && sudo firewall-cmd --reload
|
|
136
|
+
- If you installed Development Tools, you will have gcc, make, etc.
|
|
137
|
+
|
|
138
|
+
Examples:
|
|
139
|
+
sudo ./scripts/rocky-setup.sh --install-dev
|
|
140
|
+
INSTALL_DEV=1 sudo ./scripts/rocky-setup.sh
|
|
141
|
+
sudo ./scripts/rocky-setup.sh --yes
|
|
142
|
+
|
|
143
|
+
Customize PACKAGES=(...) inside this script according to your needs (docker, podman, kube, mssql-tools, etc.).
|
|
144
|
+
EOF
|
package/src/cli/cluster.js
CHANGED
|
@@ -735,8 +735,11 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
735
735
|
initHost() {
|
|
736
736
|
const archData = UnderpostBaremetal.API.getHostArch();
|
|
737
737
|
logger.info('Installing essential host-level prerequisites for Kubernetes...', archData);
|
|
738
|
+
|
|
739
|
+
// Install base rocky setup and updates
|
|
740
|
+
shellExec(`node bin run host-update`);
|
|
741
|
+
|
|
738
742
|
// Install Docker and its dependencies
|
|
739
|
-
shellExec(`sudo dnf -y install dnf-plugins-core dbus-x11`);
|
|
740
743
|
shellExec(`sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo`);
|
|
741
744
|
shellExec(`sudo dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin`);
|
|
742
745
|
|
package/src/cli/deploy.js
CHANGED
|
@@ -85,21 +85,28 @@ class UnderpostDeploy {
|
|
|
85
85
|
/**
|
|
86
86
|
* Creates a YAML service configuration for a deployment.
|
|
87
87
|
* @param {string} deployId - Deployment ID for which the service is being created.
|
|
88
|
+
* @param {string} path - Path for which the service is being created.
|
|
88
89
|
* @param {string} env - Environment for which the service is being created.
|
|
89
90
|
* @param {number} port - Port number for the service.
|
|
90
91
|
* @param {Array<string>} deploymentVersions - List of deployment versions.
|
|
91
92
|
* @returns {string} - YAML service configuration for the specified deployment.
|
|
93
|
+
* @param {string} [serviceId] - Custom service name (optional).
|
|
92
94
|
* @memberof UnderpostDeploy
|
|
93
95
|
*/
|
|
94
|
-
deploymentYamlServiceFactory({ deployId, env, port, deploymentVersions }) {
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
deploymentYamlServiceFactory({ deployId, path, env, port, deploymentVersions, serviceId }) {
|
|
97
|
+
return `
|
|
98
|
+
- conditions:
|
|
99
|
+
- prefix: ${path}
|
|
100
|
+
enableWebsockets: true
|
|
101
|
+
services:
|
|
102
|
+
${deploymentVersions
|
|
103
|
+
.map(
|
|
104
|
+
(version, i) => ` - name: ${serviceId ? serviceId : `${deployId}-${env}-${version}-service`}
|
|
98
105
|
port: ${port}
|
|
99
106
|
weight: ${i === 0 ? 100 : 0}
|
|
100
107
|
`,
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
)
|
|
109
|
+
.join('')}`;
|
|
103
110
|
},
|
|
104
111
|
/**
|
|
105
112
|
* Creates a YAML deployment configuration for a deployment.
|
|
@@ -214,6 +221,9 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
|
|
|
214
221
|
|
|
215
222
|
let proxyYaml = '';
|
|
216
223
|
let secretYaml = '';
|
|
224
|
+
const customServices = fs.existsSync(`./engine-private/conf/${deployId}/conf.services.json`)
|
|
225
|
+
? JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.services.json`))
|
|
226
|
+
: [];
|
|
217
227
|
|
|
218
228
|
for (const host of Object.keys(confServer)) {
|
|
219
229
|
if (env === 'production') secretYaml += UnderpostDeploy.API.buildCertManagerCertificate({ host });
|
|
@@ -236,20 +246,33 @@ spec:
|
|
|
236
246
|
secretName: ${host}`
|
|
237
247
|
}
|
|
238
248
|
routes:`;
|
|
249
|
+
const deploymentVersions =
|
|
250
|
+
options.traffic && typeof options.traffic === 'string' ? options.traffic.split(',') : ['blue'];
|
|
239
251
|
for (const conditionObj of pathPortAssignment) {
|
|
240
252
|
const { path, port } = conditionObj;
|
|
241
|
-
proxyYaml +=
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
+
proxyYaml += UnderpostDeploy.API.deploymentYamlServiceFactory({
|
|
254
|
+
path,
|
|
255
|
+
deployId,
|
|
256
|
+
env,
|
|
257
|
+
port,
|
|
258
|
+
deploymentVersions,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
for (const customService of customServices) {
|
|
262
|
+
const { path: _path, port, serviceId, host: _host } = customService;
|
|
263
|
+
if (host === _host) {
|
|
264
|
+
switch (serviceId) {
|
|
265
|
+
case 'mongo-express-service': {
|
|
266
|
+
proxyYaml += UnderpostDeploy.API.deploymentYamlServiceFactory({
|
|
267
|
+
path: _path,
|
|
268
|
+
port,
|
|
269
|
+
serviceId,
|
|
270
|
+
deploymentVersions,
|
|
271
|
+
});
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
253
276
|
}
|
|
254
277
|
}
|
|
255
278
|
const yamlPath = `./engine-private/conf/${deployId}/build/${env}/proxy.yaml`;
|
|
@@ -579,6 +602,23 @@ EOF`);
|
|
|
579
602
|
* @memberof UnderpostDeploy
|
|
580
603
|
*/
|
|
581
604
|
existsContainerFile({ podName, path }) {
|
|
605
|
+
if (podName === 'kind-worker') {
|
|
606
|
+
const isFile = JSON.parse(
|
|
607
|
+
shellExec(`docker exec ${podName} sh -c 'test -f "$1" && echo true || echo false' sh ${path}`, {
|
|
608
|
+
stdout: true,
|
|
609
|
+
disableLog: true,
|
|
610
|
+
silent: true,
|
|
611
|
+
}).trim(),
|
|
612
|
+
);
|
|
613
|
+
const isFolder = JSON.parse(
|
|
614
|
+
shellExec(`docker exec ${podName} sh -c 'test -d "$1" && echo true || echo false' sh ${path}`, {
|
|
615
|
+
stdout: true,
|
|
616
|
+
disableLog: true,
|
|
617
|
+
silent: true,
|
|
618
|
+
}).trim(),
|
|
619
|
+
);
|
|
620
|
+
return isFolder || isFile;
|
|
621
|
+
}
|
|
582
622
|
return JSON.parse(
|
|
583
623
|
shellExec(`kubectl exec ${podName} -- test -f ${path} && echo "true" || echo "false"`, {
|
|
584
624
|
stdout: true,
|
|
@@ -704,6 +744,61 @@ EOF`);
|
|
|
704
744
|
}
|
|
705
745
|
logger.info(`${iteratorTag} | Deployment ready. | Total delay number check iterations: ${checkStatusIteration}`);
|
|
706
746
|
},
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Retrieves the currently loaded images in the Kubernetes cluster.
|
|
750
|
+
* @returns {Array<object>} - Array of objects containing pod names and their corresponding images.
|
|
751
|
+
* @memberof UnderpostDeploy
|
|
752
|
+
*/
|
|
753
|
+
getCurrentLoadedImages(node = 'kind-worker', specContainers = false) {
|
|
754
|
+
if (specContainers) {
|
|
755
|
+
const raw = shellExec(
|
|
756
|
+
`kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\\n"}{.metadata.name}{":\\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}'`,
|
|
757
|
+
{
|
|
758
|
+
stdout: true,
|
|
759
|
+
silent: true,
|
|
760
|
+
},
|
|
761
|
+
);
|
|
762
|
+
return raw
|
|
763
|
+
.split(`\n`)
|
|
764
|
+
.map((lines) => ({
|
|
765
|
+
pod: lines.split('\t')[0].replaceAll(':', '').trim(),
|
|
766
|
+
image: lines.split('\t')[1] ? lines.split('\t')[1].replaceAll(',', '').trim() : null,
|
|
767
|
+
}))
|
|
768
|
+
.filter((o) => o.image);
|
|
769
|
+
}
|
|
770
|
+
if (node === 'kind-worker') {
|
|
771
|
+
const raw = shellExec(`docker exec -i kind-control-plane crictl images`, {
|
|
772
|
+
stdout: true,
|
|
773
|
+
silent: true,
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
const heads = raw
|
|
777
|
+
.split(`\n`)[0]
|
|
778
|
+
.split(' ')
|
|
779
|
+
.filter((_r) => _r.trim());
|
|
780
|
+
|
|
781
|
+
const pods = raw
|
|
782
|
+
.split(`\n`)
|
|
783
|
+
.filter((r) => !r.match('IMAGE'))
|
|
784
|
+
.map((r) => r.split(' ').filter((_r) => _r.trim()));
|
|
785
|
+
|
|
786
|
+
const result = [];
|
|
787
|
+
|
|
788
|
+
for (const row of pods) {
|
|
789
|
+
if (row.length === 0) continue;
|
|
790
|
+
const pod = {};
|
|
791
|
+
let index = -1;
|
|
792
|
+
for (const head of heads) {
|
|
793
|
+
if (head in pod) continue;
|
|
794
|
+
index++;
|
|
795
|
+
pod[head] = row[index];
|
|
796
|
+
}
|
|
797
|
+
result.push(pod);
|
|
798
|
+
}
|
|
799
|
+
return result;
|
|
800
|
+
}
|
|
801
|
+
},
|
|
707
802
|
};
|
|
708
803
|
}
|
|
709
804
|
|
package/src/cli/env.js
CHANGED
|
@@ -56,9 +56,10 @@ class UnderpostRootEnv {
|
|
|
56
56
|
* @param {string} value - The value of the environment variable to get.
|
|
57
57
|
* @param {object} options - Options for getting the environment variable.
|
|
58
58
|
* @param {boolean} [options.plain=false] - If true, returns the environment variable value as a string.
|
|
59
|
+
* @param {boolean} [options.disableLog=false] - If true, disables logging of the environment variable value.
|
|
59
60
|
* @memberof UnderpostEnv
|
|
60
61
|
*/
|
|
61
|
-
get(key, value, options = { plain: false }) {
|
|
62
|
+
get(key, value, options = { plain: false, disableLog: false }) {
|
|
62
63
|
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
63
64
|
const envPath = `${exeRootPath}/.env`;
|
|
64
65
|
if (!fs.existsSync(envPath)) {
|
|
@@ -66,7 +67,8 @@ class UnderpostRootEnv {
|
|
|
66
67
|
return undefined;
|
|
67
68
|
}
|
|
68
69
|
const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
69
|
-
|
|
70
|
+
if (!options.disableLog)
|
|
71
|
+
options?.plain === true ? console.log(env[key]) : logger.info(`${key}(${typeof env[key]})`, env[key]);
|
|
70
72
|
return env[key];
|
|
71
73
|
},
|
|
72
74
|
/**
|
package/src/cli/image.js
CHANGED
|
@@ -53,7 +53,7 @@ class UnderpostImage {
|
|
|
53
53
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
54
54
|
const baseCommandOption = options.dev ? ' --dev' : '';
|
|
55
55
|
const IMAGE_NAME = `rockylinux9-underpost`;
|
|
56
|
-
const IMAGE_NAME_FULL = `${IMAGE_NAME}:${options.version
|
|
56
|
+
const IMAGE_NAME_FULL = `${IMAGE_NAME}:${options.version ? options.version : Underpost.version}`;
|
|
57
57
|
let LOAD_TYPE = '';
|
|
58
58
|
if (options.kindLoad === true) {
|
|
59
59
|
LOAD_TYPE = `--kind-load`;
|
|
@@ -105,7 +105,7 @@ class UnderpostImage {
|
|
|
105
105
|
dev: false,
|
|
106
106
|
},
|
|
107
107
|
) {
|
|
108
|
-
|
|
108
|
+
let {
|
|
109
109
|
path,
|
|
110
110
|
imageName,
|
|
111
111
|
imagePath,
|
|
@@ -119,6 +119,7 @@ class UnderpostImage {
|
|
|
119
119
|
reset,
|
|
120
120
|
dev,
|
|
121
121
|
} = options;
|
|
122
|
+
if (!path) path = '.';
|
|
122
123
|
const podManImg = `localhost/${imageName}`;
|
|
123
124
|
if (imagePath && typeof imagePath === 'string' && !fs.existsSync(imagePath))
|
|
124
125
|
fs.mkdirSync(imagePath, { recursive: true });
|
package/src/cli/index.js
CHANGED
|
@@ -68,10 +68,16 @@ program
|
|
|
68
68
|
.argument(`[commit-type]`, `The type of commit to perform. Options: ${Object.keys(commitData).join(', ')}.`)
|
|
69
69
|
.argument(`[module-tag]`, 'Optional: Sets a specific module tag for the commit.')
|
|
70
70
|
.argument(`[message]`, 'Optional: Provides an additional custom message for the commit.')
|
|
71
|
-
.option(`--log
|
|
71
|
+
.option(`--log <latest-n>`, 'Shows commit history from the specified number of latest n path commits.')
|
|
72
|
+
.option('--last-msg <latest-n>', 'Displays the last n commit message.')
|
|
72
73
|
.option('--empty', 'Allows committing with empty files.')
|
|
73
74
|
.option('--copy', 'Copies the generated commit message to the clipboard.')
|
|
74
75
|
.option('--info', 'Displays information about available commit types.')
|
|
76
|
+
.option('--diff', 'Shows the current git diff changes.')
|
|
77
|
+
.option('--edit', 'Edit last commit.')
|
|
78
|
+
.option('--msg <msg>', 'Sets a custom commit message.')
|
|
79
|
+
.option('--deploy-id <deploy-id>', 'Sets the deployment configuration ID for the commit context.')
|
|
80
|
+
.option('--cached', 'Commit staged changes only or context.')
|
|
75
81
|
.description('Manages commits to a GitHub repository, supporting various commit types and options.')
|
|
76
82
|
.action(Underpost.repo.commit);
|
|
77
83
|
|
|
@@ -382,6 +388,7 @@ program
|
|
|
382
388
|
.option('--namespace <namespace>', 'Optional: Specifies the namespace for test execution.')
|
|
383
389
|
.option('--kubeadm', 'Flag to indicate Kubeadm cluster type context')
|
|
384
390
|
.option('--k3s', 'Flag to indicate K3s cluster type context')
|
|
391
|
+
.option('--force', 'Forces operation, overriding any warnings or conflicts.')
|
|
385
392
|
.description('Runs a script from the specified path.')
|
|
386
393
|
.action(UnderpostRun.API.callback);
|
|
387
394
|
|
package/src/cli/repository.js
CHANGED
|
@@ -17,6 +17,8 @@ dotenv.config();
|
|
|
17
17
|
|
|
18
18
|
const logger = loggerFactory(import.meta);
|
|
19
19
|
|
|
20
|
+
const diffCmd = `--no-pager show -U0 -w --word-diff=color --word-diff-regex='[^[:space:]]' --color=always`;
|
|
21
|
+
|
|
20
22
|
/**
|
|
21
23
|
* @class UnderpostRepository
|
|
22
24
|
* @description Manages Git operations and configurations.
|
|
@@ -80,6 +82,13 @@ class UnderpostRepository {
|
|
|
80
82
|
* @param {boolean} [options.copy=false] - If true, copies the commit message to the clipboard.
|
|
81
83
|
* @param {boolean} [options.info=false] - If true, displays information about commit types.
|
|
82
84
|
* @param {boolean} [options.empty=false] - If true, allows an empty commit.
|
|
85
|
+
* @param {boolean} [options.diff=false] - If true, shows the diff of the last commit.
|
|
86
|
+
* @param {boolean} [options.edit=false] - If true, amends the last commit without changing the message.
|
|
87
|
+
* @param {boolean} [options.cached=false] - If true, commits only staged changes.
|
|
88
|
+
* @param {number} [options.log=0] - If greater than 0, shows the last N commits with diffs.
|
|
89
|
+
* @param {boolean} [options.lastMsg=0] - If greater than 0, copies or show the last last single n commit message to clipboard.
|
|
90
|
+
* @param {string} [options.msg=''] - If provided, outputs this message instead of committing.
|
|
91
|
+
* @param {string} [options.deployId=''] - An optional deploy ID to include in the commit message.
|
|
83
92
|
* @memberof UnderpostRepository
|
|
84
93
|
*/
|
|
85
94
|
commit(
|
|
@@ -91,14 +100,43 @@ class UnderpostRepository {
|
|
|
91
100
|
copy: false,
|
|
92
101
|
info: false,
|
|
93
102
|
empty: false,
|
|
94
|
-
|
|
103
|
+
diff: false,
|
|
104
|
+
edit: false,
|
|
105
|
+
cached: false,
|
|
106
|
+
lastMsg: 0,
|
|
107
|
+
log: 0,
|
|
108
|
+
msg: '',
|
|
109
|
+
deployId: '',
|
|
95
110
|
},
|
|
96
111
|
) {
|
|
112
|
+
if (!repoPath) repoPath = '.';
|
|
113
|
+
if (options.msg) {
|
|
114
|
+
options.msg = options.msg.replaceAll('"', '').replaceAll(`'`, '').replaceAll('`', '');
|
|
115
|
+
let key = Object.keys(commitData).find((k) => k && options.msg.toLocaleLowerCase().slice(0, 16).match(k));
|
|
116
|
+
if (!key) key = Object.keys(commitData).find((k) => k && options.msg.toLocaleLowerCase().match(k));
|
|
117
|
+
if (!key || key === undefined) key = 'chore';
|
|
118
|
+
shellExec(
|
|
119
|
+
`underpost cmt ${repoPath} ${key} ${options.deployId ? options.deployId : `''`} '${options.msg.replaceAll(`${key}(${key}`, '')}'`,
|
|
120
|
+
);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (options.lastMsg) {
|
|
124
|
+
if (options.copy) {
|
|
125
|
+
pbcopy(UnderpostRepository.API.getLastCommitMsg(options.lastMsg - 1));
|
|
126
|
+
} else console.log(UnderpostRepository.API.getLastCommitMsg(options.lastMsg - 1));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (options.diff) {
|
|
130
|
+
const _diffCmd = `git ${diffCmd.replace('show', `diff${options.cached ? ` --cached` : ''}`)}`;
|
|
131
|
+
if (options.copy) pbcopy(_diffCmd);
|
|
132
|
+
else console.log('Diff command:', _diffCmd);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
97
135
|
if (options.log) {
|
|
98
|
-
const history = UnderpostRepository.API.getHistory(
|
|
136
|
+
const history = UnderpostRepository.API.getHistory(options.log);
|
|
99
137
|
const chainCmd = history
|
|
100
138
|
.reverse()
|
|
101
|
-
.map((commitData, i) => `${i === 0 ? '' : ' && '}git
|
|
139
|
+
.map((commitData, i) => `${i === 0 ? '' : ' && '}git ${diffCmd} ${commitData.hash}`)
|
|
102
140
|
.join('');
|
|
103
141
|
if (history[0]) {
|
|
104
142
|
for (const commit of history) {
|
|
@@ -117,7 +155,7 @@ class UnderpostRepository {
|
|
|
117
155
|
return;
|
|
118
156
|
}
|
|
119
157
|
if (commitType === 'reset') {
|
|
120
|
-
if (options.copy) pbcopy(
|
|
158
|
+
if (options.copy) pbcopy(UnderpostRepository.API.getLastCommitMsg());
|
|
121
159
|
shellExec(`cd ${repoPath} && git reset --soft HEAD~${isNaN(parseInt(subModule)) ? 1 : parseInt(subModule)}`);
|
|
122
160
|
return;
|
|
123
161
|
}
|
|
@@ -126,7 +164,18 @@ class UnderpostRepository {
|
|
|
126
164
|
commitData[commitType].emoji
|
|
127
165
|
} ${message ? message : commitData[commitType].description}`;
|
|
128
166
|
if (options.copy) return pbcopy(_message);
|
|
129
|
-
shellExec(
|
|
167
|
+
shellExec(
|
|
168
|
+
`cd ${repoPath} && git commit ${options?.empty ? `--allow-empty ` : ''}${options.edit ? `--amend --no-edit ` : `-m "${_message}"`}`,
|
|
169
|
+
);
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Retrieves the message of the last Git commit.
|
|
174
|
+
* @returns {string} The last commit message.
|
|
175
|
+
* @memberof UnderpostRepository
|
|
176
|
+
*/
|
|
177
|
+
getLastCommitMsg(skip = 0) {
|
|
178
|
+
return shellExec(`git --no-pager log -1 --skip=${skip} --pretty=%B`, { stdout: true });
|
|
130
179
|
},
|
|
131
180
|
|
|
132
181
|
/**
|
|
@@ -291,17 +340,25 @@ Prevent build private config repo.`,
|
|
|
291
340
|
deployVersion: packageJsonDeploy.version,
|
|
292
341
|
};
|
|
293
342
|
},
|
|
294
|
-
|
|
295
|
-
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Retrieves the Git commit history.
|
|
346
|
+
* @param {number} [sinceCommit=1] - The number of recent commits to retrieve.
|
|
347
|
+
* @returns {Array<{hash: string, message: string, files: string}>} An array of commit objects with hash, message, and files.
|
|
348
|
+
* @memberof UnderpostRepository
|
|
349
|
+
*/
|
|
350
|
+
getHistory(sinceCommit = 1) {
|
|
351
|
+
return shellExec(`git log -1 --pretty=format:"%h %s" -n ${sinceCommit}`, {
|
|
296
352
|
stdout: true,
|
|
297
353
|
silent: true,
|
|
298
354
|
disableLog: true,
|
|
299
355
|
})
|
|
300
356
|
.split(`\n`)
|
|
301
357
|
.map((line) => {
|
|
358
|
+
const hash = line.split(' ')[0];
|
|
302
359
|
return {
|
|
303
|
-
hash
|
|
304
|
-
message: line.
|
|
360
|
+
hash,
|
|
361
|
+
message: line.split(`${hash} `)[1],
|
|
305
362
|
};
|
|
306
363
|
})
|
|
307
364
|
.filter((line) => line.hash)
|
package/src/cli/run.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { daemonProcess, getTerminalPid, openTerminal, pbcopy, shellCd, shellExec } from '../server/process.js';
|
|
8
|
-
import { getNpmRootPath, isDeployRunnerContext } from '../server/conf.js';
|
|
8
|
+
import { getNpmRootPath, getUnderpostRootPath, isDeployRunnerContext } from '../server/conf.js';
|
|
9
9
|
import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
10
10
|
import UnderpostTest from './test.js';
|
|
11
11
|
import fs from 'fs-extra';
|
|
@@ -14,6 +14,7 @@ import UnderpostDeploy from './deploy.js';
|
|
|
14
14
|
import UnderpostRootEnv from './env.js';
|
|
15
15
|
import UnderpostRepository from './repository.js';
|
|
16
16
|
import os from 'os';
|
|
17
|
+
import Underpost from '../index.js';
|
|
17
18
|
|
|
18
19
|
const logger = loggerFactory(import.meta);
|
|
19
20
|
|
|
@@ -42,6 +43,7 @@ class UnderpostRun {
|
|
|
42
43
|
* @property {number} replicas - The number of replicas to run.
|
|
43
44
|
* @property {boolean} k3s - Whether to run in k3s mode.
|
|
44
45
|
* @property {boolean} kubeadm - Whether to run in kubeadm mode.
|
|
46
|
+
* @property {boolean} force - Whether to force the operation.
|
|
45
47
|
* @memberof UnderpostRun
|
|
46
48
|
*/
|
|
47
49
|
static DEFAULT_OPTION = {
|
|
@@ -56,6 +58,7 @@ class UnderpostRun {
|
|
|
56
58
|
replicas: 1,
|
|
57
59
|
k3s: false,
|
|
58
60
|
kubeadm: false,
|
|
61
|
+
force: false,
|
|
59
62
|
};
|
|
60
63
|
/**
|
|
61
64
|
* @static
|
|
@@ -271,14 +274,32 @@ class UnderpostRun {
|
|
|
271
274
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
272
275
|
* @memberof UnderpostRun
|
|
273
276
|
*/
|
|
274
|
-
'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
277
|
+
'template-deploy': (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
275
278
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
276
279
|
shellExec(`${baseCommand} run clean`);
|
|
277
|
-
shellExec(
|
|
280
|
+
shellExec(
|
|
281
|
+
`${baseCommand} push ./engine-private ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine-private`,
|
|
282
|
+
);
|
|
278
283
|
shellCd('/home/dd/engine');
|
|
279
284
|
shellExec(`git reset`);
|
|
280
|
-
shellExec(
|
|
281
|
-
|
|
285
|
+
shellExec(
|
|
286
|
+
`${baseCommand} cmt . --empty ci package-pwa-microservices-template${path.startsWith('sync') ? `-${path}` : ''}`,
|
|
287
|
+
);
|
|
288
|
+
shellExec(`${baseCommand} push . ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine`);
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* @method template-deploy-image
|
|
293
|
+
* @description Commits and pushes a Docker image deployment for the `engine` repository.
|
|
294
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
295
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
296
|
+
* @memberof UnderpostRun
|
|
297
|
+
*/
|
|
298
|
+
'template-deploy-image': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
299
|
+
// const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
300
|
+
shellExec(
|
|
301
|
+
`cd /home/dd/engine && git reset && underpost cmt . --empty ci docker-image 'underpost-engine:${Underpost.version}' && underpost push . ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine`,
|
|
302
|
+
);
|
|
282
303
|
},
|
|
283
304
|
/**
|
|
284
305
|
* @method clean
|
|
@@ -293,16 +314,23 @@ class UnderpostRun {
|
|
|
293
314
|
},
|
|
294
315
|
/**
|
|
295
316
|
* @method pull
|
|
296
|
-
* @description
|
|
317
|
+
* @description Clones or pulls updates for the `engine` and `engine-private` repositories into `/home/dd/engine` and `/home/dd/engine/engine-private`.
|
|
297
318
|
* @param {string} path - The input value, identifier, or path for the operation.
|
|
298
319
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
299
320
|
* @memberof UnderpostRun
|
|
300
321
|
*/
|
|
301
322
|
pull: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
323
|
+
if (!fs.existsSync(`/home/dd`) || !fs.existsSync(`/home/dd/engine`)) {
|
|
324
|
+
fs.mkdirSync(`/home/dd`, { recursive: true });
|
|
325
|
+
shellExec(`cd /home/dd && underpost clone ${process.env.GITHUB_USERNAME}/engine`);
|
|
326
|
+
} else {
|
|
327
|
+
shellExec(`underpost run clean`);
|
|
328
|
+
shellExec(`cd /home/dd/engine && underpost pull . ${process.env.GITHUB_USERNAME}/engine`);
|
|
329
|
+
}
|
|
330
|
+
if (!fs.existsSync(`/home/dd/engine/engine-private`))
|
|
331
|
+
shellExec(`cd /home/dd/engine && underpost clone ${process.env.GITHUB_USERNAME}/engine-private`);
|
|
332
|
+
else
|
|
333
|
+
shellExec(`cd /home/dd/engine/engine-private underpost pull . ${process.env.GITHUB_USERNAME}/engine-private`);
|
|
306
334
|
},
|
|
307
335
|
/**
|
|
308
336
|
* @method release-deploy
|
|
@@ -333,18 +361,25 @@ class UnderpostRun {
|
|
|
333
361
|
shellCd('/home/dd/engine');
|
|
334
362
|
shellExec(`git reset`);
|
|
335
363
|
shellExec(`${baseCommand} cmt . --empty cd ssh-${path}`);
|
|
336
|
-
shellExec(`${baseCommand} push . ${process.env.GITHUB_USERNAME}/engine`);
|
|
364
|
+
shellExec(`${baseCommand} push . ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine`);
|
|
337
365
|
},
|
|
338
366
|
/**
|
|
339
367
|
* @method ide
|
|
340
|
-
* @description Opens a Visual Studio Code (VS Code) session for the specified path using `node ${underpostRoot}/bin/zed ${path}
|
|
368
|
+
* @description Opens a Visual Studio Code (VS Code) session for the specified path using `node ${underpostRoot}/bin/zed ${path}`,
|
|
369
|
+
* or installs Zed and sublime-text IDE if `path` is 'install'.
|
|
341
370
|
* @param {string} path - The input value, identifier, or path for the operation (used as the path to the directory to open in the IDE).
|
|
342
371
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
343
372
|
* @memberof UnderpostRun
|
|
344
373
|
*/
|
|
345
374
|
ide: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
346
375
|
const { underpostRoot } = options;
|
|
347
|
-
|
|
376
|
+
if (path === 'install') {
|
|
377
|
+
shellExec(`sudo curl -f https://zed.dev/install.sh | sh`);
|
|
378
|
+
shellExec(
|
|
379
|
+
`sudo dnf config-manager --add-repo https://download.sublimetext.com/rpm/stable/x86_64/sublime-text.repo`,
|
|
380
|
+
);
|
|
381
|
+
shellExec(`sudo dnf install -y sublime-text`);
|
|
382
|
+
} else shellExec(`node ${underpostRoot}/bin/zed ${path}`);
|
|
348
383
|
},
|
|
349
384
|
/**
|
|
350
385
|
* @method sync
|
|
@@ -384,7 +419,7 @@ class UnderpostRun {
|
|
|
384
419
|
|
|
385
420
|
shellExec(
|
|
386
421
|
`${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${
|
|
387
|
-
replicas
|
|
422
|
+
replicas ? replicas : 1
|
|
388
423
|
} --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''} dd ${env}`,
|
|
389
424
|
);
|
|
390
425
|
|
|
@@ -405,6 +440,57 @@ class UnderpostRun {
|
|
|
405
440
|
'ls-deployments': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
406
441
|
console.table(await UnderpostDeploy.API.get(path, 'deployments'));
|
|
407
442
|
},
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* @method host-update
|
|
446
|
+
* @description Executes the `rocky-setup.sh` script to update the host system configuration.
|
|
447
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
448
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
449
|
+
* @memberof UnderpostRun
|
|
450
|
+
*/
|
|
451
|
+
'host-update': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
452
|
+
// const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
453
|
+
shellExec(`chmod +x ${options.underpostRoot}/scripts/rocky-setup.sh`);
|
|
454
|
+
shellExec(`${options.underpostRoot}/scripts/rocky-setup.sh --yes${options.dev ? ' --install-dev' : ``}`);
|
|
455
|
+
},
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* @method dev-container
|
|
459
|
+
* @description Runs a development container pod named `underpost-dev-container` with specified volume mounts and opens a terminal to follow its logs.
|
|
460
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as an optional command to run inside the container).
|
|
461
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
462
|
+
* @memberof UnderpostRun
|
|
463
|
+
*/
|
|
464
|
+
'dev-container': async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
465
|
+
options.dev = true;
|
|
466
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
467
|
+
const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
468
|
+
const currentImage = UnderpostDeploy.API.getCurrentLoadedImages('kind-worker', false).find((o) =>
|
|
469
|
+
o.IMAGE.match('underpost'),
|
|
470
|
+
);
|
|
471
|
+
const podName = `underpost-dev-container`;
|
|
472
|
+
if (!UnderpostDeploy.API.existsContainerFile({ podName: 'kind-worker', path: '/home/dd/engine' })) {
|
|
473
|
+
shellExec(`docker exec -i kind-worker bash -c "mkdir -p /home/dd"`);
|
|
474
|
+
shellExec(`docker cp /home/dd/engine kind-worker:/home/dd/engine`);
|
|
475
|
+
shellExec(`docker exec -i kind-worker bash -c "chown -R 1000:1000 /home/dd || true; chmod -R 755 /home/dd"`);
|
|
476
|
+
}
|
|
477
|
+
if (!currentImage) shellExec(`${baseCommand} dockerfile-pull-base-images${baseClusterCommand} --kind-load`);
|
|
478
|
+
// shellExec(`kubectl delete pod ${podName} --ignore-not-found`);
|
|
479
|
+
await UnderpostRun.RUNNERS['deploy-job']('', {
|
|
480
|
+
dev: true,
|
|
481
|
+
podName,
|
|
482
|
+
imageName: currentImage ? currentImage.image : `localhost/rockylinux9-underpost:${Underpost.version}`,
|
|
483
|
+
volumeHostPath: '/home/dd',
|
|
484
|
+
volumeMountPath: '/home/dd',
|
|
485
|
+
on: {
|
|
486
|
+
init: async () => {
|
|
487
|
+
// openTerminal(`kubectl logs -f ${podName}`);
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
args: [daemonProcess(path ? path : `cd /home/dd/engine && npm run test`)],
|
|
491
|
+
});
|
|
492
|
+
},
|
|
493
|
+
|
|
408
494
|
/**
|
|
409
495
|
* @method monitor
|
|
410
496
|
* @description Monitors a specific pod (identified by `path`) for the existence of a file (`/await`), and performs conditional actions (like file copying and opening Firefox) when the file is removed.
|
|
@@ -513,6 +599,40 @@ class UnderpostRun {
|
|
|
513
599
|
shellExec(`underpost deploy --expose adminer`);
|
|
514
600
|
}
|
|
515
601
|
},
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* @method git-conf
|
|
605
|
+
* @description Configures Git global and local user name and email settings based on the provided `path` (formatted as `username,email`), or defaults to environment variables.
|
|
606
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as a comma-separated string: `username,email`).
|
|
607
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
608
|
+
* @memberof UnderpostRun
|
|
609
|
+
*/
|
|
610
|
+
'git-conf': (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
611
|
+
const defaultUsername = UnderpostRootEnv.API.get('GITHUB_USERNAME', '', { disableLog: true });
|
|
612
|
+
const defaultEmail = UnderpostRootEnv.API.get('GITHUB_EMAIL', '', { disableLog: true });
|
|
613
|
+
const [username, email] = path && path.split(',').length > 0 ? path.split(',') : [defaultUsername, defaultEmail];
|
|
614
|
+
|
|
615
|
+
shellExec(
|
|
616
|
+
`git config --global credential.helper "" && ` +
|
|
617
|
+
`git config credential.helper "" && ` +
|
|
618
|
+
`git config --global user.name '${username}' && ` +
|
|
619
|
+
`git config --global user.email '${email}' && ` +
|
|
620
|
+
`git config --global credential.interactive always && ` +
|
|
621
|
+
`git config user.name '${username}' && ` +
|
|
622
|
+
`git config user.email '${email}' && ` +
|
|
623
|
+
`git config credential.interactive always &&` +
|
|
624
|
+
`git config pull.rebase false`,
|
|
625
|
+
);
|
|
626
|
+
|
|
627
|
+
console.log(
|
|
628
|
+
shellExec(`git config list`, { silent: true, stdout: true })
|
|
629
|
+
.replaceAll('user.email', 'user.email'.yellow)
|
|
630
|
+
.replaceAll(username, username.green)
|
|
631
|
+
.replaceAll('user.name', 'user.name'.yellow)
|
|
632
|
+
.replaceAll(email, email.green),
|
|
633
|
+
);
|
|
634
|
+
},
|
|
635
|
+
|
|
516
636
|
/**
|
|
517
637
|
* @method promote
|
|
518
638
|
* @description Switches traffic between blue/green deployments for a specified deployment ID(s) (uses `dd.router` for 'dd', or a specific ID).
|
|
@@ -630,6 +750,64 @@ class UnderpostRun {
|
|
|
630
750
|
UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
|
|
631
751
|
},
|
|
632
752
|
|
|
753
|
+
/**
|
|
754
|
+
* @method service
|
|
755
|
+
* @description Deploys and exposes specific services (like `mongo-express-service`) on the cluster, updating deployment configurations and monitoring status.
|
|
756
|
+
* @param {string} path - The input value, identifier, or path for the operation (formatted as `deployId,serviceId,host,path,replicas,image,node`).
|
|
757
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
758
|
+
* @memberof UnderpostRun
|
|
759
|
+
*/
|
|
760
|
+
service: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
761
|
+
const env = options.dev ? 'development' : 'production';
|
|
762
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
763
|
+
// const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
764
|
+
shellCd(`/home/dd/engine`);
|
|
765
|
+
let [deployId, serviceId, host, _path, replicas, image, node] = path.split(',');
|
|
766
|
+
const services = fs.existsSync(`./engine-private/deploy/${deployId}/conf.services.json`)
|
|
767
|
+
? JSON.parse(fs.readFileSync(`./engine-private/deploy/${deployId}/conf.services.json`, 'utf8'))
|
|
768
|
+
: [];
|
|
769
|
+
switch (serviceId) {
|
|
770
|
+
case 'mongo-express-service': {
|
|
771
|
+
let serviceData = services.findIndex((s) => s.serviceId === serviceId);
|
|
772
|
+
const payload = {
|
|
773
|
+
serviceId,
|
|
774
|
+
path: _path,
|
|
775
|
+
port: 8081,
|
|
776
|
+
host,
|
|
777
|
+
};
|
|
778
|
+
if (serviceData == -1) {
|
|
779
|
+
services.push(payload);
|
|
780
|
+
} else {
|
|
781
|
+
services[serviceData] = payload;
|
|
782
|
+
}
|
|
783
|
+
fs.writeFileSync(
|
|
784
|
+
`./engine-private/conf/${deployId}/conf.services.json`,
|
|
785
|
+
JSON.stringify(services, null, 4),
|
|
786
|
+
'utf8',
|
|
787
|
+
);
|
|
788
|
+
shellExec(`kubectl delete svc mongo-express-service --ignore-not-found`);
|
|
789
|
+
shellExec(`kubectl delete deployment mongo-express --ignore-not-found`);
|
|
790
|
+
shellExec(`kubectl apply -f manifests/deployment/mongo-express/deployment.yaml`);
|
|
791
|
+
|
|
792
|
+
const success = await UnderpostTest.API.statusMonitor('mongo-express');
|
|
793
|
+
|
|
794
|
+
if (success) {
|
|
795
|
+
const versions = UnderpostDeploy.API.getCurrentTraffic(deployId) || 'blue';
|
|
796
|
+
if (!node) node = os.hostname();
|
|
797
|
+
shellExec(
|
|
798
|
+
`${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${
|
|
799
|
+
replicas ? replicas : 1
|
|
800
|
+
} --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''} dd ${env}`,
|
|
801
|
+
);
|
|
802
|
+
shellExec(
|
|
803
|
+
`${baseCommand} deploy --kubeadm --disable-update-deployment ${deployId} ${env} --versions ${versions}`,
|
|
804
|
+
);
|
|
805
|
+
} else logger.error('Mongo Express deployment failed');
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
|
|
633
811
|
/**
|
|
634
812
|
* @method sync-replica
|
|
635
813
|
* @description Syncs a replica for the dd.router
|
|
@@ -797,15 +975,22 @@ EOF`;
|
|
|
797
975
|
* @returns {Promise<any>} The result of the callback execution.
|
|
798
976
|
*/
|
|
799
977
|
async callback(runner, path, options = UnderpostRun.DEFAULT_OPTION) {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
978
|
+
try {
|
|
979
|
+
const npmRoot = getNpmRootPath();
|
|
980
|
+
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
981
|
+
if (options.command) options.command = options.command.split(',');
|
|
982
|
+
if (options.args) options.args = options.args.split(',');
|
|
983
|
+
options.underpostRoot = underpostRoot;
|
|
984
|
+
options.npmRoot = npmRoot;
|
|
985
|
+
logger.info('callback', { path, options });
|
|
986
|
+
if (!(runner in UnderpostRun.RUNNERS)) throw new Error(`Runner not found: ${runner}`);
|
|
987
|
+
const result = await UnderpostRun.RUNNERS[runner](path, options);
|
|
988
|
+
return result;
|
|
989
|
+
} catch (error) {
|
|
990
|
+
console.log(error);
|
|
991
|
+
logger.error(error);
|
|
992
|
+
return null;
|
|
993
|
+
}
|
|
809
994
|
},
|
|
810
995
|
};
|
|
811
996
|
}
|
|
@@ -118,7 +118,12 @@ const getQueryParams = () => {
|
|
|
118
118
|
const sanitizeRoute = (route) =>
|
|
119
119
|
!route || route === '/' || route === `\\`
|
|
120
120
|
? 'home'
|
|
121
|
-
: route
|
|
121
|
+
: route
|
|
122
|
+
.toLowerCase()
|
|
123
|
+
.replaceAll('/', '')
|
|
124
|
+
.replaceAll(`\\`, '')
|
|
125
|
+
.replaceAll(' ', '-')
|
|
126
|
+
.replaceAll(getProxyPath().replaceAll('/', ''), '');
|
|
122
127
|
|
|
123
128
|
/**
|
|
124
129
|
* Sets the document title and updates the active state of the main menu button corresponding to the route.
|
|
@@ -16,8 +16,10 @@ const getApiBasePath = (options) =>
|
|
|
16
16
|
options?.proxyPath
|
|
17
17
|
? `/${options.proxyPath}/`
|
|
18
18
|
: window.renderPayload?.apiBaseProxyPath
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
? window.renderPayload.apiBaseProxyPath == '/'
|
|
20
|
+
? window.renderPayload.apiBaseProxyPath
|
|
21
|
+
: `${window.renderPayload.apiBaseProxyPath}/`
|
|
22
|
+
: getProxyPath()
|
|
21
23
|
}${window.renderPayload?.apiBasePath ? window.renderPayload.apiBasePath : 'api'}/`;
|
|
22
24
|
|
|
23
25
|
const getApiBaseUrl = (options = { id: '', endpoint: '', proxyPath: '' }) =>
|