underpost 2.8.78 → 2.8.79

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/README.md CHANGED
@@ -68,7 +68,7 @@ Run dev client server
68
68
  npm run dev
69
69
  ```
70
70
  <!-- -->
71
- ## underpost ci/cd cli v2.8.78
71
+ ## underpost ci/cd cli v2.8.79
72
72
 
73
73
  ### Usage: `underpost [options] [command]`
74
74
  ```
package/bin/deploy.js CHANGED
@@ -822,6 +822,9 @@ try {
822
822
  }
823
823
 
824
824
  case 'version-deploy': {
825
+ shellExec(
826
+ `underpost secret underpost --create-from-file /home/dd/engine/engine-private/conf/dd-cron/.env.production`,
827
+ );
825
828
  shellExec(`node bin/build dd conf`);
826
829
  shellExec(`git add . && cd ./engine-private && git add .`);
827
830
  shellExec(`node bin cmt . ci package-pwa-microservices-template`);
package/cli.md CHANGED
@@ -1,4 +1,4 @@
1
- ## underpost ci/cd cli v2.8.78
1
+ ## underpost ci/cd cli v2.8.79
2
2
 
3
3
  ### Usage: `underpost [options] [command]`
4
4
  ```
@@ -204,7 +204,6 @@ Options:
204
204
  --mongodb Init with mongodb statefulset
205
205
  --postgresql Init with postgresql statefulset
206
206
  --mongodb4 Init with mongodb 4.4 service
207
- --istio Init base istio cluster
208
207
  --valkey Init with valkey service
209
208
  --contour Init with project contour base HTTPProxy and envoy
210
209
  --cert-manager Init with letsencrypt-prod ClusterIssuer
@@ -218,6 +217,11 @@ Options:
218
217
  --info-capacity display current total machine capacity info
219
218
  --info-capacity-pod display current machine capacity pod info
220
219
  --pull-image Set optional pull associated image
220
+ --init-host Install k8s node necessary cli env: kind, kubeadm,
221
+ docker, podman, helm
222
+ --config Set k8s base node config
223
+ --worker Set worker node context
224
+ --chown Set k8s kube chown
221
225
  -h, --help display help for command
222
226
 
223
227
  ```
@@ -471,10 +475,22 @@ Options:
471
475
  Lxd management
472
476
 
473
477
  Options:
474
- --init Init lxd
475
- --reset Reset lxd on current machine
476
- --install Install lxd on current machine
477
- -h, --help display help for command
478
+ --init Init lxd
479
+ --reset Reset lxd on current machine
480
+ --install Install lxd on current machine
481
+ --dev Set dev context env
482
+ --control set control node vm context
483
+ --worker set worker node context
484
+ --create-vm <vm-id> Create default virtual machines
485
+ --init-vm <vm-id> Get init vm underpost script
486
+ --info-vm <vm-id> Get all info vm
487
+ --start-vm <vm-id> Start vm with networkt config
488
+ --root-size <gb-size> Set root size vm
489
+ --join-node <nodes> Comma separated worker and control node e. g.
490
+ k8s-worker-1,k8s-control
491
+ --expose <vm-name-ports> Vm name and : separated with Comma separated vm
492
+ port to expose e. g. k8s-control:80,443
493
+ -h, --help display help for command
478
494
 
479
495
  ```
480
496
 
@@ -58,7 +58,7 @@ services:
58
58
  cpus: '0.25'
59
59
  memory: 20M
60
60
  labels: # labels in Compose file instead of Dockerfile
61
- engine.version: '2.8.78'
61
+ engine.version: '2.8.79'
62
62
  networks:
63
63
  - load-balancer
64
64
 
@@ -0,0 +1,16 @@
1
+ config:
2
+ limits.cpu: "2"
3
+ limits.memory: 4GB
4
+ description: vm nat network
5
+ devices:
6
+ eth0:
7
+ name: eth0
8
+ network: lxdbr0
9
+ type: nic
10
+ root:
11
+ path: /
12
+ pool: local # lxc storage list
13
+ size: 100GB
14
+ type: disk
15
+ name: admin-profile
16
+ used_by: []
@@ -0,0 +1,58 @@
1
+ config:
2
+ core.https_address: 127.0.0.1:8443
3
+
4
+ networks:
5
+ - name: lxdbr0
6
+ type: bridge
7
+ config:
8
+ ipv4.address: 10.250.250.1/24
9
+ ipv4.nat: "true"
10
+ ipv4.dhcp: "true"
11
+ ipv4.dhcp.ranges: 10.250.250.2-10.250.250.254
12
+ ipv4.firewall: "false"
13
+ ipv6.address: none
14
+
15
+ storage_pools:
16
+ - name: local
17
+ driver: zfs
18
+ config:
19
+ size: 100GiB
20
+
21
+ profiles:
22
+ - name: default
23
+ config: {}
24
+ description: "default profile"
25
+ devices:
26
+ root:
27
+ path: /
28
+ pool: local
29
+ type: disk
30
+
31
+ - name: admin-profile
32
+ description: "vm nat network admin profile"
33
+ config:
34
+ limits.cpu: "2"
35
+ limits.memory: 4GB
36
+ devices:
37
+ eth0:
38
+ name: eth0
39
+ network: lxdbr0
40
+ type: nic
41
+ root:
42
+ path: /
43
+ pool: local
44
+ size: 100GB
45
+ type: disk
46
+
47
+ projects: []
48
+
49
+ cluster:
50
+ server_name: lxd-node1
51
+ enabled: true
52
+ member_config: []
53
+ cluster_address: ""
54
+ cluster_certificate: ""
55
+ server_address: ""
56
+ cluster_password: ""
57
+ cluster_token: ""
58
+ cluster_certificate_path: ""
@@ -0,0 +1,146 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ # Expand /dev/sda2 partition and resize filesystem automatically
6
+
7
+ # Check if parted is installed
8
+ if ! command -v parted &>/dev/null; then
9
+ echo "parted not found, installing..."
10
+ dnf install -y parted
11
+ fi
12
+
13
+ # Get start sector of /dev/sda2
14
+ START_SECTOR=$(parted /dev/sda -ms unit s print | awk -F: '/^2:/{print $2}' | sed 's/s//')
15
+
16
+ # Resize the partition
17
+ parted /dev/sda ---pretend-input-tty <<EOF
18
+ unit s
19
+ resizepart 2 100%
20
+ Yes
21
+ quit
22
+ EOF
23
+
24
+ # Resize the filesystem
25
+ resize2fs /dev/sda2
26
+
27
+ echo "Disk and filesystem resized successfully."
28
+ sudo dnf install -y tar
29
+ sudo dnf install -y bzip2
30
+ sudo dnf install -y git
31
+ sudo dnf -y update
32
+ sudo dnf -y install epel-release
33
+ sudo dnf install -y ufw
34
+ sudo systemctl enable --now ufw
35
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
36
+ NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
37
+ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
38
+ nvm install 23.8.0
39
+ nvm use 23.8.0
40
+ echo "
41
+ ██╗░░░██╗███╗░░██╗██████╗░███████╗██████╗░██████╗░░█████╗░░██████╗████████╗
42
+ ██║░░░██║████╗░██║██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝╚══██╔══╝
43
+ ██║░░░██║██╔██╗██║██║░░██║█████╗░░██████╔╝██████╔╝██║░░██║╚█████╗░░░░██║░░░
44
+ ██║░░░██║██║╚████║██║░░██║██╔══╝░░██╔══██╗██╔═══╝░██║░░██║░╚═══██╗░░░██║░░░
45
+ ╚██████╔╝██║░╚███║██████╔╝███████╗██║░░██║██║░░░░░╚█████╔╝██████╔╝░░░██║░░░
46
+ ░╚═════╝░╚═╝░░╚══╝╚═════╝░╚══════╝╚═╝░░╚═╝╚═╝░░░░░░╚════╝░╚═════╝░░░░╚═╝░░░
47
+
48
+ Installing underpost k8s node ...
49
+
50
+ "
51
+ npm install -g underpost
52
+ chmod +x /root/.nvm/versions/node/v23.8.0/bin/underpost
53
+ sudo modprobe br_netfilter
54
+ mkdir -p /home/dd
55
+ cd $(underpost root)/underpost
56
+ underpost cluster --init-host
57
+
58
+ # Default flags
59
+ USE_KUBEADM=false
60
+ USE_KIND=false
61
+ USE_WORKER=false
62
+
63
+ # Loop through arguments
64
+ for arg in "$@"; do
65
+ case "$arg" in
66
+ --kubeadm)
67
+ USE_KUBEADM=true
68
+ ;;
69
+ --kind)
70
+ USE_KIND=true
71
+ ;;
72
+ --worker)
73
+ USE_WORKER=true
74
+ ;;
75
+ esac
76
+ done
77
+
78
+ echo "USE_KUBEADM = $USE_KUBEADM"
79
+ echo "USE_KIND = $USE_KIND"
80
+ echo "USE_WORKER = $USE_WORKER"
81
+
82
+ underpost cluster --kubeadm
83
+ underpost cluster --reset
84
+
85
+ PORTS=(
86
+ 22 # SSH
87
+ 80 # HTTP
88
+ 443 # HTTPS
89
+ 53 # DNS (TCP/UDP)
90
+ 66 # TFTP
91
+ 67 # DHCP
92
+ 69 # TFTP
93
+ 111 # rpcbind
94
+ 179 # Calico BGP
95
+ 2049 # NFS
96
+ 20048 # NFS mountd
97
+ 4011 # PXE boot
98
+ 5240 # snapd API
99
+ 5248 # Juju controller
100
+ 6443 # Kubernetes API
101
+ 9153 # CoreDNS metrics
102
+ 10250 # Kubelet API
103
+ 10251 # kube-scheduler
104
+ 10252 # kube-controller-manager
105
+ 10255 # Kubelet read-only (deprecated)
106
+ 10257 # controller-manager (v1.23+)
107
+ 10259 # scheduler (v1.23+)
108
+ )
109
+
110
+ PORT_RANGES=(
111
+ 2379:2380 # etcd
112
+ # 30000:32767 # NodePort range
113
+ # 3000:3100 # App node ports
114
+ 32765:32766 # Ephemeral ports
115
+ 6783:6784 # Weave Net
116
+ )
117
+
118
+ # Open individual ports
119
+ for PORT in "${PORTS[@]}"; do
120
+ ufw allow ${PORT}/tcp
121
+ ufw allow ${PORT}/udp
122
+ done
123
+
124
+ # Open port ranges
125
+ for RANGE in "${PORT_RANGES[@]}"; do
126
+ ufw allow ${RANGE}/tcp
127
+ ufw allow ${RANGE}/udp
128
+ done
129
+
130
+ # Behavior based on flags
131
+ if $USE_KUBEADM; then
132
+ echo "Running control node with kubeadm..."
133
+ underpost cluster --kubeadm
134
+ # kubectl get pods --all-namespaces -o wide -w
135
+ fi
136
+
137
+ if $USE_KIND; then
138
+ echo "Running control node with kind..."
139
+ underpost cluster
140
+ # kubectl get pods --all-namespaces -o wide -w
141
+ fi
142
+
143
+ if $USE_WORKER; then
144
+ echo "Running worker..."
145
+ underpost cluster --worker --config
146
+ fi
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.8.78",
5
+ "version": "2.8.79",
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",
@@ -31,6 +31,10 @@ class UnderpostCluster {
31
31
  pullImage: false,
32
32
  dedicatedGpu: false,
33
33
  kubeadm: false,
34
+ initHost: false,
35
+ config: false,
36
+ worker: false,
37
+ chown: false,
34
38
  },
35
39
  ) {
36
40
  // sudo dnf update
@@ -39,6 +43,9 @@ class UnderpostCluster {
39
43
  // 3) Install Nvidia drivers from Rocky Linux docs
40
44
  // 4) Install LXD with MAAS from Rocky Linux docs
41
45
  // 5) Install MAAS src from snap
46
+ if (options.initHost === true) return UnderpostCluster.API.initHost();
47
+ if (options.config === true) UnderpostCluster.API.config();
48
+ if (options.chown === true) UnderpostCluster.API.chown();
42
49
  const npmRoot = getNpmRootPath();
43
50
  const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
44
51
  if (options.infoCapacityPod === true) return logger.info('', UnderpostDeploy.API.resourcesFactory());
@@ -89,28 +96,17 @@ class UnderpostCluster {
89
96
  UnderpostDeploy.API.get('calico-kube-controllers')[0];
90
97
 
91
98
  if (
99
+ !options.worker &&
92
100
  !alrreadyCluster &&
93
- ((!options.istio && !UnderpostDeploy.API.get('kube-apiserver-kind-control-plane')[0]) ||
94
- (options.istio === true && !UnderpostDeploy.API.get('calico-kube-controllers')[0]))
101
+ ((!options.kubeadm && !UnderpostDeploy.API.get('kube-apiserver-kind-control-plane')[0]) ||
102
+ (options.kubeadm === true && !UnderpostDeploy.API.get('calico-kube-controllers')[0]))
95
103
  ) {
96
- shellExec(`sudo setenforce 0`);
97
- shellExec(`sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config`);
98
- // sudo systemctl disable kubelet
99
- // shellExec(`sudo systemctl enable --now kubelet`);
100
- shellExec(`containerd config default > /etc/containerd/config.toml`);
101
- shellExec(`sed -i -e "s/SystemdCgroup = false/SystemdCgroup = true/g" /etc/containerd/config.toml`);
102
- // shellExec(`cp /etc/kubernetes/admin.conf ~/.kube/config`);
103
- // shellExec(`sudo systemctl restart kubelet`);
104
- shellExec(`sudo service docker restart`);
105
- shellExec(`sudo systemctl enable --now containerd.service`);
106
- shellExec(`sudo swapoff -a; sudo sed -i '/swap/d' /etc/fstab`);
107
- if (options.istio === true) {
108
- shellExec(`sysctl net.bridge.bridge-nf-call-iptables=1`);
104
+ UnderpostCluster.API.config();
105
+ if (options.kubeadm === true) {
109
106
  shellExec(
110
107
  `sudo kubeadm init --pod-network-cidr=192.168.0.0/16 --control-plane-endpoint="${os.hostname()}:6443"`,
111
108
  );
112
- shellExec(`sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config`);
113
- shellExec(`sudo chown $(id -u):$(id -g) $HOME/.kube/config**`);
109
+ UnderpostCluster.API.chown();
114
110
  // https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart
115
111
  shellExec(
116
112
  `sudo kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.3/manifests/tigera-operator.yaml`,
@@ -119,17 +115,16 @@ class UnderpostCluster {
119
115
  // `wget https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/custom-resources.yaml`,
120
116
  // );
121
117
  shellExec(`sudo kubectl apply -f ${underpostRoot}/manifests/kubeadm-calico-config.yaml`);
122
- shellExec(`sudo systemctl restart containerd`);
123
118
  const nodeName = os.hostname();
124
119
  shellExec(`kubectl taint nodes ${nodeName} node-role.kubernetes.io/control-plane:NoSchedule-`);
125
120
  shellExec(
126
121
  `kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml`,
127
122
  );
128
123
  } else {
129
- shellExec(`sudo systemctl restart containerd`);
130
124
  if (options.full === true || options.dedicatedGpu === true) {
131
125
  // https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/
132
126
  shellExec(`cd ${underpostRoot}/manifests && kind create cluster --config kind-config-cuda.yaml`);
127
+ UnderpostCluster.API.chown();
133
128
  } else {
134
129
  shellExec(
135
130
  `cd ${underpostRoot}/manifests && kind create cluster --config kind-config${
@@ -137,7 +132,6 @@ class UnderpostCluster {
137
132
  }.yaml`,
138
133
  );
139
134
  }
140
- shellExec(`sudo chown $(id -u):$(id -g) $HOME/.kube/config**`);
141
135
  }
142
136
  } else logger.warn('Cluster already initialized');
143
137
 
@@ -285,6 +279,26 @@ class UnderpostCluster {
285
279
  shellExec(`sudo kubectl apply -f ${underpostRoot}/manifests/${letsEncName}.yaml`);
286
280
  }
287
281
  },
282
+
283
+ config() {
284
+ shellExec(`sudo setenforce 0`);
285
+ shellExec(`sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config`);
286
+ shellExec(`sudo systemctl enable --now docker`);
287
+ shellExec(`sudo systemctl enable --now kubelet`);
288
+ shellExec(`containerd config default > /etc/containerd/config.toml`);
289
+ shellExec(`sed -i -e "s/SystemdCgroup = false/SystemdCgroup = true/g" /etc/containerd/config.toml`);
290
+ shellExec(`sudo service docker restart`);
291
+ shellExec(`sudo systemctl enable --now containerd.service`);
292
+ shellExec(`sudo swapoff -a; sudo sed -i '/swap/d' /etc/fstab`);
293
+ shellExec(`sudo systemctl daemon-reload`);
294
+ shellExec(`sudo systemctl restart containerd`);
295
+ shellExec(`sysctl net.bridge.bridge-nf-call-iptables=1`);
296
+ },
297
+ chown() {
298
+ shellExec(`mkdir -p ~/.kube`);
299
+ shellExec(`sudo -E cp -i /etc/kubernetes/admin.conf ~/.kube/config`);
300
+ shellExec(`sudo -E chown $(id -u):$(id -g) ~/.kube/config`);
301
+ },
288
302
  // This function performs a comprehensive reset of Kubernetes and container environments
289
303
  // on the host machine. Its primary goal is to clean up cluster components, temporary files,
290
304
  // and container data, ensuring a clean state for re-initialization or fresh deployments,
@@ -460,6 +474,35 @@ Allocatable:
460
474
 
461
475
  return resources;
462
476
  },
477
+ initHost() {
478
+ // Install docker
479
+ shellExec(`sudo dnf -y install dnf-plugins-core
480
+ sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo`);
481
+ shellExec(`sudo dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin`);
482
+ // Install podman
483
+ shellExec(`sudo dnf -y install podman`);
484
+ // Install kind
485
+ shellExec(`[ $(uname -m) = aarch64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.29.0/kind-linux-arm64
486
+ chmod +x ./kind
487
+ sudo mv ./kind /bin/kind`);
488
+ // Install kubeadm
489
+ shellExec(`cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
490
+ [kubernetes]
491
+ name=Kubernetes
492
+ baseurl=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/
493
+ enabled=1
494
+ gpgcheck=1
495
+ gpgkey=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key
496
+ exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
497
+ EOF`);
498
+ shellExec(`sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes`);
499
+ // Install helm
500
+ shellExec(`curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
501
+ chmod 700 get_helm.sh
502
+ ./get_helm.sh
503
+ chmod +x /usr/local/bin/helm
504
+ sudo mv /usr/local/bin/helm /bin/helm`);
505
+ },
463
506
  };
464
507
  }
465
508
  export default UnderpostCluster;
package/src/cli/deploy.js CHANGED
@@ -82,13 +82,13 @@ spec:
82
82
  containers:
83
83
  - name: ${deployId}-${env}-${suffix}
84
84
  image: localhost/debian-underpost:${Underpost.version}
85
- resources:
86
- requests:
87
- memory: "${resources.requests.memory}"
88
- cpu: "${resources.requests.cpu}"
89
- limits:
90
- memory: "${resources.limits.memory}"
91
- cpu: "${resources.limits.cpu}"
85
+ # resources:
86
+ # requests:
87
+ # memory: "${resources.requests.memory}"
88
+ # cpu: "${resources.requests.cpu}"
89
+ # limits:
90
+ # memory: "${resources.limits.memory}"
91
+ # cpu: "${resources.limits.cpu}"
92
92
  command:
93
93
  - /bin/sh
94
94
  - -c
package/src/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import dotenv from 'dotenv';
2
2
  import { Command } from 'commander';
3
3
  import Underpost from '../index.js';
4
- import { getUnderpostRootPath, loadConf } from '../server/conf.js';
4
+ import { getNpmRootPath, getUnderpostRootPath, loadConf } from '../server/conf.js';
5
5
  import fs from 'fs-extra';
6
6
  import { commitData } from '../client/components/core/CommonJs.js';
7
7
  import { shellExec } from '../server/process.js';
@@ -97,7 +97,7 @@ program
97
97
  .option('--mongodb', 'Init with mongodb statefulset')
98
98
  .option('--postgresql', 'Init with postgresql statefulset')
99
99
  .option('--mongodb4', 'Init with mongodb 4.4 service')
100
- .option('--istio', 'Init base istio cluster')
100
+ // .option('--istio', 'Init base istio service mesh')
101
101
  .option('--valkey', 'Init with valkey service')
102
102
  .option('--contour', 'Init with project contour base HTTPProxy and envoy')
103
103
  .option('--cert-manager', 'Init with letsencrypt-prod ClusterIssuer')
@@ -111,6 +111,10 @@ program
111
111
  .option('--info-capacity', 'display current total machine capacity info')
112
112
  .option('--info-capacity-pod', 'display current machine capacity pod info')
113
113
  .option('--pull-image', 'Set optional pull associated image')
114
+ .option('--init-host', 'Install k8s node necessary cli env: kind, kubeadm, docker, podman, helm')
115
+ .option('--config', 'Set k8s base node config')
116
+ .option('--worker', 'Set worker node context')
117
+ .option('--chown', 'Set k8s kube chown')
114
118
  .action(Underpost.cluster.init)
115
119
  .description('Manage cluster, for default initialization base kind cluster');
116
120
 
@@ -271,6 +275,19 @@ program
271
275
  .option('--init', 'Init lxd')
272
276
  .option('--reset', 'Reset lxd on current machine')
273
277
  .option('--install', 'Install lxd on current machine')
278
+ .option('--dev', 'Set dev context env')
279
+ .option('--control', 'set control node vm context')
280
+ .option('--worker', 'set worker node context')
281
+ .option('--create-vm <vm-id>', 'Create default virtual machines')
282
+ .option('--init-vm <vm-id>', 'Get init vm underpost script')
283
+ .option('--info-vm <vm-id>', 'Get all info vm')
284
+ .option('--start-vm <vm-id>', 'Start vm with networkt config')
285
+ .option('--root-size <gb-size>', 'Set root size vm')
286
+ .option('--join-node <nodes>', 'Comma separated worker and control node e. g. k8s-worker-1,k8s-control')
287
+ .option(
288
+ '--expose <vm-name-ports>',
289
+ 'Vm name and : separated with Comma separated vm port to expose e. g. k8s-control:80,443',
290
+ )
274
291
  .description('Lxd management')
275
292
  .action(UnderpostLxd.API.callback);
276
293
 
package/src/cli/lxd.js CHANGED
@@ -1,8 +1,30 @@
1
- import { shellExec } from '../server/process.js';
1
+ import { getNpmRootPath } from '../server/conf.js';
2
+ import { getLocalIPv4Address } from '../server/dns.js';
3
+ import { pbcopy, shellExec } from '../server/process.js';
4
+ import fs from 'fs-extra';
2
5
 
3
6
  class UnderpostLxd {
4
7
  static API = {
5
- async callback(options = { init: false, reset: false, install: false }) {
8
+ async callback(
9
+ options = {
10
+ init: false,
11
+ reset: false,
12
+ dev: false,
13
+ install: false,
14
+ createVirtualNetwork: false,
15
+ control: false,
16
+ worker: false,
17
+ startVm: '',
18
+ initVm: '',
19
+ createVm: '',
20
+ infoVm: '',
21
+ rootSize: '',
22
+ joinNode: '',
23
+ expose: '',
24
+ },
25
+ ) {
26
+ const npmRoot = getNpmRootPath();
27
+ const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
6
28
  if (options.reset === true) {
7
29
  shellExec(`sudo systemctl stop snap.lxd.daemon`);
8
30
  shellExec(`sudo snap remove lxd --purge`);
@@ -11,7 +33,128 @@ class UnderpostLxd {
11
33
  if (options.init === true) {
12
34
  shellExec(`sudo systemctl start snap.lxd.daemon`);
13
35
  shellExec(`sudo systemctl status snap.lxd.daemon`);
36
+ const lxdPressedContent = fs
37
+ .readFileSync(`${underpostRoot}/manifests/lxd/lxd-preseed.yaml`, 'utf8')
38
+ .replaceAll(`127.0.0.1`, getLocalIPv4Address());
39
+ // shellExec(`lxc profile show admin-profile`);
40
+ // shellExec(`lxc network show lxdbr0`);
41
+ // shellExec(`lxd init --preseed < ${underpostRoot}/manifests/lxd/lxd-preseed.yaml`);
42
+ shellExec(`echo "${lxdPressedContent}" | lxd init --preseed`);
43
+ shellExec(`lxc cluster list`);
14
44
  }
45
+ if (options.createVm && typeof options.createVm === 'string') {
46
+ // lxc launch
47
+ const createVmCommand = `lxc init images:rockylinux/9/cloud ${
48
+ options.createVm
49
+ } --vm --target lxd-node1 -c limits.cpu=2 -c limits.memory=4GB --profile admin-profile -d root,size=${
50
+ options.rootSize && typeof options.rootSize === 'string' ? options.rootSize + 'GiB' : '32GiB'
51
+ }`;
52
+ pbcopy(createVmCommand); // Copy the command to clipboard for user
53
+ }
54
+ if (options.startVm && typeof options.startVm === 'string') {
55
+ const vmIp = UnderpostLxd.API.getNextAvailableIp();
56
+ shellExec(`lxc stop ${options.startVm}`);
57
+ shellExec(
58
+ `lxc config set ${options.startVm} user.network-config="${UnderpostLxd.API.generateCloudInitNetworkConfig(
59
+ vmIp,
60
+ )}"`,
61
+ );
62
+ shellExec(`lxc config device override ${options.startVm} eth0`);
63
+ shellExec(`lxc config device set ${options.startVm} eth0 ipv4.address ${vmIp}`);
64
+ shellExec(
65
+ `lxc config set ${options.startVm} user.user-data="#cloud-config
66
+ runcmd:
67
+ - [touch, /var/log/userdata-ok]"`,
68
+ );
69
+ shellExec(`lxc start ${options.startVm}`);
70
+ }
71
+ if (options.initVm && typeof options.initVm === 'string') {
72
+ let flag = '';
73
+ if (options.control === true) {
74
+ flag = ' -s -- --kubeadm';
75
+ shellExec(`lxc exec ${options.initVm} -- bash -c 'mkdir -p /home/dd/engine'`);
76
+ shellExec(`lxc file push /home/dd/engine/engine-private ${options.initVm}/home/dd/engine --recursive`);
77
+ } else if (options.worker == true) {
78
+ flag = ' -s -- --worker';
79
+ }
80
+ pbcopy(`cat ${underpostRoot}/manifests/lxd/underpost-setup.sh | lxc exec ${options.initVm} -- bash${flag}`);
81
+ }
82
+ if (options.joinNode && typeof options.joinNode === 'string') {
83
+ const [workerNode, controlNode] = options.joinNode.split(',');
84
+ const token = shellExec(
85
+ `echo "$(lxc exec ${controlNode} -- bash -c 'sudo kubeadm token create --print-join-command')"`,
86
+ { stdout: true },
87
+ );
88
+ shellExec(`lxc exec ${workerNode} -- bash -c '${token}'`);
89
+ }
90
+ if (options.infoVm && typeof options.infoVm === 'string') {
91
+ shellExec(`lxc config show ${options.infoVm}`);
92
+ shellExec(`lxc info --show-log ${options.infoVm}`);
93
+ shellExec(`lxc info ${options.infoVm}`);
94
+ shellExec(`lxc list ${options.infoVm}`);
95
+ }
96
+ if (options.expose && typeof options.expose === 'string') {
97
+ const [controlNode, ports] = options.expose.split(':');
98
+ console.log({ controlNode, ports });
99
+ const protocols = ['tcp', 'udp'];
100
+ const hostIp = getLocalIPv4Address();
101
+ const vmIp = shellExec(
102
+ `lxc list ${controlNode} --format json | jq -r '.[0].state.network.enp5s0.addresses[] | select(.family=="inet") | .address'`,
103
+ { stdout: true },
104
+ ).trim();
105
+ for (const port of ports.split(',')) {
106
+ for (const protocol of protocols) {
107
+ shellExec(`lxc config device remove ${controlNode} ${controlNode}-port-${port}`);
108
+ shellExec(
109
+ `lxc config device add ${controlNode} ${controlNode}-port-${port} proxy listen=${protocol}:${hostIp}:${port} connect=${protocol}:${vmIp}:${port} nat=true`,
110
+ );
111
+ shellExec(`lxc config show ${controlNode} --expanded | grep proxy`);
112
+ }
113
+ }
114
+ }
115
+ },
116
+ generateCloudInitNetworkConfig(ip) {
117
+ return `version: 2
118
+ ethernets:
119
+ enp5s0:
120
+ dhcp4: false
121
+ addresses:
122
+ - ${ip}/24
123
+ gateway4: 10.250.250.1
124
+ nameservers:
125
+ addresses: [1.1.1.1, 8.8.8.8]`;
126
+ },
127
+ getUsedIpsFromLxd() {
128
+ const json = shellExec('lxc list --format json', { stdout: true, silent: true });
129
+ const vms = JSON.parse(json);
130
+
131
+ const usedIps = [];
132
+
133
+ for (const vm of vms) {
134
+ if (vm.state && vm.state.network) {
135
+ for (const iface of Object.values(vm.state.network)) {
136
+ if (iface.addresses) {
137
+ for (const addr of iface.addresses) {
138
+ if (addr.family === 'inet' && addr.address.startsWith('10.250.250.')) {
139
+ usedIps.push(addr.address);
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ return usedIps;
148
+ },
149
+ getNextAvailableIp(base = '10.250.250.', start = 100, end = 254) {
150
+ const usedIps = UnderpostLxd.API.getUsedIpsFromLxd();
151
+ for (let i = start; i <= end; i++) {
152
+ const candidate = `${base}${i}`;
153
+ if (!usedIps.includes(candidate)) {
154
+ return candidate;
155
+ }
156
+ }
157
+ throw new Error('No IPs available in the static range');
15
158
  },
16
159
  };
17
160
  }
package/src/index.js CHANGED
@@ -11,6 +11,7 @@ import UnderpostDeploy from './cli/deploy.js';
11
11
  import UnderpostRootEnv from './cli/env.js';
12
12
  import UnderpostFileStorage from './cli/fs.js';
13
13
  import UnderpostImage from './cli/image.js';
14
+ import UnderpostLxd from './cli/lxd.js';
14
15
  import UnderpostMonitor from './cli/monitor.js';
15
16
  import UnderpostRepository from './cli/repository.js';
16
17
  import UnderpostScript from './cli/script.js';
@@ -30,7 +31,7 @@ class Underpost {
30
31
  * @type {String}
31
32
  * @memberof Underpost
32
33
  */
33
- static version = 'v2.8.78';
34
+ static version = 'v2.8.79';
34
35
  /**
35
36
  * Repository cli API
36
37
  * @static
@@ -122,6 +123,13 @@ class Underpost {
122
123
  * @memberof Underpost
123
124
  */
124
125
  static monitor = UnderpostMonitor.API;
126
+ /**
127
+ * LXD cli API
128
+ * @static
129
+ * @type {UnderpostLxd.API}
130
+ * @memberof Underpost
131
+ */
132
+ static lxd = UnderpostLxd.API;
125
133
  }
126
134
 
127
135
  const up = Underpost;