Compare commits

...

51 Commits

Author SHA1 Message Date
hys
a822538fc3 feat: add deviceName to helm values 2025-12-22 17:36:31 +08:00
hys
c5610cbcb7 fix: pending canceled namespace delete 2025-12-19 20:54:16 +08:00
hysyeah
47e82908c4 app-service: app entrance update (#2278)
* fix: app entrance update

* fix: set appservice tag
2025-12-18 23:22:41 +08:00
lovehunter9
4b79a7aefe fix: sync add support video of 3gp, mpg and vob (#2276) 2025-12-18 23:22:02 +08:00
hysyeah
dfd74239dd kubeblock-addons: fix image repo transfer due to opa (#2275) 2025-12-18 23:21:08 +08:00
berg
5a08f918c6 system frontend, market backend: fix market page suspend and upgrade status bug (#2274)
feat: update system frontend and market backend verison
2025-12-18 21:16:38 +08:00
hysyeah
8fde456f74 app-service: fix check resource before resume operation and image offset cal (#2273)
* fix: check resource before resume operation

* fix: image service tag to 0.4.65
2025-12-18 21:16:07 +08:00
eball
b173f005cd ci: bump version to 1.12.4 in workflows and scripts (#2271)
chore: bump version to 1.12.4 in workflows and scripts
2025-12-18 19:14:46 +08:00
eball
ecf8849b55 daemon: handle restarting state for system errors (#2270) 2025-12-18 17:07:57 +08:00
aby913
c8f416c4c0 backup: replace 85% disk usage percentage threshold (#2233) 2025-12-18 16:32:11 +08:00
dkeven
ed183b8e4e fix(ci): specify working dir in github action for backup module (#2269) 2025-12-18 15:21:16 +08:00
hysyeah
20595b72c7 app-serivce: delete applyenv created ns (#2268)
fix: update appservice image tag
2025-12-18 15:20:37 +08:00
dkeven
04c9e8309b feat(cli): add upgrader for stable version 1.12.3 (#2267) 2025-12-18 15:05:31 +08:00
lovehunter9
3cd388d83a feat: files sync search (#2262)
* feat: files sync search

* feat(olares-app): update sync search

* fix(login):  nginx config error

---------

Co-authored-by: qq815776412 <815776412@qq.com>
2025-12-18 14:56:29 +08:00
hysyeah
8266fc6085 app-service: fix concurrency cause two app in downloading state (#2265)
* fix: helm failed release

* fix: update app-service,image-service image tag

* fix: compatible with legacy mongodb uninstall

* fix: concurrency cause two app in downloading state

* fix: for an app with env will create namespace at first
2025-12-17 23:59:29 +08:00
dkeven
78fb8bcdca chore(gpu): upgrade NVIDIA driver version to 590.44.01 (#2264) 2025-12-17 23:59:05 +08:00
dkeven
cdb7afafef fix(cli): only (un)label current node in multi-node cluster (#2260) 2025-12-17 23:58:07 +08:00
salt
c4e1c74538 fix: document rest api error (#2259)
* fix: fix document recreate error, x-bfl-headeer replace error

* feat: upgrade to v0.0.95

---------

Co-authored-by: ubuntu <you@example.com>
2025-12-17 23:57:19 +08:00
Yajing
07b9470e4e docs: add access olares locally doc (#2224) 2025-12-17 22:00:33 +08:00
yajing wang
da11265189 fix format and add learn more 2025-12-17 21:55:03 +08:00
Yajing
f6d1addc7d Apply suggestions 2025-12-17 21:38:46 +08:00
hys
3b644efa0a cli: argo workflow breaking change 2025-12-17 21:26:16 +08:00
yajing wang
27d8463775 address comments and improve wording 2025-12-17 21:12:47 +08:00
wiy
5bf89ace05 feat(olares-app): update olares version to v1.6.24 (#2254) 2025-12-17 11:09:07 +08:00
hysyeah
fe9120edb4 app-service: fix helm release failed issue (#2252)
* fix: helm failed release

* fix: update app-service,image-service image tag
2025-12-17 11:08:36 +08:00
dkeven
2a77fe4c8a chore(bfl): remove some unused API handlers (#2250)
* chore(bfl): remove some unused API handlers

* bfl: update image version to v0.4.36
2025-12-17 11:06:49 +08:00
dkeven
85a5e2dc4b fix(cli): adjust internal DNS when cloud VM is detected (#2248) 2025-12-17 11:05:43 +08:00
eball
cd88ade7ca daemon: improve handling of broken mounts with detailed error reporting (#2247) 2025-12-17 11:00:24 +08:00
salt
0c3cedc1a5 feat: upgrade v0.0.93 (#2246)
Co-authored-by: ubuntu <you@example.com>
2025-12-17 11:00:02 +08:00
wiy
4ed649bff7 feat(olares-app): update olares-app version to v1.6.23 (#2244)
* feat: update frontend system and user-service version

* feat: update vault-server version to v1.6.23

---------

Co-authored-by: icebergtsn <zyh2433219116@gmail.com>
2025-12-15 23:50:09 +08:00
hysyeah
e383c22fe5 app-service: fix v2 app stop (#2243)
* feat: v2 stop support all to stop server

* fix: app clone failed

* fix: envoy inbound skip qemu source ip (#2208)

fix: skip qemu source ip

* app-service: update owner field to use app owner from app manager

* app-service: update owner field to use app owner from app manager

* fix: argo resource namespace validate

* Revert "fix: app clone failed"

This reverts commit a8a14ab9d6.

* app-service: update app-service image tag

* fix: v2 app stop

* update app-service image tag

* feat: upgrade v0.0.90 (#2227)

Co-authored-by: ubuntu <you@example.com>

* feat(olares-app): update olares app version to v1.6.22 (#2232)

* feat(olares-app): update olares app version to v1.6.22

* feat: create empty file for uploading

---------

Co-authored-by: lovehunter9 <wangrx07@aliyun.com>

* chore(ci): only scan for image manifest under .olares (#2234)

---------

Co-authored-by: eball <liuy102@hotmail.com>
Co-authored-by: salt <bleachzou2@163.com>
Co-authored-by: ubuntu <you@example.com>
Co-authored-by: wiy <guojianmin@bytetrade.io>
Co-authored-by: lovehunter9 <wangrx07@aliyun.com>
Co-authored-by: dkeven <82354774+dkeven@users.noreply.github.com>
2025-12-15 23:49:25 +08:00
dkeven
ce15e2ce00 chore(cli): remove unnecessary files and code related to kubesphere (#2242) 2025-12-15 23:48:40 +08:00
eball
957dff10a6 cli: refactor timestamp check for clarity and correctness (#2241)
* cli: refactor timestamp check for clarity and correctness

* fix: improve timestamp validation logic in CheckJWS function
2025-12-15 23:47:57 +08:00
salt
da35df9280 feat: upgrade to v0.0.92 (#2239)
Co-authored-by: ubuntu <you@example.com>
2025-12-15 23:47:31 +08:00
wiy
14edf88acb fix(notifications-api): payment template id error (#2238) 2025-12-15 23:46:55 +08:00
dkeven
939a9b5ba3 refactor: merge module kubesphere into main repo (#2237) 2025-12-15 23:45:34 +08:00
yajing wang
aa9b2aa243 refactor vpn-related docs 2025-12-15 22:59:52 +08:00
Yajing
3bd0705742 docs: add redirects and refactor studio docs (#2188) 2025-12-15 21:59:24 +08:00
yajing wang
6662923b87 add redirects and address comments 2025-12-15 21:55:34 +08:00
dkeven
f39fec6c68 chore(ci): only scan for image manifest under .olares (#2234) 2025-12-15 21:41:52 +08:00
yajing wang
e1362a43f7 add screenshots and address comments 2025-12-15 21:06:52 +08:00
wiy
a7c611571f feat(olares-app): update olares app version to v1.6.22 (#2232)
* feat(olares-app): update olares app version to v1.6.22

* feat: create empty file for uploading

---------

Co-authored-by: lovehunter9 <wangrx07@aliyun.com>
2025-12-12 23:52:46 +08:00
hysyeah
f0f2d4798c app-service: argo resource namespace validate (#2230)
* feat: v2 stop support all to stop server

* fix: app clone failed

* fix: envoy inbound skip qemu source ip (#2208)

fix: skip qemu source ip

* app-service: update owner field to use app owner from app manager

* app-service: update owner field to use app owner from app manager

* fix: argo resource namespace validate

* Revert "fix: app clone failed"

This reverts commit a8a14ab9d6.

* app-service: update app-service image tag

---------

Co-authored-by: eball <liuy102@hotmail.com>
2025-12-12 23:52:10 +08:00
salt
9d6fd7a276 feat: upgrade v0.0.90 (#2227)
Co-authored-by: ubuntu <you@example.com>
2025-12-12 23:51:36 +08:00
eball
02e45a7fb3 daemon: fix intranet server restarting bug (#2229)
* daemon: fix intranet server restarting bug

* fix(watcher): correct condition for verifying AdGuard DNS pod health
2025-12-12 21:28:19 +08:00
yajing wang
1c4257065f fix anchor links 2025-12-12 18:51:33 +08:00
yajing wang
40c0491925 compress image sizes 2025-12-12 18:46:50 +08:00
yajing wang
a7f2d9c583 add screenshots and zh-cn version 2025-12-12 18:15:32 +08:00
yajing wang
a72c760b07 docs: add access olares locally doc 2025-12-11 23:19:37 +08:00
yajing wang
6ec7f214cb add zh-cn version 2025-12-11 18:06:06 +08:00
yajing wang
543328fa6e docs: add redirects and refactor studio docs 2025-12-10 00:59:54 +08:00
576 changed files with 60749 additions and 4159 deletions

View File

@@ -75,7 +75,7 @@ jobs:
steps:
- id: generate
run: |
v=1.12.3-$(echo $RANDOM$RANDOM)
v=1.12.4-$(echo $RANDOM$RANDOM)
echo "version=$v" >> "$GITHUB_OUTPUT"
upload-cli:

View File

@@ -26,6 +26,6 @@ jobs:
with:
go-version: '1.21.10'
- name: Run Build
working-directory: framework/backup-server
run: |
make all
working-directory: framework/backup-server
make build

View File

@@ -0,0 +1,29 @@
name: Kubesphere Build Test
on:
push:
branches:
- "module-kubesphere"
paths:
- 'infrastructure/kubesphere/**'
- '!infrastructure/kubesphere/.olares/**'
- '!infrastructure/kubesphere/README.md'
pull_request:
branches:
- "module-kubesphere"
paths:
- 'infrastructure/kubesphere/**'
- '!infrastructure/kubesphere/.olares/**'
- '!infrastructure/kubesphere/README.md'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '1.24'
- run: make binary
working-directory: infrastructure/kubesphere

View File

@@ -0,0 +1,36 @@
name: Publish Kubesphere to Dockerhub
on:
workflow_dispatch:
inputs:
tags:
description: 'Release Tags'
jobs:
publish_dockerhub:
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v3
with:
push: true
tags: beclab/ks-apiserver:${{ github.event.inputs.tags }}
file: infrastructure/kubesphere/build/ks-apiserver/Dockerfile
context: infrastructure/kubesphere
platforms: linux/amd64,linux/arm64

View File

@@ -17,7 +17,7 @@ jobs:
steps:
- id: generate
run: |
v=1.12.3-$(date +"%Y%m%d")
v=1.12.4-$(date +"%Y%m%d")
echo "version=$v" >> "$GITHUB_OUTPUT"
release-id:

View File

@@ -53,6 +53,7 @@ rules:
- "/seahub/api/*"
- "/system/configuration/encoding"
- "/api/search/get_directory/"
- "/api/search/sync_search/"
verbs: ["*"]
---

View File

@@ -239,7 +239,6 @@ metadata:
applications.app.bytetrade.io/icon: https://app.cdn.olares.com/appstore/olaresapps/icon.png
applications.app.bytetrade.io/title: 'Olares Apps'
applications.app.bytetrade.io/version: '0.0.1'
applications.app.bytetrade.io/policies: '{"policies":[{"entranceName":"dashboard","uriRegex":"/js/script.js", "level":"public"},{"entranceName":"dashboard","uriRegex":"/js/api/send", "level":"public"}]}'
applications.app.bytetrade.io/entrances: '[{"name":"files", "host":"files-fe-service", "port":80,"title":"Files","windowPushState":true,"icon":"https://app.cdn.olares.com/appstore/files/icon.png"},{"name":"share","authLevel":"public", "host":"share-fe-service", "port":80,"title":"Share","windowPushState":true,"icon":"https://app.cdn.olares.com/appstore/files/icon.png","invisible":true},{"name":"vault", "host":"vault-service", "port":80,"title":"Vault","windowPushState":true,"icon":"https://app.cdn.olares.com/appstore/vault/icon.png"},{"name":"market", "host":"appstore-fe-service", "port":80,"title":"Market","windowPushState":true,"icon":"https://app.cdn.olares.com/appstore/appstore/icon.png"},{"name":"settings", "host":"settings-service", "port":80,"title":"Settings","icon":"https://app.cdn.olares.com/appstore/settings/icon.png"},{"name":"profile", "host":"profile-service", "port":80,"title":"Profile","windowPushState":true,"icon":"https://app.cdn.olares.com/appstore/profile/icon.png"},{"name":"dashboard","host":"dashboard-service","port":80,"title":"Dashboard","windowPushState":true,"icon":"https://app.cdn.olares.com/appstore/dashboard/icon.png"},{"name":"control-hub","host":"control-hub-service","port":80,"title":"Control Hub","windowPushState":true,"icon":"https://app.cdn.olares.com/appstore/control-hub/icon.png"},{"name":"headscale", "host":"headscale-svc", "port":80,"title":"Headscale","invisible": true,"icon":"https://app.cdn.olares.com/appstore/headscale/icon.png"}]'
spec:
replicas: 1
@@ -318,7 +317,7 @@ spec:
chown -R 1000:1000 /uploadstemp && \
chown -R 1000:1000 /appdata
- name: olares-app-init
image: beclab/system-frontend:v1.6.21
image: beclab/system-frontend:v1.6.27
imagePullPolicy: IfNotPresent
command:
- /bin/sh
@@ -440,7 +439,7 @@ spec:
- name: NATS_SUBJECT_VAULT
value: os.vault.{{ .Values.bfl.username}}
- name: user-service
image: beclab/user-service:v0.0.76
image: beclab/user-service:v0.0.81
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000

View File

@@ -18,7 +18,7 @@ fi
if [[ x"$VERSION" == x"" ]]; then
if [[ "$LOCAL_RELEASE" == "1" ]]; then
ts=$(date +%Y%m%d%H%M%S)
export VERSION="1.12.3-$ts"
export VERSION="1.12.4-$ts"
echo "will build and use a local release of Olares with version: $VERSION"
echo ""
else
@@ -28,7 +28,7 @@ fi
if [[ "x${VERSION}" == "x" || "x${VERSION:3}" == "xVERSION__" ]]; then
echo "error: Olares version is unspecified, please set the VERSION env var and rerun this script."
echo "for example: VERSION=1.12.3-20241124 bash $0"
echo "for example: VERSION=1.12.4-20241124 bash $0"
exit 1
fi

View File

@@ -158,7 +158,7 @@ export VERSION="#__VERSION__"
if [[ "x${VERSION}" == "x" || "x${VERSION:3}" == "xVERSION__" ]]; then
echo "error: Olares version is unspecified, please set the VERSION env var and rerun this script."
echo "for example: VERSION=1.12.3-20241124 bash $0"
echo "for example: VERSION=1.12.4-20241124 bash $0"
exit 1
fi

View File

@@ -17,7 +17,7 @@ for mod in "${PACKAGE_MODULE[@]}";do
chart_path="${mod}/${app}"
if [ -d $chart_path ]; then
find $chart_path -type f -name *.yaml | while read p; do
find $chart_path -type f -path '*/.olares/*.yaml' | while read p; do
bash ${BASE_DIR}/yaml2prop.sh -f $p | while read l;do
if [[ "$l" == *".image = "* || "$l" == "output.containers."*".name"* ]]; then
echo "$l"

View File

@@ -49,7 +49,7 @@ func NewCmdRelease() *cobra.Command {
}
if version == "" {
version = fmt.Sprintf("1.12.3-%s", time.Now().Format("20060102150405"))
version = fmt.Sprintf("1.12.4-%s", time.Now().Format("20060102150405"))
fmt.Printf("--version unspecified, using: %s\n", version)
time.Sleep(1 * time.Second)
}

View File

@@ -100,18 +100,9 @@ func (c *ConfigSystemModule) Init() {
Retry: 0,
}
configProxyTask := &task.RemoteTask{
Name: "ConfigProxy",
Hosts: c.Runtime.GetAllHosts(),
Action: new(ConfigProxyTask),
Parallel: false,
Retry: 0,
}
c.Tasks = []task.Interface{
updateNtpDateTask,
timeSyncTask,
configProxyTask,
}
}

View File

@@ -204,24 +204,6 @@ exit 0`, setNTPCommand, hwclockCmd)
return nil
}
type ConfigProxyTask struct {
common.KubeAction
}
func (t *ConfigProxyTask) Execute(runtime connector.Runtime) error {
if common.ResolvProxy == "" {
return nil
}
var cmd = fmt.Sprintf("echo nameserver %s > /etc/resolv.conf", common.ResolvProxy)
if _, err := runtime.GetRunner().SudoCmd(cmd, false, true); err != nil {
logger.Errorf("failed to execute %s: %v", cmd, err)
return err
}
return nil
}
type NodeConfigureOS struct {
common.KubeAction
}

View File

@@ -275,9 +275,17 @@ func (t *DisableLocalDNSTask) configResolvConf(runtime connector.Runtime) error
overrideOp := ">"
appendOp := ">>"
if common.CloudVendor == common.CloudVendorAliYun {
var internalDNS string
if util.IsOnAliyunECS() {
internalDNS = "100.100.10.12"
} else if util.IsOnAWSEC2() {
internalDNS = "169.254.169.253"
} else if util.IsOnTencentCVM() {
internalDNS = "183.60.83.19"
}
if internalDNS != "" {
secondNameserverOp = appendOp
cmd = `echo 'nameserver 100.100.2.136' > /etc/resolv.conf`
cmd = fmt.Sprintf("echo 'nameserver %s' > /etc/resolv.conf", internalDNS)
if _, err = runtime.GetRunner().SudoCmd(cmd, false, true); err != nil {
logger.Errorf("exec %s error %v", cmd, err)
return err

View File

@@ -25,8 +25,7 @@ const (
DefaultK3sVersion = "v1.33.3-k3s"
DefaultKubernetesVersion = ""
DefaultKubeSphereVersion = "v3.3.0"
DefaultTokenMaxAge = 31536000
CurrentVerifiedCudaVersion = "13.0"
CurrentVerifiedCudaVersion = "13.1"
)
const (
@@ -170,21 +169,11 @@ const (
ManagedMinIO = "managed-minio"
)
var (
CloudVendor = os.Getenv("CLOUD_VENDOR")
ResolvProxy = os.Getenv("PROXY")
)
const (
OlaresRegistryMirrorHost = "mirrors.joinolares.cn"
OlaresRegistryMirrorHostLegacy = "mirrors.jointerminus.cn"
)
const (
CloudVendorAliYun = "aliyun"
CloudVendorAWS = "aws"
)
const (
RaspbianCmdlineFile = "/boot/cmdline.txt"
RaspbianFirmwareFile = "/boot/firmware/cmdline.txt"
@@ -236,7 +225,6 @@ const (
CacheNodeNum = "node_num"
CacheRedisPassword = "redis_password"
CacheSecretsNum = "secrets_num"
CacheJwtSecret = "jwt_secret"
CacheCrdsNUm = "users_iam_num"
CacheMinioPath = "minio_binary_path"
@@ -295,7 +283,6 @@ const (
ENV_BACKUP_SECRET = "BACKUP_SECRET"
ENV_CLUSTER_ID = "CLUSTER_ID"
ENV_BACKUP_CLUSTER_BUCKET = "BACKUP_CLUSTER_BUCKET"
ENV_TOKEN_MAX_AGE = "TOKEN_MAX_AGE"
ENV_HOST_IP = "HOST_IP"
ENV_PREINSTALL = "PREINSTALL"
ENV_DISABLE_HOST_IP_PROMPT = "DISABLE_HOST_IP_PROMPT"

View File

@@ -101,7 +101,6 @@ type Argument struct {
Storage *Storage `json:"storage"`
NetworkSettings *NetworkSettings `json:"network_settings"`
GPU *GPU `json:"gpu"`
TokenMaxAge int64 `json:"token_max_age"` // nanosecond
Request any `json:"-"`
@@ -353,15 +352,6 @@ func (a *Argument) SetOlaresCDNService(url string) {
a.OlaresCDNService = u
}
func (a *Argument) SetTokenMaxAge() {
s := os.Getenv(ENV_TOKEN_MAX_AGE)
age, err := strconv.ParseInt(s, 10, 64)
if err != nil || age == 0 {
age = DefaultTokenMaxAge
}
a.TokenMaxAge = age
}
func (a *Argument) SetGPU(enable bool) {
if a.GPU == nil {
a.GPU = new(GPU)

View File

@@ -6,9 +6,9 @@ const (
NamespaceKubePublic = "kube-public"
NamespaceKubeSystem = "kube-system"
NamespaceKubekeySystem = "kubekey-system"
NamespaceKubesphereControlsSystem = "kubesphere-controls-system"
NamespaceKubesphereMonitoringSystem = "kubesphere-monitoring-system"
NamespaceKubesphereSystem = "kubesphere-system"
NamespaceKubesphereControlsSystem = "kubesphere-controls-system"
NamespaceOsFramework = "os-framework"
NamespaceOsPlatform = "os-platform"

View File

@@ -1,109 +0,0 @@
package common
import (
"fmt"
"strconv"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/core/prepare"
"github.com/beclab/Olares/cli/pkg/core/util"
"github.com/pkg/errors"
)
type Skip struct {
KubePrepare
Not bool
}
func (p *Skip) PreCheck(runtime connector.Runtime) (bool, error) {
return !p.Not, nil
}
type Stop struct {
prepare.BasePrepare
}
func (p *Stop) PreCheck(runtime connector.Runtime) (bool, error) {
return true, nil
// return false, fmt.Errorf("STOP !!!!!!")
}
type GetCommandKubectl struct {
prepare.BasePrepare
}
func (p *GetCommandKubectl) PreCheck(runtime connector.Runtime) (bool, error) {
cmd, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("command -v %s", CommandKubectl), false, false)
if err != nil {
return true, nil
}
if cmd != "" {
p.PipelineCache.Set(CacheKubectlKey, cmd)
}
return true, nil
}
type GetMasterNum struct {
prepare.BasePrepare
}
func (p *GetMasterNum) PreCheck(runtime connector.Runtime) (bool, error) {
var kubectlpath, err = util.GetCommand(CommandKubectl)
if err != nil {
return false, fmt.Errorf("kubectl not found")
}
var cmd = fmt.Sprintf("%s get node | awk '{if(NR>1){print $3}}' | grep master | wc -l", kubectlpath)
stdout, err := runtime.GetRunner().SudoCmd(cmd, false, false)
if err != nil {
return false, errors.Wrap(errors.WithStack(err), "get master num failed")
}
masterNum, _ := strconv.ParseInt(stdout, 10, 64)
p.PipelineCache.Set(CacheMasterNum, masterNum)
return true, nil
}
type GetNodeNum struct {
prepare.BasePrepare
}
func (p *GetNodeNum) PreCheck(runtime connector.Runtime) (bool, error) {
var kubectlpath, err = util.GetCommand(CommandKubectl)
if err != nil {
return false, fmt.Errorf("kubectl not found")
}
var cmd = fmt.Sprintf("%s get node | wc -l", kubectlpath)
stdout, err := runtime.GetRunner().SudoCmd(cmd, false, false)
if err != nil {
return false, errors.Wrap(errors.WithStack(err), "get node num failed")
}
nodeNum, _ := strconv.ParseInt(stdout, 10, 64)
p.PipelineCache.Set(CacheNodeNum, nodeNum)
return true, nil
}
type ClusterType struct {
KubePrepare
ClusterType string
Not bool
}
func (p *ClusterType) PreCheck(runtime connector.Runtime) (bool, error) {
if p.KubeConf == nil || p.KubeConf.Cluster == nil {
return false, nil
}
var isK3s = p.KubeConf.Cluster.Kubernetes.Type == p.ClusterType
if p.Not {
return !isK3s, nil
}
return isK3s, nil
}

View File

@@ -331,3 +331,46 @@ func GetPublicIPFromTencentIMDS() (net.IP, error) {
logger.Debugf("retrieved public IP info from Tencent metadata service: %s", string(body))
return net.ParseIP(strings.TrimSpace(string(body))), nil
}
func GetPublicIPFromAliyunIMDS() (net.IP, error) {
token, err := GetTokenFromAliyunIMDS()
if err != nil {
return nil, fmt.Errorf("failed to get Aliyun ECS IMDS token: %v", err)
}
url := "http://100.100.100.200/latest/meta-data/public-ipv4"
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, fmt.Errorf("failed to build http request: %v", err)
}
req.Header.Set("X-aliyun-ecs-metadata-token", token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, errors.Wrap(err, "failed to reach Aliyun metadata service")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "failed to read response from Aliyun metadata service")
}
logger.Debugf("retrieved public IP info from Aliyun metadata service: %s", string(body))
return net.ParseIP(strings.TrimSpace(string(body))), nil
}
func GetTokenFromAliyunIMDS() (string, error) {
url := "http://100.100.100.200/latest/api/token"
req, err := http.NewRequest(http.MethodPut, url, nil)
if err != nil {
return "", fmt.Errorf("failed to build http request: %v", err)
}
req.Header.Set("X-aliyun-ecs-metadata-token-ttl-seconds", "600")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", errors.Wrap(err, "failed to reach Aliyun metadata service")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", errors.Wrap(err, "failed to read response from Aliyun metadata service")
}
return strings.TrimSpace(string(body)), nil
}

View File

@@ -1,63 +0,0 @@
package util
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
)
var header = JWTHeader{
Alg: "HS256",
Typ: "JWT",
}
var payload = JWTPayload{
Email: "admin@kubesphere.io",
Username: "admin",
TokenType: "static_token",
}
type JWTHeader struct {
Alg string `json:"alg"`
Typ string `json:"typ"`
}
type JWTPayload struct {
Email string `json:"email"`
Username string `json:"username"`
TokenType string `json:"token_type"`
}
func EncryptToken(secret string) (string, error) {
headerJson, _ := json.Marshal(header)
headerBase64 := Base64URLEncode(headerJson)
payloadJson, _ := json.Marshal(payload)
payloadBase64 := Base64URLEncode(payloadJson)
headerPayload := fmt.Sprintf("%s.%s", headerBase64, payloadBase64)
var secretBytes = []byte(secret)
signature := HMACSHA256([]byte(headerPayload), secretBytes)
// Encode the signature to base64 URL encoding.
signatureBase64 := Base64URLEncode(signature)
return fmt.Sprintf("%s.%s", headerPayload, signatureBase64), nil
}
func Base64URLEncode(data []byte) string {
return strings.TrimRight(base64.URLEncoding.EncodeToString(data), "=")
}
// HMACSHA256 signs a message using a secret key with HMAC SHA256.
func HMACSHA256(message, secret []byte) []byte {
h := hmac.New(sha256.New, secret)
h.Write(message)
return h.Sum(nil)
}

View File

@@ -1,16 +0,0 @@
package util
import (
"fmt"
"testing"
)
func TestToken(t *testing.T) {
var a = "n7X2dggXApH91fnVUzgPr1Fr1vAO0Upo"
// var b = `{"email": "admin@kubesphere.io","username": "admin","token_type": "static_token"}`
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFkbWluQGt1YmVzcGhlcmUuaW8iLCJ1c2VybmFtZSI6ImFkbWluIiwidG9rZW5fdHlwZSI6InN0YXRpY190b2tlbiJ9.iwsRH37tcqE8HyI_S98AEM6KUH7bVdxDasR3V8QasXI
var data, _ = EncryptToken(a)
fmt.Println("---data---", data)
}

View File

@@ -264,3 +264,41 @@ func IsOnTencentCVM() bool {
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK
}
func IsOnAliyunECS() bool {
vendorFiles := []string{
"/sys/class/dmi/id/sys_vendor",
"/sys/class/dmi/id/board_vendor",
"/sys/class/dmi/id/bios_vendor",
"/sys/class/dmi/id/product_name",
}
for _, p := range vendorFiles {
if b, err := os.ReadFile(p); err == nil {
s := strings.ToLower(strings.TrimSpace(string(b)))
if strings.Contains(s, "alibaba") || strings.Contains(s, "aliyun") {
return true
}
}
}
if IsExist("/etc/aliyun-release") {
return true
}
reqCtx, cancel := context.WithTimeout(context.Background(), 400*time.Millisecond)
defer cancel()
req, _ := http.NewRequestWithContext(reqCtx, http.MethodGet, "http://100.100.100.200/latest/meta-data/instance-id", nil)
tr := &http.Transport{
Proxy: nil,
DialContext: (&net.Dialer{
Timeout: 250 * time.Millisecond,
}).DialContext,
}
resp, err := (&http.Client{Transport: tr}).Do(req)
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK
}

View File

@@ -74,7 +74,6 @@ func (g *GenerateTerminusdServiceEnv) Execute(runtime connector.Runtime) error {
"RegistryMirrors": g.KubeConf.Arg.RegistryMirrors,
"BaseDir": baseDir,
"GpuEnable": utils.FormatBoolToInt(g.KubeConf.Arg.GPU.Enable),
"TokenMaxAge": g.KubeConf.Arg.TokenMaxAge,
},
PrintContent: true,
}

View File

@@ -14,5 +14,4 @@ KUBE_TYPE={{ .KubeType }}
REGISTRY_MIRRORS={{ .RegistryMirrors }}
BASE_DIR={{ .BaseDir }}
LOCAL_GPU_ENABLE={{ .GpuEnable }}
TOKEN_MAX_AGE={{ .TokenMaxAge }}
`)))

View File

@@ -251,7 +251,7 @@ func (l *NodeLabelingModule) Init() {
Name: "UpdateNode",
Prepare: &prepare.PrepareCollection{
new(CudaInstalled),
new(K8sNodeInstalled),
new(CurrentNodeInK8s),
},
Action: new(UpdateNodeLabels),
Retry: 1,
@@ -262,7 +262,7 @@ func (l *NodeLabelingModule) Init() {
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(CudaInstalled),
new(K8sNodeInstalled),
new(CurrentNodeInK8s),
},
Action: new(RestartPlugin),
Retry: 1,
@@ -286,7 +286,7 @@ func (l *NodeUnlabelingModule) Init() {
Hosts: l.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(K8sNodeInstalled),
new(CurrentNodeInK8s),
},
Action: new(RemoveNodeLabels),
Parallel: false,
@@ -298,7 +298,7 @@ func (l *NodeUnlabelingModule) Init() {
Hosts: l.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(K8sNodeInstalled),
new(CurrentNodeInK8s),
new(GpuDevicePluginInstalled),
},
Action: new(RestartPlugin),

View File

@@ -63,11 +63,11 @@ func (p *CudaNotInstalled) PreCheck(runtime connector.Runtime) (bool, error) {
return false, nil
}
type K8sNodeInstalled struct {
type CurrentNodeInK8s struct {
common.KubePrepare
}
func (p *K8sNodeInstalled) PreCheck(runtime connector.Runtime) (bool, error) {
func (p *CurrentNodeInK8s) PreCheck(runtime connector.Runtime) (bool, error) {
client, err := clientset.NewKubeClient()
if err != nil {
logger.Debug(errors.Wrap(errors.WithStack(err), "kubeclient create error"))
@@ -84,11 +84,13 @@ func (p *K8sNodeInstalled) PreCheck(runtime connector.Runtime) (bool, error) {
return false, nil
}
if len(node.Items) == 0 {
return false, nil
for _, node := range node.Items {
if node.Name == runtime.GetSystemInfo().GetHostname() {
return true, nil
}
}
return true, nil
return false, nil
}
type NvidiaGraphicsCard struct {

View File

@@ -3,13 +3,14 @@ package kubesphere
import (
"encoding/json"
"fmt"
"github.com/beclab/Olares/cli/pkg/storage"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"github.com/beclab/Olares/cli/pkg/storage"
"github.com/containerd/containerd/plugin"
"github.com/pelletier/go-toml"
@@ -470,6 +471,7 @@ func (t *InitMinikubeNs) Execute(runtime connector.Runtime) error {
common.NamespaceKubekeySystem,
common.NamespaceKubesphereSystem,
common.NamespaceKubesphereMonitoringSystem,
common.NamespaceKubesphereControlsSystem,
}
for _, ns := range allNs {

View File

@@ -17,12 +17,9 @@
package kubesphere
import (
"path/filepath"
"time"
"github.com/beclab/Olares/cli/pkg/core/action"
"github.com/beclab/Olares/cli/pkg/core/logger"
"github.com/beclab/Olares/cli/pkg/version/kubesphere/templates"
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/prepare"
@@ -61,81 +58,19 @@ func (d *DeployModule) Init() {
d.Name = "DeployKubeSphereModule"
d.Desc = "Deploy KubeSphere"
generateManifests := &task.RemoteTask{
Name: "GenerateKsInstallerCRD",
Desc: "Generate KubeSphere ks-installer crd manifests",
Hosts: d.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: &action.Template{
Name: "GenerateKsInstallerCRD",
Template: templates.KsInstaller,
Dst: filepath.Join(common.KubeAddonsDir, templates.KsInstaller.Name()),
},
Parallel: false,
}
addConfig := &task.RemoteTask{
Name: "AddKsInstallerConfig",
Desc: "Add config to ks-installer manifests",
Hosts: d.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(AddInstallerConfig),
Parallel: false,
}
createNamespace := &task.RemoteTask{
Name: "CreateKubeSphereNamespace",
Desc: "Create the kubesphere namespace",
Hosts: d.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(CreateNamespace),
Parallel: false,
}
setup := &task.RemoteTask{
Name: "SetupKsInstallerConfig",
Desc: "Setup ks-installer config",
Hosts: d.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(Setup), // todo
Parallel: false,
Retry: 1,
}
apply := &task.RemoteTask{
Name: "ApplyKsInstaller",
Desc: "Apply ks-installer",
Hosts: d.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(Apply),
Parallel: false,
Retry: 10,
Delay: 5 * time.Second,
}
d.Tasks = []task.Interface{
generateManifests,
// apply crd installer.kubesphere.io/v1alpha1
// apply,
addConfig,
createNamespace,
setup,
apply,
}
}
@@ -157,7 +92,6 @@ func (c *CheckResultModule) Init() {
Hosts: c.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(Check),
Parallel: false,
@@ -170,7 +104,6 @@ func (c *CheckResultModule) Init() {
Hosts: c.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(GetKubeCommand),
Parallel: false,

File diff suppressed because one or more lines are too long

View File

@@ -1,243 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:kubesphere-router-clusterrole
annotations:
kubernetes.io/created-by: kubesphere.io/ks-router
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
- namespaces
verbs:
- list
- watch
- get
- update
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- "networking.k8s.io"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- "networking.k8s.io"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: system:kubesphere-router-role
namespace: kubesphere-controls-system
annotations:
kubernetes.io/created-by: kubesphere.io/ks-router
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# Defaults to "<election-id>-<ingress-class>"
# Here: "<ingress-controller-leader>-<nginx>"
# This has to be adapted if you change either parameter
# when launching the nginx-ingress-controller.
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubesphere-router-serviceaccount
namespace: kubesphere-controls-system
annotations:
kubernetes.io/created-by: kubesphere.io/ks-router
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:nginx-ingress-clusterrole-nisa-binding
annotations:
kubernetes.io/created-by: kubesphere.io/ks-router
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kubesphere-router-clusterrole
subjects:
- kind: ServiceAccount
name: kubesphere-router-serviceaccount
namespace: kubesphere-controls-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: kubesphere-controls-system
annotations:
kubernetes.io/created-by: kubesphere.io/ks-router
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: system:kubesphere-router-role
subjects:
- kind: ServiceAccount
name: kubesphere-router-serviceaccount
namespace: kubesphere-controls-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: default-http-backend
namespace: kubesphere-controls-system
labels:
app: kubesphere
component: kubesphere-router
version: express-1.0.alpha
annotations:
kubernetes.io/created-by: kubesphere.io/ks-router
spec:
replicas: 1
selector:
matchLabels:
app: kubesphere
component: kubesphere-router
template:
metadata:
labels:
app: kubesphere
component: kubesphere-router
spec:
terminationGracePeriodSeconds: 60
containers:
- name: default-http-backend
# Any image is permissible as long as:
# 1. It serves a 404 page at /
# 2. It serves 200 on a /healthz endpoint
image: {{ .Values.image.defaultbackend_repo }}:{{ .Values.image.defaultbackend_tag | default "latest" }}
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
ports:
- containerPort: 8080
resources:
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
---
apiVersion: v1
kind: Service
metadata:
name: default-http-backend
namespace: kubesphere-controls-system
labels:
app: kubesphere
component: kubesphere-router
annotations:
kubernetes.io/created-by: kubesphere.io/ks-router
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: kubesphere
component: kubesphere-router
---
# create a seviceaccount for kubectl pod
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubesphere-cluster-admin
namespace: kubesphere-controls-system
annotations:
kubernetes.io/created-by: kubesphere.io/kubectl
---
# bind kubesphere-cluster-admin sa to clusterrole cluster-admin
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:kubesphere-cluster-admin
annotations:
kubernetes.io/created-by: kubesphere.io/kubectl
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: kubesphere-cluster-admin
namespace: kubesphere-controls-system

View File

@@ -1,466 +0,0 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.6.1
creationTimestamp: null
name: clusterdashboards.monitoring.kubesphere.io
spec:
group: monitoring.kubesphere.io
names:
kind: ClusterDashboard
listKind: ClusterDashboardList
plural: clusterdashboards
singular: clusterdashboard
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: ClusterDashboard is the Schema for the culsterdashboards API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: DashboardSpec defines the desired state of Dashboard
properties:
datasource:
description: Dashboard datasource
type: string
description:
description: Dashboard description
type: string
panels:
description: Collection of panels. Panel is one of [Row](row.md),
[Singlestat](#singlestat.md) or [Graph](graph.md)
items:
description: Supported panel
properties:
bars:
description: A collection of queries Targets []Target `json:"targets,omitempty"`
Display as a bar chart
type: boolean
colors:
description: Set series color
items:
type: string
type: array
decimals:
description: Name of the signlestat panel Title string `json:"title,omitempty"`
Must be `singlestat` Type string `json:"type"` Panel ID Id
int64 `json:"id,omitempty"` A collection of queries Targets
[]Target `json:"targets,omitempty"` Limit the decimal numbers
format: int64
type: integer
description:
description: Name of the graph panel Title string `json:"title,omitempty"`
Must be `graph` Type string `json:"type"` Panel ID Id int64
`json:"id,omitempty"` Panel description
type: string
format:
description: Display unit
type: string
id:
description: Panel ID
format: int64
type: integer
lines:
description: Display as a line chart
type: boolean
stack:
description: Display as a stacked chart
type: boolean
targets:
description: A collection of queries Only for panels with `graph`
or `singlestat` type
items:
description: Query editor options
properties:
expr:
description: Input for fetching metrics.
type: string
legendFormat:
description: Legend format for outputs. You can make a
dynamic legend with templating variables.
type: string
refId:
description: Reference ID
format: int64
type: integer
step:
description: Set series time interval
type: string
type: object
type: array
title:
description: Name of the panel
type: string
type:
description: Panel Type, one of `row`, `graph`, `singlestat`
type: string
yaxes:
description: Y-axis options
items:
properties:
decimals:
description: Limit the decimal numbers
format: int64
type: integer
format:
description: Display unit
type: string
type: object
type: array
required:
- type
type: object
type: array
templating:
description: Templating variables
items:
description: Templating defines a variable, which can be used as
a placeholder in query
properties:
name:
description: Variable name
type: string
query:
description: Set variable values to be the return result of
the query
type: string
type: object
type: array
time:
description: Time range for display
properties:
from:
description: Start time in the format of `^now([+-][0-9]+[smhdwMy])?$`,
eg. `now-1M`. It denotes the end time is set to the last month
since now.
type: string
to:
description: End time in the format of `^now([+-][0-9]+[smhdwMy])?$`,
eg. `now-1M`. It denotes the start time is set to the last month
since now.
type: string
type: object
title:
description: Dashboard title
type: string
type: object
type: object
served: true
storage: false
- name: v1alpha2
schema:
openAPIV3Schema:
description: ClusterDashboard is the Schema for the culsterdashboards API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: DashboardSpec defines the desired state of Dashboard
properties:
annotations:
description: Annotations
items:
properties:
datasource:
type: string
enable:
type: boolean
expr:
type: string
iconColor:
type: string
iconSize:
type: integer
lineColor:
type: string
name:
type: string
query:
type: string
showLine:
type: boolean
step:
type: string
tagKeys:
type: string
tags:
items:
type: string
type: array
tagsField:
type: string
textField:
type: string
textFormat:
type: string
titleFormat:
type: string
type:
type: string
type: object
type: array
auto_refresh:
type: string
description:
type: string
editable:
type: boolean
id:
type: integer
panels:
items:
properties:
bars:
description: Display as a bar chart
type: boolean
colors:
description: Set series color
items:
type: string
type: array
content:
type: string
datasource:
description: Datasource
type: string
decimals:
format: int64
type: integer
description:
description: Description
type: string
format:
description: Display unit
type: string
gauge:
description: gauge
properties:
maxValue:
format: int64
type: integer
minValue:
format: int64
type: integer
show:
type: boolean
thresholdLabels:
type: boolean
thresholdMarkers:
type: boolean
type: object
height:
description: Height
type: string
id:
description: Panel ID
format: int64
type: integer
legend:
description: legend
items:
type: string
type: array
lines:
description: Display as a line chart
type: boolean
mode:
type: string
options:
properties:
colorMode:
type: string
content:
type: string
displayMode:
type: string
graphMode:
type: string
justifyMode:
type: string
mode:
type: string
orientation:
type: string
textMode:
type: string
type: object
scroll:
type: boolean
sort:
properties:
col:
type: integer
desc:
type: boolean
type: object
sparkline:
description: 'spark line: full or bottom'
type: string
stack:
description: Display as a stacked chart
type: boolean
targets:
description: A collection of queries
items:
description: Query editor options Referers to https://pkg.go.dev/github.com/grafana-tools/sdk#Target
properties:
expr:
description: 'only support prometheus,and the corresponding
fields are as follows: Input for fetching metrics.'
type: string
legendFormat:
description: Legend format for outputs. You can make a
dynamic legend with templating variables.
type: string
refId:
description: Reference ID
format: int64
type: integer
step:
description: Set series time interval
type: string
type: object
type: array
title:
description: Name of the panel
type: string
type:
description: Type of the panel
type: string
valueName:
description: value name
type: string
xaxis:
properties:
decimals:
description: Limit the decimal numbers
format: int64
type: integer
format:
description: Display unit
type: string
type: object
yaxes:
description: Y-axis options
items:
properties:
decimals:
description: Limit the decimal numbers
format: int64
type: integer
format:
description: Display unit
type: string
type: object
type: array
type: object
type: array
shared_crosshair:
type: boolean
tags:
items:
type: string
type: array
templatings:
description: // Templating variables
items:
properties:
allFormat:
type: string
allValue:
type: string
auto:
type: boolean
auto_count:
type: integer
datasource:
type: string
hide:
type: integer
includeAll:
type: boolean
label:
type: string
multi:
type: boolean
multiFormat:
type: string
name:
type: string
options:
items:
properties:
selected:
type: boolean
text:
type: string
value:
type: string
type: object
type: array
query:
type: string
regex:
type: string
sort:
type: integer
type:
type: string
type: object
type: array
time:
description: Time range
properties:
from:
description: Start time in the format of `^now([+-][0-9]+[smhdwMy])?$`,
eg. `now-1M`. It denotes the end time is set to the last month
since now.
type: string
to:
description: End time in the format of `^now([+-][0-9]+[smhdwMy])?$`,
eg. `now-1M`. It denotes the start time is set to the last month
since now.
type: string
type: object
timezone:
type: string
title:
type: string
uid:
type: string
type: object
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -1,470 +0,0 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.6.1
creationTimestamp: null
name: dashboards.monitoring.kubesphere.io
spec:
group: monitoring.kubesphere.io
names:
kind: Dashboard
listKind: DashboardList
plural: dashboards
singular: dashboard
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: Dashboard is the Schema for the dashboards API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: DashboardSpec defines the desired state of Dashboard
properties:
datasource:
description: Dashboard datasource
type: string
description:
description: Dashboard description
type: string
panels:
description: Collection of panels. Panel is one of [Row](row.md),
[Singlestat](#singlestat.md) or [Graph](graph.md)
items:
description: Supported panel
properties:
bars:
description: A collection of queries Targets []Target `json:"targets,omitempty"`
Display as a bar chart
type: boolean
colors:
description: Set series color
items:
type: string
type: array
decimals:
description: Name of the signlestat panel Title string `json:"title,omitempty"`
Must be `singlestat` Type string `json:"type"` Panel ID Id
int64 `json:"id,omitempty"` A collection of queries Targets
[]Target `json:"targets,omitempty"` Limit the decimal numbers
format: int64
type: integer
description:
description: Name of the graph panel Title string `json:"title,omitempty"`
Must be `graph` Type string `json:"type"` Panel ID Id int64
`json:"id,omitempty"` Panel description
type: string
format:
description: Display unit
type: string
id:
description: Panel ID
format: int64
type: integer
lines:
description: Display as a line chart
type: boolean
stack:
description: Display as a stacked chart
type: boolean
targets:
description: A collection of queries Only for panels with `graph`
or `singlestat` type
items:
description: Query editor options
properties:
expr:
description: Input for fetching metrics.
type: string
legendFormat:
description: Legend format for outputs. You can make a
dynamic legend with templating variables.
type: string
refId:
description: Reference ID
format: int64
type: integer
step:
description: Set series time interval
type: string
type: object
type: array
title:
description: Name of the panel
type: string
type:
description: Panel Type, one of `row`, `graph`, `singlestat`
type: string
yaxes:
description: Y-axis options
items:
properties:
decimals:
description: Limit the decimal numbers
format: int64
type: integer
format:
description: Display unit
type: string
type: object
type: array
required:
- type
type: object
type: array
templating:
description: Templating variables
items:
description: Templating defines a variable, which can be used as
a placeholder in query
properties:
name:
description: Variable name
type: string
query:
description: Set variable values to be the return result of
the query
type: string
type: object
type: array
time:
description: Time range for display
properties:
from:
description: Start time in the format of `^now([+-][0-9]+[smhdwMy])?$`,
eg. `now-1M`. It denotes the end time is set to the last month
since now.
type: string
to:
description: End time in the format of `^now([+-][0-9]+[smhdwMy])?$`,
eg. `now-1M`. It denotes the start time is set to the last month
since now.
type: string
type: object
title:
description: Dashboard title
type: string
type: object
type: object
served: true
storage: false
subresources:
status: {}
- name: v1alpha2
schema:
openAPIV3Schema:
description: Dashboard is the Schema for the dashboards API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: DashboardSpec defines the desired state of Dashboard
properties:
annotations:
description: Annotations
items:
properties:
datasource:
type: string
enable:
type: boolean
expr:
type: string
iconColor:
type: string
iconSize:
type: integer
lineColor:
type: string
name:
type: string
query:
type: string
showLine:
type: boolean
step:
type: string
tagKeys:
type: string
tags:
items:
type: string
type: array
tagsField:
type: string
textField:
type: string
textFormat:
type: string
titleFormat:
type: string
type:
type: string
type: object
type: array
auto_refresh:
type: string
description:
type: string
editable:
type: boolean
id:
type: integer
panels:
items:
properties:
bars:
description: Display as a bar chart
type: boolean
colors:
description: Set series color
items:
type: string
type: array
content:
type: string
datasource:
description: Datasource
type: string
decimals:
format: int64
type: integer
description:
description: Description
type: string
format:
description: Display unit
type: string
gauge:
description: gauge
properties:
maxValue:
format: int64
type: integer
minValue:
format: int64
type: integer
show:
type: boolean
thresholdLabels:
type: boolean
thresholdMarkers:
type: boolean
type: object
height:
description: Height
type: string
id:
description: Panel ID
format: int64
type: integer
legend:
description: legend
items:
type: string
type: array
lines:
description: Display as a line chart
type: boolean
mode:
type: string
options:
properties:
colorMode:
type: string
content:
type: string
displayMode:
type: string
graphMode:
type: string
justifyMode:
type: string
mode:
type: string
orientation:
type: string
textMode:
type: string
type: object
scroll:
type: boolean
sort:
properties:
col:
type: integer
desc:
type: boolean
type: object
sparkline:
description: 'spark line: full or bottom'
type: string
stack:
description: Display as a stacked chart
type: boolean
targets:
description: A collection of queries
items:
description: Query editor options Referers to https://pkg.go.dev/github.com/grafana-tools/sdk#Target
properties:
expr:
description: 'only support prometheus,and the corresponding
fields are as follows: Input for fetching metrics.'
type: string
legendFormat:
description: Legend format for outputs. You can make a
dynamic legend with templating variables.
type: string
refId:
description: Reference ID
format: int64
type: integer
step:
description: Set series time interval
type: string
type: object
type: array
title:
description: Name of the panel
type: string
type:
description: Type of the panel
type: string
valueName:
description: value name
type: string
xaxis:
properties:
decimals:
description: Limit the decimal numbers
format: int64
type: integer
format:
description: Display unit
type: string
type: object
yaxes:
description: Y-axis options
items:
properties:
decimals:
description: Limit the decimal numbers
format: int64
type: integer
format:
description: Display unit
type: string
type: object
type: array
type: object
type: array
shared_crosshair:
type: boolean
tags:
items:
type: string
type: array
templatings:
description: // Templating variables
items:
properties:
allFormat:
type: string
allValue:
type: string
auto:
type: boolean
auto_count:
type: integer
datasource:
type: string
hide:
type: integer
includeAll:
type: boolean
label:
type: string
multi:
type: boolean
multiFormat:
type: string
name:
type: string
options:
items:
properties:
selected:
type: boolean
text:
type: string
value:
type: string
type: object
type: array
query:
type: string
regex:
type: string
sort:
type: integer
type:
type: string
type: object
type: array
time:
description: Time range
properties:
from:
description: Start time in the format of `^now([+-][0-9]+[smhdwMy])?$`,
eg. `now-1M`. It denotes the end time is set to the last month
since now.
type: string
to:
description: End time in the format of `^now([+-][0-9]+[smhdwMy])?$`,
eg. `now-1M`. It denotes the start time is set to the last month
since now.
type: string
type: object
timezone:
type: string
title:
type: string
uid:
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -21,24 +21,6 @@ type CreateKsCore struct {
}
func (t *CreateKsCore) Execute(runtime connector.Runtime) error {
//var kubectlpath, err = util.GetCommand(common.CommandKubectl)
//if err != nil {
// return fmt.Errorf("kubectl not found")
//}
//var cmd = fmt.Sprintf("%s get pod -n %s -l 'app=redis,tier=database,version=redis-4.0' -o jsonpath='{.items[0].status.phase}'", kubectlpath,
// common.NamespaceKubesphereSystem)
//rphase, err := runtime.GetRunner().Host.SudoCmd(cmd, false, false)
//if rphase != "Running" {
// return fmt.Errorf("Redis State %s", rphase)
//}
masterNumIf, ok := t.PipelineCache.Get(common.CacheMasterNum)
if !ok || masterNumIf == nil {
return fmt.Errorf("failed to get master num")
}
masterNum := masterNumIf.(int64)
config, err := ctrl.GetConfig()
if err != nil {
return err
@@ -55,7 +37,7 @@ func (t *CreateKsCore) Execute(runtime connector.Runtime) error {
var values = make(map[string]interface{})
values["Release"] = map[string]string{
"Namespace": common.NamespaceKubesphereSystem,
"ReplicaCount": fmt.Sprintf("%d", masterNum),
"ReplicaCount": fmt.Sprintf("%d", 1),
}
if err := utils.UpgradeCharts(context.Background(), actionConfig, settings, appKsCoreName,
appPath, "", common.NamespaceKubesphereSystem, values, false); err != nil {
@@ -78,7 +60,6 @@ func (m *DeployKsCoreModule) Init() {
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(CreateKsCore),
Parallel: false,

View File

@@ -6,7 +6,6 @@ import (
"os"
"path"
"path/filepath"
"strconv"
"time"
"github.com/beclab/Olares/cli/pkg/common"
@@ -21,129 +20,6 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
)
var kscorecrds = []map[string]string{
{
"ns": "kubesphere-controls-system",
"kind": "serviceaccounts",
"resource": "kubesphere-cluster-admin",
"release": "ks-core",
},
{
"ns": "kubesphere-controls-system",
"kind": "serviceaccounts",
"resource": "kubesphere-router-serviceaccount",
"release": "ks-core",
},
{
"ns": "kubesphere-controls-system",
"kind": "role",
"resource": "system:kubesphere-router-role",
"release": "ks-core",
},
{
"ns": "kubesphere-controls-system",
"kind": "rolebinding",
"resource": "nginx-ingress-role-nisa-binding",
"release": "ks-core",
},
{
"ns": "kubesphere-controls-system",
"kind": "deployment",
"resource": "default-http-backend",
"release": "ks-core",
},
{
"ns": "kubesphere-controls-system",
"kind": "service",
"resource": "default-http-backend",
"release": "ks-core",
},
//{
// "ns": "kubesphere-system",
// "kind": "secrets",
// "resource": "ks-controller-manager-webhook-cert",
// "release": "ks-core",
//},
{
"ns": "kubesphere-system",
"kind": "serviceaccounts",
"resource": "kubesphere",
"release": "ks-core",
},
{
"ns": "kubesphere-system",
"kind": "clusterroles",
"resource": "system:kubesphere-router-clusterrole",
"release": "ks-core",
},
{
"ns": "kubesphere-system",
"kind": "clusterrolebindings",
"resource": "system:nginx-ingress-clusterrole-nisa-binding",
"release": "ks-core",
},
{
"ns": "kubesphere-system",
"kind": "clusterrolebindings",
"resource": "system:kubesphere-cluster-admin",
"release": "ks-core",
},
{
"ns": "kubesphere-system",
"kind": "clusterrolebindings",
"resource": "kubesphere",
"release": "ks-core",
},
{
"ns": "kubesphere-system",
"kind": "services",
"resource": "ks-apiserver",
"release": "ks-core",
},
//{
// "ns": "kubesphere-system",
// "kind": "services",
// "resource": "ks-controller-manager",
// "release": "ks-core",
//},
{
"ns": "kubesphere-system",
"kind": "deployments",
"resource": "ks-apiserver",
"release": "ks-core",
},
//{
// "ns": "kubesphere-system",
// "kind": "deployments",
// "resource": "ks-controller-manager",
// "release": "ks-core",
//},
//{
// "ns": "kubesphere-system",
// "kind": "validatingwebhookconfigurations",
// "resource": "users.iam.kubesphere.io",
// "release": "ks-core",
//},
{
"ns": "kubesphere-system",
"kind": "validatingwebhookconfigurations",
"resource": "resourcesquotas.quota.kubesphere.io",
"release": "ks-core",
},
{
"ns": "kubesphere-system",
"kind": "validatingwebhookconfigurations",
"resource": "network.kubesphere.io",
"release": "ks-core",
},
{
"ns": "kubesphere-system",
"kind": "users.iam.kubesphere.io",
"resource": "admin",
"release": "ks-core",
},
}
type CreateKsRole struct {
common.KubeAction
}
@@ -167,42 +43,11 @@ func (t *CreateKsRole) Execute(runtime connector.Runtime) error {
return nil
}
type PatchKsCoreStatus struct {
common.KubeAction
}
func (t *PatchKsCoreStatus) Execute(runtime connector.Runtime) error {
//var kubectlpath, _ = t.PipelineCache.GetMustString(common.CacheCommandKubectlPath)
//if kubectlpath == "" {
// kubectlpath = path.Join(common.BinDir, common.CommandKubectl)
//}
//
//var jsonPath = fmt.Sprintf(`{\"status\": {\"core\": {\"status\": \"enabled\", \"enabledTime\": \"%s\"}}}`, time.Now().Format("2006-01-02T15:04:05Z"))
//var cmd = fmt.Sprintf("%s patch cc ks-installer --type merge -p '%s' -n %s", kubectlpath, jsonPath, common.NamespaceKubesphereSystem)
//
//_, err := runtime.GetRunner().Host.SudoCmd(cmd, false, true)
//if err != nil {
// return errors.Wrap(errors.WithStack(err), "patch ks-core status failed")
//}
return nil
}
type CreateKsCoreConfig struct {
common.KubeAction
}
func (t *CreateKsCoreConfig) Execute(runtime connector.Runtime) error {
jwtSecretIf, ok := t.PipelineCache.Get(common.CacheJwtSecret)
if !ok || jwtSecretIf == nil {
return fmt.Errorf("failed to get jwt secret")
}
kubeVersionIf, ok := t.PipelineCache.Get(common.CacheKubeletVersion)
if !ok || kubeVersionIf == nil {
return fmt.Errorf("failed to get kubelet version")
}
config, err := ctrl.GetConfig()
if err != nil {
return err
@@ -230,13 +75,8 @@ func (t *CreateKsCoreConfig) Execute(runtime connector.Runtime) error {
// create ks-config
var appKsConfigName = common.ChartNameKsConfig
appPath = path.Join(runtime.GetInstallerDir(), cc.BuildFilesCacheDir, cc.BuildDir, appKsConfigName)
values = make(map[string]interface{})
values["Release"] = map[string]interface{}{
"JwtSecret": jwtSecretIf.(string),
"TokenMaxAge": t.KubeConf.Arg.TokenMaxAge * int64(time.Second),
}
if err := utils.UpgradeCharts(context.Background(), actionConfig, settings, appKsConfigName,
appPath, "", common.NamespaceKubesphereSystem, values, false); err != nil {
appPath, "", common.NamespaceKubesphereSystem, nil, false); err != nil {
logger.Errorf("failed to install %s chart: %v", appKsConfigName, err)
return err
}
@@ -273,82 +113,6 @@ func (t *CreateKsCoreConfigManifests) Execute(runtime connector.Runtime) error {
return nil
}
type PacthKsCore struct {
common.KubeAction
}
func (t *PacthKsCore) Execute(runtime connector.Runtime) error {
var secretsNum int64
var crdNum int64
var secretsNumIf, ok = t.PipelineCache.Get(common.CacheSecretsNum)
if ok && secretsNumIf != nil {
secretsNum = secretsNumIf.(int64)
}
crdNumIf, ok := t.PipelineCache.Get(common.CacheCrdsNUm)
if ok && crdNumIf != nil {
crdNum = crdNumIf.(int64)
}
var kubectlpath, err = util.GetCommand(common.CommandKubectl)
if err != nil {
return fmt.Errorf("kubectl not found")
}
if secretsNum == 0 && crdNum != 0 {
for _, item := range kscorecrds {
var cmd = fmt.Sprintf("%s -n %s annotate --overwrite %s %s meta.helm.sh/release-name=%s && %s -n %s annotate --overwrite %s %s meta.helm.sh/release-namespace=%s && %s -n %s label --overwrite %s %s app.kubernetes.io/managed-by=Helm",
kubectlpath, item["ns"], item["kind"], item["resource"], item["release"],
kubectlpath, item["ns"], item["kind"], item["resource"], common.NamespaceKubesphereSystem,
kubectlpath, item["ns"], item["kind"], item["resource"])
if _, err := runtime.GetRunner().SudoCmd(cmd, false, true); err != nil {
return errors.Wrap(errors.WithStack(err), "patch ks-core crd")
}
}
}
return nil
}
type CheckKsCoreExist struct {
common.KubeAction
}
func (t *CheckKsCoreExist) Execute(runtime connector.Runtime) error {
var kubectlpath, err = util.GetCommand(common.CommandKubectl)
if err != nil {
return fmt.Errorf("kubectl not found")
}
var cmd string
cmd = fmt.Sprintf("%s -n %s get secrets --field-selector=type=helm.sh/release.v1 | grep ks-core |wc -l",
kubectlpath,
common.NamespaceKubesphereSystem)
stdout, _ := runtime.GetRunner().SudoCmd(cmd, false, false)
secretNum, err := strconv.ParseInt(stdout, 10, 64)
if err != nil {
secretNum = 0
}
cmd = fmt.Sprintf("%s get crd users.iam.kubesphere.io | grep 'users.iam.kubesphere.io' |wc -l", kubectlpath)
stdout, _ = runtime.GetRunner().SudoCmd(cmd, false, false)
usersCrdNum, err := strconv.ParseInt(stdout, 10, 64)
if err != nil {
usersCrdNum = 0
}
logger.Debugf("secretNum: %d, usersCrdNum: %d", secretNum, usersCrdNum)
t.ModuleCache.Set(common.CacheSecretsNum, secretNum)
t.ModuleCache.Set(common.CacheCrdsNUm, usersCrdNum)
return nil
}
type DeployKsCoreConfigModule struct {
common.KubeModule
}
@@ -356,37 +120,11 @@ type DeployKsCoreConfigModule struct {
func (m *DeployKsCoreConfigModule) Init() {
m.Name = "DeployKsCoreConfig"
checkKsCoreExist := &task.RemoteTask{
Name: "CheckKsCoreExist",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
new(common.GetMasterNum),
},
Action: new(CheckKsCoreExist),
Parallel: false,
Retry: 0,
}
pacthKsCore := &task.RemoteTask{
Name: "PacthKsCore",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(PacthKsCore),
Parallel: false,
Retry: 0,
}
createKsCoreConfigManifests := &task.RemoteTask{
Name: "CreateKsCoreConfigManifests",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(CreateKsCoreConfigManifests),
Parallel: false,
@@ -399,31 +137,17 @@ func (m *DeployKsCoreConfigModule) Init() {
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(CreateKsCoreConfig),
Parallel: true,
Retry: 0,
}
patchKsCoreStatus := &task.RemoteTask{
Name: "PatchKsCoreStatus",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(PatchKsCoreStatus),
Parallel: true,
Retry: 0,
}
createKsRole := &task.RemoteTask{
Name: "CreateKsRole",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(CreateKsRole),
Parallel: true,
@@ -431,11 +155,8 @@ func (m *DeployKsCoreConfigModule) Init() {
}
m.Tasks = []task.Interface{
checkKsCoreExist,
pacthKsCore,
createKsCoreConfigManifests,
createKsCoreConfig,
patchKsCoreStatus,
createKsRole,
}
}

View File

@@ -1,17 +0,0 @@
package plugins
// ! Y ./ks-monitor/files/federated --> notification-manager
// ~ N ./ks-monitor/files/gpu-monitoring
// ~ Y ./ks-monitor/files/ks-istio-monitoring
// ! Y ./ks-monitor/files/monitoring-dashboard
// ! Y ./ks-monitor/files/notification-manager
// ! Y ./ks-monitor/files/prometheus/alertmanager
// ~ N ./ks-monitor/files/prometheus/etcd
// ~ N ./ks-monitor/files/prometheus/grafana
// ~ N ./ks-monitor/files/prometheus/kube-prometheus
// ! Y ./ks-monitor/files/prometheus/kube-state-metrics
// ! Y ./ks-monitor/files/prometheus/kubernetes
// ! Y ./ks-monitor/files/prometheus/node-exporter
// ! Y ./ks-monitor/files/prometheus/prometheus
// ! Y ./ks-monitor/files/prometheus/prometheus-operator
// ~ N ./ks-monitor/files/prometheus/thanos-ruler

View File

@@ -1,10 +1,7 @@
package plugins
import (
"time"
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/prepare"
"github.com/beclab/Olares/cli/pkg/core/task"
)
@@ -24,40 +21,3 @@ func (t *CopyEmbed) Init() {
copyEmbed,
}
}
type DeployKsPluginsModule struct {
common.KubeModule
}
func (t *DeployKsPluginsModule) Init() {
t.Name = "DeployKsPlugins"
checkNodeState := &task.RemoteTask{
Name: "CheckNodeState",
Hosts: t.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(CheckNodeState),
Parallel: false,
Retry: 20,
Delay: 10 * time.Second,
}
initNs := &task.RemoteTask{
Name: "InitKsNamespace",
Hosts: t.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(InitNamespace),
Parallel: false,
}
t.Tasks = []task.Interface{
checkNodeState,
initNs,
}
}

View File

@@ -1,56 +0,0 @@
package plugins
import (
"fmt"
"path"
"github.com/beclab/Olares/cli/pkg/common"
cc "github.com/beclab/Olares/cli/pkg/core/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/core/prepare"
"github.com/beclab/Olares/cli/pkg/core/task"
"github.com/beclab/Olares/cli/pkg/core/util"
)
type InstallMonitorDashboardCrd struct {
common.KubeAction
}
func (t *InstallMonitorDashboardCrd) Execute(runtime connector.Runtime) error {
var kubectlpath, err = util.GetCommand(common.CommandKubectl)
if err != nil {
return fmt.Errorf("kubectl not found")
}
var p = path.Join(runtime.GetInstallerDir(), cc.BuildFilesCacheDir, cc.BuildDir, "ks-monitor", "monitoring-dashboard")
var cmd = fmt.Sprintf("%s apply -f %s", kubectlpath, p)
if _, err := runtime.GetRunner().SudoCmd(cmd, false, true); err != nil {
return err
}
return nil
}
type CreateMonitorDashboardModule struct {
common.KubeModule
}
func (m *CreateMonitorDashboardModule) Init() {
m.Name = "CreateMonitorDashboardModule"
installMonitorDashboardCrd := &task.RemoteTask{
Name: "InstallMonitorDashboardCrd",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(InstallMonitorDashboardCrd),
Parallel: false,
Retry: 0,
}
m.Tasks = []task.Interface{
installMonitorDashboardCrd,
}
}

View File

@@ -17,14 +17,8 @@
package plugins
import (
"fmt"
"path"
"strings"
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/utils"
"github.com/pkg/errors"
)
type IsCloudInstance struct {
@@ -43,72 +37,3 @@ func (p *IsCloudInstance) PreCheck(runtime connector.Runtime) (bool, error) {
}
return p.Not, nil
}
type CheckStorageClass struct {
common.KubePrepare
}
func (p *CheckStorageClass) PreCheck(runtime connector.Runtime) (bool, error) {
var kubectlpath, _ = p.PipelineCache.GetMustString(common.CacheCommandKubectlPath)
if kubectlpath == "" {
kubectlpath = path.Join(common.BinDir, common.CommandKubectl)
}
var cmd = fmt.Sprintf("%s get sc | awk '{if(NR>1){print $1}}'", kubectlpath)
stdout, err := runtime.GetRunner().SudoCmd(cmd, false, true)
if err != nil {
return false, errors.Wrap(errors.WithStack(err), "get storageclass failed")
}
if stdout == "" {
return false, fmt.Errorf("no storageclass found")
}
cmd = fmt.Sprintf("%s get sc --no-headers", kubectlpath)
stdout, err = runtime.GetRunner().SudoCmd(cmd, false, true)
if err != nil {
return false, errors.Wrap(errors.WithStack(err), "get storageclass failed")
}
if stdout == "" {
return false, fmt.Errorf("no storageclass found")
}
if !strings.Contains(stdout, "(default)") {
return false, fmt.Errorf("default storageclass was not found")
}
return true, nil
}
type GenerateRedisPassword struct {
common.KubePrepare
}
func (p *GenerateRedisPassword) PreCheck(runtime connector.Runtime) (bool, error) {
pass, err := utils.GeneratePassword(15)
if err != nil {
return false, err
}
if pass == "" {
return false, fmt.Errorf("failed to generate redis password")
}
p.PipelineCache.Set(common.CacheRedisPassword, pass)
return true, nil
}
type NotEqualDesiredVersion struct {
common.KubePrepare
}
func (n *NotEqualDesiredVersion) PreCheck(runtime connector.Runtime) (bool, error) {
ksVersion, ok := n.PipelineCache.GetMustString(common.KubeSphereVersion)
if !ok {
ksVersion = ""
}
if n.KubeConf.Cluster.KubeSphere.Version == ksVersion {
return false, nil
}
return true, nil
}

View File

@@ -118,7 +118,6 @@ func (m *DeployPrometheusModule) Init() {
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(CreateOperator),
Parallel: false,
@@ -130,7 +129,6 @@ func (m *DeployPrometheusModule) Init() {
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: &CreatePrometheusComponent{
Component: "node-exporter",
@@ -145,7 +143,6 @@ func (m *DeployPrometheusModule) Init() {
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: &CreatePrometheusComponent{
Component: "kube-state-metrics",
@@ -160,7 +157,6 @@ func (m *DeployPrometheusModule) Init() {
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: &CreatePrometheusComponent{
Component: "prometheus",
@@ -173,7 +169,6 @@ func (m *DeployPrometheusModule) Init() {
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: &CreatePrometheusComponent{
Component: "kubernetes",
@@ -182,26 +177,12 @@ func (m *DeployPrometheusModule) Init() {
Parallel: false,
}
//createAlertManager := &task.RemoteTask{
// Name: "CreateAlertManager",
// Hosts: m.Runtime.GetHostsByRole(common.Master),
// Prepare: &prepare.PrepareCollection{
// new(common.OnlyFirstMaster),
// new(NotEqualDesiredVersion),
// },
// Action: &CreatePrometheusComponent{
// Component: "alertmanager",
// },
// Parallel: false,
//}
m.Tasks = []task.Interface{
createOperator,
createNodeExporter,
createKubeStateMetrics,
createPrometheus,
createKubeMonitor,
//createAlertManager,
}
}

View File

@@ -1,161 +0,0 @@
package plugins
import (
"context"
"fmt"
"path"
"strings"
"time"
"github.com/beclab/Olares/cli/pkg/common"
cc "github.com/beclab/Olares/cli/pkg/core/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/core/logger"
"github.com/beclab/Olares/cli/pkg/core/prepare"
"github.com/beclab/Olares/cli/pkg/core/task"
"github.com/beclab/Olares/cli/pkg/core/util"
"github.com/beclab/Olares/cli/pkg/utils"
"github.com/pkg/errors"
ctrl "sigs.k8s.io/controller-runtime"
)
type CreateRedisSecret struct {
common.KubeAction
}
func (t *CreateRedisSecret) Execute(runtime connector.Runtime) error {
kubectlpath, err := util.GetCommand(common.CommandKubectl)
if err != nil {
return fmt.Errorf("kubectl not found")
}
redisPwd, ok := t.PipelineCache.Get(common.CacheRedisPassword)
if !ok {
return fmt.Errorf("get redis password from module cache failed")
}
if stdout, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("%s -n %s create secret generic redis-secret --from-literal=auth=%s", kubectlpath, common.NamespaceKubesphereSystem, redisPwd), false, true); err != nil {
if err != nil && !strings.Contains(stdout, "already exists") {
return errors.Wrap(errors.WithStack(err), "create redis secret failed")
}
}
return nil
}
type BackupRedisManifests struct {
common.KubeAction
}
func (t *BackupRedisManifests) Execute(runtime connector.Runtime) error {
kubectlpath, err := util.GetCommand(common.CommandKubectl)
if err != nil {
return fmt.Errorf("kubectl not found")
}
rver, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("%s get pod -n %s -l app=%s,tier=database,version=%s-4.0 | wc -l",
kubectlpath, common.NamespaceKubesphereSystem, common.ChartNameRedis, common.ChartNameRedis), false, false)
if err != nil || strings.Contains(rver, "No resources found") {
return nil
}
rver = strings.ReplaceAll(rver, "No resources found in kubesphere-system namespace.", "")
rver = strings.ReplaceAll(rver, "\r\n", "")
rver = strings.ReplaceAll(rver, "\n", "")
if rver != "0" {
var cmd = fmt.Sprintf("%s get svc -n %s %s -o yaml > %s/redis-svc-backup.yaml && %s delete svc -n %s %s",
kubectlpath,
common.NamespaceKubesphereSystem, common.ChartNameRedis,
common.KubeManifestDir, // todo need fix cross platforms
kubectlpath,
common.NamespaceKubesphereSystem, common.ChartNameRedis)
if _, err := runtime.GetRunner().SudoCmd(cmd, false, true); err != nil {
logger.Errorf("failed to backup %s svc: %v", common.ChartNameRedis, err)
return errors.Wrap(errors.WithStack(err), "backup redis svc failed")
}
}
return nil
}
type DeployRedis struct {
common.KubeAction
}
func (t *DeployRedis) Execute(runtime connector.Runtime) error {
config, err := ctrl.GetConfig()
if err != nil {
return err
}
var appName = common.ChartNameRedis
var appPath = path.Join(runtime.GetInstallerDir(), cc.BuildFilesCacheDir, cc.BuildDir, appName)
actionConfig, settings, err := utils.InitConfig(config, common.NamespaceKubesphereSystem)
if err != nil {
return err
}
var ctx, cancel = context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
if err := utils.UpgradeCharts(ctx, actionConfig, settings, appName, appPath, "", common.NamespaceKubesphereSystem, nil, false); err != nil {
return err
}
return nil
}
// +++++
type DeployRedisModule struct {
common.KubeModule
}
func (m *DeployRedisModule) Init() {
m.Name = "DeployRedis"
createRedisSecret := &task.RemoteTask{
Name: "CreateRedisSecret",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
new(GenerateRedisPassword),
},
Action: new(CreateRedisSecret),
Parallel: false,
Retry: 0,
}
backupRedisManifests := &task.RemoteTask{
Name: "BackupRedisManifests",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(BackupRedisManifests),
Parallel: false,
Retry: 0,
}
deployRedis := &task.RemoteTask{
Name: "DeployRedis",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
new(CheckStorageClass),
},
Action: new(DeployRedis),
Parallel: false,
Retry: 0,
}
m.Tasks = []task.Interface{
createRedisSecret,
backupRedisManifests,
deployRedis,
}
}

View File

@@ -1,16 +1,12 @@
package plugins
import (
"fmt"
"path"
"strings"
"github.com/beclab/Olares/cli/pkg/common"
cc "github.com/beclab/Olares/cli/pkg/core/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/core/logger"
"github.com/beclab/Olares/cli/pkg/utils"
"github.com/pkg/errors"
)
type CopyEmbedFiles struct {
@@ -21,97 +17,3 @@ func (t *CopyEmbedFiles) Execute(runtime connector.Runtime) error {
var dst = path.Join(runtime.GetInstallerDir(), cc.BuildFilesCacheDir)
return utils.CopyEmbed(assets, ".", dst)
}
type CheckNodeState struct {
common.KubeAction
}
func (t *CheckNodeState) Execute(runtime connector.Runtime) error {
var kubectlpath, _ = t.PipelineCache.GetMustString(common.CacheCommandKubectlPath)
if kubectlpath == "" {
kubectlpath = path.Join(common.BinDir, common.CommandKubectl)
}
var cmd = fmt.Sprintf("%s get node --no-headers", kubectlpath)
stdout, err := runtime.GetRunner().SudoCmd(cmd, false, false)
if err != nil || stdout == "" {
return fmt.Errorf("Node Pending")
}
var nodeInfo = strings.Fields(stdout)
if len(nodeInfo) != 5 {
logger.Errorf("node info invalid: %s", stdout)
return fmt.Errorf("Node Pending")
}
var state = nodeInfo[1]
var version = nodeInfo[4]
if state != "Ready" {
return fmt.Errorf("Node Pending")
}
t.PipelineCache.Set(common.CacheKubeletVersion, version)
return nil
}
type InitNamespace struct {
common.KubeAction
}
func (t *InitNamespace) Execute(runtime connector.Runtime) error {
var kubectlpath, _ = t.PipelineCache.GetMustString(common.CacheCommandKubectlPath)
if kubectlpath == "" {
kubectlpath = path.Join(common.BinDir, common.CommandKubectl)
}
for _, ns := range []string{common.NamespaceKubesphereControlsSystem} {
if stdout, err := runtime.GetRunner().Cmd(fmt.Sprintf("%s create ns %s", kubectlpath, ns), false, true); err != nil {
if !strings.Contains(stdout, "already exists") {
logger.Errorf("create ns %s failed: %v", ns, err)
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("create namespace %s failed: %v", ns, err))
}
}
}
// _, err := runtime.GetRunner().SudoCmd(
// fmt.Sprintf(`cat <<EOF | /usr/local/bin/kubectl apply -f -
// apiVersion: v1
// kind: Namespace
// metadata:
// name: %s
// ---
// apiVersion: v1
// kind: Namespace
// metadata:
// name: %s
// EOF
// `, common.NamespaceKubesphereControlsSystem, common.NamespaceKubesphereMonitoringFederated), false, true)
// if err != nil {
// return errors.Wrap(errors.WithStack(err), fmt.Sprintf("create namespace: %s and %s",
// common.NamespaceKubesphereControlsSystem, common.NamespaceKubesphereMonitoringFederated))
// }
var allNs = []string{
common.NamespaceDefault,
common.NamespaceKubeNodeLease,
common.NamespaceKubePublic,
common.NamespaceKubeSystem,
common.NamespaceKubekeySystem,
common.NamespaceKubesphereControlsSystem,
common.NamespaceKubesphereSystem,
}
for _, ns := range allNs {
if _, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("%s label ns %s kubesphere.io/workspace=system-workspace --overwrite", kubectlpath, ns), false, true); err != nil {
logger.Errorf("label ns %s kubesphere.io/workspace=system-workspace failed: %v", ns, err)
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("label namespace %s kubesphere.io/workspace=system-workspace failed: %v", ns, err))
}
if _, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("%s label ns %s kubesphere.io/namespace=%s --overwrite", kubectlpath, ns, ns), false, true); err != nil {
logger.Errorf("label ns %s kubesphere.io/namespace=%s failed: %v", ns, ns, err)
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("label namespace %s kubesphere.io/namespace=%s failed: %v", ns, ns, err))
}
}
return nil
}

View File

@@ -1,79 +0,0 @@
package plugins
import (
"fmt"
"path"
"strings"
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/core/logger"
"github.com/beclab/Olares/cli/pkg/core/prepare"
"github.com/beclab/Olares/cli/pkg/core/task"
"github.com/beclab/Olares/cli/pkg/core/util"
"github.com/beclab/Olares/cli/pkg/utils"
"github.com/pkg/errors"
)
type GenerateKubeSphereToken struct {
common.KubeAction
}
func (t *GenerateKubeSphereToken) Execute(runtime connector.Runtime) error {
var kubectlpath, _ = t.PipelineCache.GetMustString(common.CacheCommandKubectlPath)
if kubectlpath == "" {
kubectlpath = path.Join(common.BinDir, common.CommandKubectl)
}
var random, err = utils.GeneratePassword(32)
if err != nil {
logger.Errorf("failed to generate password: %v", err)
return err
}
token, err := util.EncryptToken(random)
if err != nil {
return errors.Wrap(errors.WithStack(err), "create kubesphere token failed")
}
var cmd = fmt.Sprintf("%s get secrets -n %s --no-headers", kubectlpath, common.NamespaceKubesphereSystem)
stdout, _ := runtime.GetRunner().SudoCmd(cmd, false, false)
if strings.Contains(stdout, "kubesphere-secret") {
cmd = fmt.Sprintf("%s delete secrets -n %s kubesphere-secret", kubectlpath, common.NamespaceKubesphereSystem)
runtime.GetRunner().SudoCmd(cmd, false, true)
}
cmd = fmt.Sprintf("%s create secret generic kubesphere-secret --from-literal=token=%s --from-literal=secret=%s -n %s", kubectlpath,
token, random, common.NamespaceKubesphereSystem)
if _, err := runtime.GetRunner().SudoCmd(cmd, false, true); err != nil {
return errors.Wrap(errors.WithStack(err), "create kubesphere token failed")
}
t.PipelineCache.Set(common.CacheJwtSecret, random)
return nil
}
// +++++
type CreateKubeSphereSecretModule struct {
common.KubeModule
}
func (m *CreateKubeSphereSecretModule) Init() {
m.Name = "CreateKubeSphereSecret"
generateKubeSphereToken := &task.RemoteTask{
Name: "GenerateKubeSphereToken",
Hosts: m.Runtime.GetHostsByRole(common.Master),
Prepare: &prepare.PrepareCollection{
new(common.OnlyFirstMaster),
new(NotEqualDesiredVersion),
},
Action: new(GenerateKubeSphereToken),
Parallel: false,
Retry: 0,
}
m.Tasks = []task.Interface{generateKubeSphereToken}
}

View File

@@ -1,57 +0,0 @@
/*
Copyright 2021 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubesphere
import (
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/pkg/errors"
versionutil "k8s.io/apimachinery/pkg/util/version"
)
type VersionBelowV3 struct {
common.KubePrepare
}
func (v *VersionBelowV3) PreCheck(runtime connector.Runtime) (bool, error) {
versionStr, ok := v.PipelineCache.GetMustString(common.KubeSphereVersion)
if !ok {
return false, errors.New("get current kubesphere version failed by pipeline cache")
}
version := versionutil.MustParseSemantic(versionStr)
v300 := versionutil.MustParseSemantic("v3.0.0")
if v.KubeConf.Cluster.KubeSphere.Enabled && v.KubeConf.Cluster.KubeSphere.Version == "v3.0.0" && version.LessThan(v300) {
return true, nil
}
return false, nil
}
type NotEqualDesiredVersion struct {
common.KubePrepare
}
func (n *NotEqualDesiredVersion) PreCheck(runtime connector.Runtime) (bool, error) {
ksVersion, ok := n.PipelineCache.GetMustString(common.KubeSphereVersion)
if !ok {
ksVersion = ""
}
if n.KubeConf.Cluster.KubeSphere.Version == ksVersion {
return false, nil
}
return true, nil
}

View File

@@ -18,18 +18,12 @@ package kubesphere
import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
kubekeyapiv1alpha2 "github.com/beclab/Olares/cli/apis/kubekey/v1alpha2"
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/core/logger"
"github.com/beclab/Olares/cli/pkg/core/util"
"github.com/beclab/Olares/cli/pkg/version/kubesphere"
"github.com/beclab/Olares/cli/pkg/version/kubesphere/templates"
"github.com/pkg/errors"
)
@@ -52,27 +46,6 @@ func (d *DeleteKubeSphereCaches) Execute(runtime connector.Runtime) error {
return nil
}
type AddInstallerConfig struct {
common.KubeAction
}
func (a *AddInstallerConfig) Execute(runtime connector.Runtime) error {
//var ksFilename string
// if runtime.GetSystemInfo().IsDarwin() {
// ksFilename = path.Join(common.TmpDir, "/etc/kubernetes/addons/kubesphere.yaml")
// } else {
//ksFilename = "/etc/kubernetes/addons/kubesphere.yaml"
//// }
//configurationBase64 := base64.StdEncoding.EncodeToString([]byte(a.KubeConf.Cluster.KubeSphere.Configurations))
//if _, err := runtime.GetRunner().SudoCmd(
// fmt.Sprintf("echo %s | base64 -d >> %s", configurationBase64, ksFilename),
// false, false); err != nil {
// return errors.Wrap(errors.WithStack(err), "add config to ks-installer manifests failed")
//}
return nil
}
type CreateNamespace struct {
common.KubeAction
}
@@ -91,6 +64,11 @@ metadata:
---
apiVersion: v1
kind: Namespace
metadata:
name: kubesphere-controls-system
---
apiVersion: v1
kind: Namespace
metadata:
name: kubesphere-monitoring-system
EOF`, kubectl)
@@ -101,235 +79,6 @@ EOF`, kubectl)
return nil
}
type Setup struct {
common.KubeAction
}
func (s *Setup) Execute(runtime connector.Runtime) error {
nodeIp, _ := s.PipelineCache.GetMustString(common.CacheMinikubeNodeIp)
filePath := filepath.Join(common.KubeAddonsDir, templates.KsInstaller.Name())
var minikubepath, ok = s.PipelineCache.GetMustString(common.CacheCommandMinikubePath)
if !ok || minikubepath == "" {
minikubepath = path.Join(common.BinDir, common.CommandMinikube)
}
kubectlpath, ok := s.PipelineCache.GetMustString(common.CacheCommandKubectlPath)
if !ok || kubectlpath == "" {
kubectlpath = path.Join(common.BinDir, common.CommandKubectl)
}
var addrList []string
var tlsDisable bool
var port string
switch s.KubeConf.Cluster.Etcd.Type {
case kubekeyapiv1alpha2.KubeKey:
for _, host := range runtime.GetHostsByRole(common.ETCD) {
addrList = append(addrList, host.GetInternalAddress())
}
caFile := "/etc/ssl/etcd/ssl/ca.pem"
certFile := fmt.Sprintf("/etc/ssl/etcd/ssl/node-%s.pem", runtime.RemoteHost().GetName())
keyFile := fmt.Sprintf("/etc/ssl/etcd/ssl/node-%s-key.pem", runtime.RemoteHost().GetName())
if output, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("/usr/local/bin/kubectl -n kubesphere-monitoring-system create secret generic kube-etcd-client-certs "+
"--from-file=etcd-client-ca.crt=%s "+
"--from-file=etcd-client.crt=%s "+
"--from-file=etcd-client.key=%s", caFile, certFile, keyFile), false, false); err != nil {
if !strings.Contains(output, "exists") {
return err
}
}
case kubekeyapiv1alpha2.MiniKube:
var etcdPath = common.KubeEtcdCertDir // path.Join(common.TmpDir, common.KubeEtcdCertDir)
if !util.IsExist(etcdPath) {
if _, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("mkdir -p %s", etcdPath), false, false); err != nil {
return err
}
}
var certfiles = []string{
"ca.crt",
"server.crt",
"server.key",
}
for _, certfile := range certfiles {
var cfile = path.Join(common.MinikubeEtcdCertDir, certfile)
var cmd = fmt.Sprintf("%s -p %s ssh sudo chmod 644 %s && minikube -p %s cp %s:%s %s", minikubepath,
runtime.RemoteHost().GetMinikubeProfile(), cfile,
runtime.RemoteHost().GetMinikubeProfile(), runtime.RemoteHost().GetMinikubeProfile(),
cfile, path.Join(etcdPath, certfile))
if _, err := runtime.GetRunner().SudoCmd(cmd, false, false); err != nil {
return err
}
}
caFile := path.Join(etcdPath, "ca.crt")
certFile := path.Join(etcdPath, "server.crt")
keyFile := path.Join(etcdPath, "server.key")
addrList = append(addrList, nodeIp)
if output, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("%s -n kubesphere-monitoring-system create secret generic kube-etcd-client-certs "+
"--from-file=%s "+
"--from-file=%s "+
"--from-file=%s", kubectlpath, caFile, certFile, keyFile), false, false); err != nil {
if !strings.Contains(output, "already exists") {
return err
}
}
//path.Join(common.TmpDir, filepath.Join(common.KubeAddonsDir, templates.KsInstaller.Name()))
filePath = path.Join(filepath.Join(common.KubeAddonsDir, templates.KsInstaller.Name()))
case kubekeyapiv1alpha2.Kubeadm:
for _, host := range runtime.GetHostsByRole(common.Master) {
addrList = append(addrList, host.GetInternalAddress())
}
caFile := "/etc/kubernetes/pki/etcd/ca.crt"
certFile := "/etc/kubernetes/pki/etcd/healthcheck-client.crt"
keyFile := "/etc/kubernetes/pki/etcd/healthcheck-client.key"
if output, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("/usr/local/bin/kubectl -n kubesphere-monitoring-system create secret generic kube-etcd-client-certs "+
"--from-file=etcd-client-ca.crt=%s "+
"--from-file=etcd-client.crt=%s "+
"--from-file=etcd-client.key=%s", caFile, certFile, keyFile), false, false); err != nil {
if !strings.Contains(output, "exists") {
return err
}
}
case kubekeyapiv1alpha2.External:
for _, endpoint := range s.KubeConf.Cluster.Etcd.External.Endpoints {
e := strings.Split(strings.TrimSpace(endpoint), "://")
s := strings.Split(e[1], ":")
port = s[1]
addrList = append(addrList, s[0])
if e[0] == "http" {
tlsDisable = true
}
}
if tlsDisable {
if output, err := runtime.GetRunner().SudoCmd("/usr/local/bin/kubectl -n kubesphere-monitoring-system create secret generic kube-etcd-client-certs", true, false); err != nil {
if !strings.Contains(output, "exists") {
return err
}
}
} else {
caFile := fmt.Sprintf("/etc/ssl/etcd/ssl/%s", filepath.Base(s.KubeConf.Cluster.Etcd.External.CAFile))
certFile := fmt.Sprintf("/etc/ssl/etcd/ssl/%s", filepath.Base(s.KubeConf.Cluster.Etcd.External.CertFile))
keyFile := fmt.Sprintf("/etc/ssl/etcd/ssl/%s", filepath.Base(s.KubeConf.Cluster.Etcd.External.KeyFile))
if output, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("/usr/local/bin/kubectl -n kubesphere-monitoring-system create secret generic kube-etcd-client-certs "+
"--from-file=etcd-client-ca.crt=%s "+
"--from-file=etcd-client.crt=%s "+
"--from-file=etcd-client.key=%s", caFile, certFile, keyFile), true, false); err != nil {
if !strings.Contains(output, "exists") {
return err
}
}
}
}
var sedCommand = runtime.GetCommandSed()
etcdEndPoint := strings.Join(addrList, ",")
var cmdEndpoint = fmt.Sprintf("%s '/endpointIps/s/\\:.*/\\: %s/g' %s", sedCommand, etcdEndPoint, filePath)
if _, err := runtime.GetRunner().SudoCmd(cmdEndpoint, false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("update etcd endpoint failed"))
}
if tlsDisable {
if _, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("%s '/tlsEnable/s/\\:.*/\\: false/g' %s", sedCommand, filePath),
false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("update etcd tls failed"))
}
}
if len(port) != 0 {
if _, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("%s 's/2379/%s/g' %s", sedCommand, port, filePath),
false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("update etcd tls failed"))
}
}
if s.KubeConf.Cluster.Registry.PrivateRegistry != "" {
PrivateRegistry := strings.Replace(s.KubeConf.Cluster.Registry.PrivateRegistry, "/", "\\/", -1)
if _, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("%s '/local_registry/s/\\:.*/\\: %s/g' %s", sedCommand, PrivateRegistry, filePath),
false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("add private registry: %s failed", s.KubeConf.Cluster.Registry.PrivateRegistry))
}
} else {
if _, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("%s '/local_registry/d' %s", sedCommand, filePath), false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("remove private registry failed"))
}
}
if s.KubeConf.Cluster.Registry.NamespaceOverride != "" {
if _, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("%s '/namespace_override/s/\\:.*/\\: %s/g' %s", sedCommand, s.KubeConf.Cluster.Registry.NamespaceOverride, filePath),
false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("add namespace override: %s failed", s.KubeConf.Cluster.Registry.NamespaceOverride))
}
} else {
if _, err := runtime.GetRunner().SudoCmd(fmt.Sprintf("%s '/namespace_override/d' %s", sedCommand, filePath), false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("remove namespace override failed"))
}
}
_, ok = kubesphere.CNSource[s.KubeConf.Cluster.KubeSphere.Version]
if ok && (os.Getenv("KKZONE") == "cn" || s.KubeConf.Cluster.Registry.PrivateRegistry == "registry.cn-beijing.aliyuncs.com") {
if _, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("%s '/zone/s/\\:.*/\\: %s/g' %s", sedCommand, "cn", filePath),
false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("add kubekey zone: %s failed", s.KubeConf.Cluster.Registry.PrivateRegistry))
}
} else {
if _, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("%s '/zone/d' %s", sedCommand, filePath),
false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("remove kubekey zone failed"))
}
}
switch s.KubeConf.Cluster.Kubernetes.ContainerManager {
case "docker", "containerd", "crio":
if _, err := runtime.GetRunner().SudoCmd(
fmt.Sprintf("%s '/containerruntime/s/\\:.*/\\: %s/g' %s", sedCommand, s.KubeConf.Cluster.Kubernetes.ContainerManager, filePath), false, false); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("set container runtime: %s failed", s.KubeConf.Cluster.Kubernetes.ContainerManager))
}
default:
logger.Infof(
fmt.Sprintf("%s Currently, the logging module of KubeSphere does not support %s. If %s is used, the logging module will be unavailable.", runtime.RemoteHost().GetName(),
s.KubeConf.Cluster.Kubernetes.ContainerManager, s.KubeConf.Cluster.Kubernetes.ContainerManager))
}
return nil
}
type Apply struct {
common.KubeAction
}
func (a *Apply) Execute(runtime connector.Runtime) error {
var kubectlpath, ok = a.PipelineCache.GetMustString(common.CacheCommandKubectlPath)
if !ok || kubectlpath == "" {
kubectlpath = path.Join(common.BinDir, common.CommandKubectl)
}
filePath := filepath.Join(common.KubeAddonsDir, templates.KsInstaller.Name())
// if runtime.GetSystemInfo().IsDarwin() {
// filePath = path.Join(common.TmpDir, filePath)
// }
deployKubesphereCmd := fmt.Sprintf("%s apply -f %s --force", kubectlpath, filePath)
if _, err := runtime.GetRunner().Cmd(deployKubesphereCmd, false, true); err != nil {
return errors.Wrapf(errors.WithStack(err), "deploy %s failed", filePath)
}
return nil
}
type GetKubeCommand struct {
common.KubeAction
}

View File

@@ -1,109 +0,0 @@
/*
Copyright 2021 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v2
type V2 struct {
Persistence Persistence `yaml:"persistence"`
Common Common `yaml:"common"`
Etcd Etcd `yaml:"etcd"`
MetricsServerOld MetricsServerOld `yaml:"metrics-server"`
MetricsServerNew MetricsServerNew `yaml:"metrics_server"`
Console Console `yaml:"console"`
Monitoring Monitoring `yaml:"monitoring"`
Logging Logging `yaml:"logging"`
Openpitrix Openpitrix `yaml:"openpitrix"`
Devops Devops `yaml:"devops"`
Servicemesh Servicemesh `yaml:"servicemesh"`
Notification Notification `yaml:"notification"`
Alerting Alerting `yaml:"alerting"`
LocalRegistry string `yaml:"local_registry"`
}
type Persistence struct {
StorageClass string `yaml:"storageClass"`
}
type Etcd struct {
Monitoring bool `yaml:"monitoring"`
EndpointIps string `yaml:"endpointIps"`
Port int `yaml:"port"`
TlsEnable bool `yaml:"tlsEnable"`
}
type Common struct {
MysqlVolumeSize string `yaml:"mysqlVolumeSize"`
MinioVolumeSize string `yaml:"minioVolumeSize"`
EtcdVolumeSize string `yaml:"etcdVolumeSize"`
OpenldapVolumeSize string `yaml:"openldapVolumeSize"`
RedisVolumSize string `yaml:"redisVolumSize"`
}
type MetricsServerOld struct {
Enabled string `yaml:"enabled"`
}
type MetricsServerNew struct {
Enabled string `yaml:"enabled"`
}
type Console struct {
EnableMultiLogin bool `yaml:"enableMultiLogin"`
Port int `yaml:"port"`
}
type Monitoring struct {
PrometheusReplicas int `yaml:"prometheusReplicas"`
PrometheusMemoryRequest string `yaml:"prometheusMemoryRequest"`
PrometheusVolumeSize string `yaml:"prometheusVolumeSize"`
}
type Logging struct {
Enabled bool `yaml:"enabled"`
ElasticsearchMasterReplicas int `yaml:"elasticsearchMasterReplicas"`
ElasticsearchDataReplicas int `yaml:"elasticsearchDataReplicas"`
LogsidecarReplicas int `yaml:"logsidecarReplicas"`
ElasticsearchVolumeSize string `yaml:"elasticsearchVolumeSize"`
ElasticsearchMasterVolumeSize string `yaml:"elasticsearchMasterVolumeSize"`
ElasticsearchDataVolumeSize string `yaml:"elasticsearchDataVolumeSize"`
LogMaxAge int `yaml:"logMaxAge"`
ElkPrefix string `yaml:"elkPrefix"`
}
type Openpitrix struct {
Enabled bool `yaml:"enabled"`
}
type Devops struct {
Enabled bool `yaml:"enabled"`
JenkinsMemoryLim string `yaml:"jenkinsMemoryLim"`
JenkinsMemoryReq string `yaml:"jenkinsMemoryReq"`
JenkinsVolumeSize string `yaml:"jenkinsVolumeSize"`
JenkinsjavaoptsXms string `yaml:"jenkinsJavaOpts_Xms"`
JenkinsjavaoptsXmx string `yaml:"jenkinsJavaOpts_Xmx"`
JenkinsjavaoptsMaxram string `yaml:"jenkinsJavaOpts_MaxRAM"`
}
type Servicemesh struct {
Enabled bool `yaml:"enabled"`
}
type Notification struct {
Enabled bool `yaml:"enabled"`
}
type Alerting struct {
Enabled bool `yaml:"enabled"`
}

View File

@@ -1,160 +0,0 @@
/*
Copyright 2021 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v3
type ClusterConfig struct {
ApiVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Metadata Metadata `yaml:"metadata"`
Spec *V3 `yaml:"spec"`
}
type Metadata struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
Label Label `yaml:"labels"`
}
type Label struct {
Version string `yaml:"version"`
}
type V3 struct {
Persistence Persistence `yaml:"persistence"`
Authentication Authentication `yaml:"authentication"`
Common Common `yaml:"common"`
Etcd Etcd `yaml:"etcd"`
MetricsServer MetricsServer `yaml:"metrics_server"`
Console Console `yaml:"console"`
Monitoring Monitoring `yaml:"monitoring"`
Logging Logging `yaml:"logging"`
Openpitrix Openpitrix `yaml:"openpitrix"`
Devops Devops `yaml:"devops"`
Servicemesh Servicemesh `yaml:"servicemesh"`
Notification Notification `yaml:"notification"`
Alerting Alerting `yaml:"alerting"`
Auditing Auditing `yaml:"auditing"`
Events Events `yaml:"events"`
Multicluster Multicluster `yaml:"multicluster"`
Networkpolicy Networkpolicy `yaml:"networkpolicy"`
LocalRegistry string `yaml:"local_registry"`
}
type Persistence struct {
StorageClass string `yaml:"storageClass"`
}
type MetricsServer struct {
Enabled bool `yaml:"enabled"`
}
type Authentication struct {
JwtSecret string `yaml:"jwtSecret"`
}
type Etcd struct {
Monitoring bool `yaml:"monitoring"`
EndpointIps string `yaml:"endpointIps"`
Port int `yaml:"port"`
TlsEnable bool `yaml:"tlsEnable"`
}
type Common struct {
MysqlVolumeSize string `yaml:"mysqlVolumeSize"`
MinioVolumeSize string `yaml:"minioVolumeSize"`
EtcdVolumeSize string `yaml:"etcdVolumeSize"`
OpenldapVolumeSize string `yaml:"openldapVolumeSize"`
RedisVolumSize string `yaml:"redisVolumSize"`
ES ES `yaml:"es"`
}
type ES struct {
//ElasticsearchMasterReplicas int `yaml:"elasticsearchMasterReplicas"`
//ElasticsearchDataReplicas int `yaml:"elasticsearchDataReplicas"`
ElasticsearchMasterVolumeSize string `yaml:"elasticsearchMasterVolumeSize"`
ElasticsearchDataVolumeSize string `yaml:"elasticsearchDataVolumeSize"`
LogMaxAge int `yaml:"logMaxAge"`
ElkPrefix string `yaml:"elkPrefix"`
}
type Console struct {
EnableMultiLogin bool `yaml:"enableMultiLogin"`
Port int `yaml:"port"`
}
type Alerting struct {
Enabled bool `yaml:"enabled"`
}
type Auditing struct {
Enabled bool `yaml:"enabled"`
}
type Devops struct {
Enabled bool `yaml:"enabled"`
JenkinsMemoryLim string `yaml:"jenkinsMemoryLim"`
JenkinsMemoryReq string `yaml:"jenkinsMemoryReq"`
JenkinsVolumeSize string `yaml:"jenkinsVolumeSize"`
JenkinsjavaoptsXms string `yaml:"jenkinsJavaOpts_Xms"`
JenkinsjavaoptsXmx string `yaml:"jenkinsJavaOpts_Xmx"`
JenkinsjavaoptsMaxram string `yaml:"jenkinsJavaOpts_MaxRAM"`
}
type Events struct {
Enabled bool `yaml:"enabled"`
Ruler Ruler `yaml:"ruler"`
}
type Ruler struct {
Enabled bool `yaml:"enabled"`
Replicas int `yaml:"replicas"`
}
type Logging struct {
Enabled bool `yaml:"enabled"`
LogsidecarReplicas int `yaml:"logsidecarReplicas"`
}
type Metrics struct {
Enabled bool `yaml:"enabled"`
}
type Monitoring struct {
//AlertmanagerReplicas int `yaml:"alertmanagerReplicas"`
//PrometheusReplicas int `yaml:"prometheusReplicas"`
PrometheusMemoryRequest string `yaml:"prometheusMemoryRequest"`
PrometheusVolumeSize string `yaml:"prometheusVolumeSize"`
}
type Multicluster struct {
ClusterRole string `yaml:"clusterRole"`
}
type Networkpolicy struct {
Enabled bool `yaml:"enabled"`
}
type Notification struct {
Enabled bool `yaml:"enabled"`
}
type Openpitrix struct {
Enabled bool `yaml:"enabled"`
}
type Servicemesh struct {
Enabled bool `yaml:"enabled"`
}

View File

@@ -37,12 +37,7 @@ func NewDarwinClusterPhase(runtime *common.KubeRuntime, manifestMap manifest.Ins
},
&kubesphere.DeployMiniKubeModule{},
&kubesphere.DeployModule{Skip: !runtime.Cluster.KubeSphere.Enabled},
&ksplugins.DeployKsPluginsModule{},
//&ksplugins.DeployRedisModule{},
&ksplugins.CreateKubeSphereSecretModule{},
&ksplugins.DeployKsCoreConfigModule{}, // ks-core-config
&ksplugins.CreateMonitorDashboardModule{},
//&ksplugins.CreateNotificationModule{},
&ksplugins.DeployPrometheusModule{},
&ksplugins.DeployKsCoreModule{},
&kubesphere.CheckResultModule{Skip: !runtime.Cluster.KubeSphere.Enabled},
@@ -94,13 +89,8 @@ func NewK3sCreateClusterPhase(runtime *common.KubeRuntime, manifestMap manifest.
&certs.AutoRenewCertsModule{Skip: !runtime.Cluster.Kubernetes.EnableAutoRenewCerts()},
&k3s.SaveKubeConfigModule{},
&storage.DeployLocalVolumeModule{Skip: skipLocalStorage},
&kubesphere.DeployModule{Skip: !runtime.Cluster.KubeSphere.Enabled}, //
&ksplugins.DeployKsPluginsModule{},
//&ksplugins.DeployRedisModule{},
&ksplugins.CreateKubeSphereSecretModule{},
&ksplugins.DeployKsCoreConfigModule{}, // ks-core-config
&ksplugins.CreateMonitorDashboardModule{},
//&ksplugins.CreateNotificationModule{},
&kubesphere.DeployModule{Skip: !runtime.Cluster.KubeSphere.Enabled},
&ksplugins.DeployKsCoreConfigModule{},
&ksplugins.DeployPrometheusModule{},
&ksplugins.DeployKsCoreModule{},
&kubesphere.CheckResultModule{Skip: !runtime.Cluster.KubeSphere.Enabled},
@@ -157,12 +147,7 @@ func NewCreateClusterPhase(runtime *common.KubeRuntime, manifestMap manifest.Ins
&kubernetes.SaveKubeConfigModule{},
&storage.DeployLocalVolumeModule{Skip: skipLocalStorage},
&kubesphere.DeployModule{Skip: !runtime.Cluster.KubeSphere.Enabled},
&ksplugins.DeployKsPluginsModule{},
//&ksplugins.DeployRedisModule{},
&ksplugins.CreateKubeSphereSecretModule{},
&ksplugins.DeployKsCoreConfigModule{}, // ! ks-core-config
&ksplugins.CreateMonitorDashboardModule{},
//&ksplugins.CreateNotificationModule{},
&ksplugins.DeployPrometheusModule{},
&ksplugins.DeployKsCoreModule{},
&kubesphere.CheckResultModule{Skip: !runtime.Cluster.KubeSphere.Enabled}, // check ks-apiserver phase

View File

@@ -25,7 +25,6 @@ func CliInstallTerminusPipeline(opts *options.CliTerminusInstallOptions) error {
arg.SetOlaresVersion(opts.Version)
arg.SetMinikubeProfile(opts.MiniKubeProfile)
arg.SetStorage(getStorageValueFromEnv())
arg.SetTokenMaxAge()
arg.SetSwapConfig(opts.SwapConfig)
if err := arg.SwapConfig.Validate(); err != nil {
return err

View File

@@ -35,7 +35,6 @@ func PrepareSystemPipeline(opts *options.CliPrepareSystemOptions, components []s
arg.SetOlaresVersion(opts.Version)
arg.SetRegistryMirrors(opts.RegistryMirrors)
arg.SetStorage(getStorageValueFromEnv())
arg.SetTokenMaxAge()
runtime, err := common.NewKubeRuntime(common.AllInOne, *arg)
if err != nil {

View File

@@ -16,7 +16,6 @@ import (
"github.com/beclab/Olares/cli/pkg/core/logger"
"github.com/beclab/Olares/cli/pkg/storage"
"github.com/beclab/Olares/cli/pkg/clientset"
"github.com/beclab/Olares/cli/pkg/common"
cc "github.com/beclab/Olares/cli/pkg/core/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
@@ -235,50 +234,6 @@ func (p *Patch) Execute(runtime connector.Runtime) error {
return errors.Wrap(errors.WithStack(err), "patch globalrole workspace manager failed")
}
//var notificationManager = path.Join(runtime.GetInstallerDir(), "deploy", "patch-notification-manager.yaml")
//if _, err = runtime.GetRunner().SudoCmd(fmt.Sprintf("%s apply -f %s", kubectl, notificationManager), false, true); err != nil {
// return errors.Wrap(errors.WithStack(err), "patch notification manager failed")
//}
//var notificationManager = path.Join(runtime.GetInstallerDir(), "deploy", "patch-notification-manager.yaml")
//if _, err = runtime.GetRunner().Host.SudoCmd(fmt.Sprintf("%s apply -f %s", kubectl, notificationManager), false, true); err != nil {
// return errors.Wrap(errors.WithStack(err), "patch notification manager failed")
//}
//
//patchAdminContent := `{"metadata":{"finalizers":["finalizers.kubesphere.io/users"]}}`
//patchAdminCMD := fmt.Sprintf(
// "%s patch user admin -p '%s' --type='merge' ",
// kubectl,
// patchAdminContent)
//_, err = runtime.GetRunner().SudoCmd(patchAdminCMD, false, true)
//if err != nil {
// return errors.Wrap(errors.WithStack(err), "patch user admin failed")
//}
//patchAdminContent := "{\\\"metadata\\\":{\\\"finalizers\\\":[\\\"finalizers.kubesphere.io/users\\\"]}}"
//patchAdminCMD := fmt.Sprintf(
// "%s patch user admin -p '%s' --type='merge' ",
// kubectl,
// patchAdminContent)
//_, err = runtime.GetRunner().Host.SudoCmd(patchAdminCMD, false, true)
//if err != nil {
// return errors.Wrap(errors.WithStack(err), "patch user admin failed")
//}
//deleteAdminCMD := fmt.Sprintf("%s delete user admin --ignore-not-found", kubectl)
//_, err = runtime.GetRunner().SudoCmd(deleteAdminCMD, false, true)
//if err != nil {
// return errors.Wrap(errors.WithStack(err), "failed to delete ks admin user")
//}
deleteKubectlAdminCMD := fmt.Sprintf("%s -n kubesphere-controls-system delete deploy kubectl-admin --ignore-not-found", kubectl)
_, err = runtime.GetRunner().SudoCmd(deleteKubectlAdminCMD, false, true)
if err != nil {
return errors.Wrap(errors.WithStack(err), "failed to delete ks kubectl admin deployment")
}
deleteHTTPBackendCMD := fmt.Sprintf("%s -n kubesphere-controls-system delete deploy default-http-backend --ignore-not-found", kubectl)
_, err = runtime.GetRunner().SudoCmd(deleteHTTPBackendCMD, false, true)
if err != nil {
return errors.Wrap(errors.WithStack(err), "failed to delete ks default http backend")
}
patchFelixConfigContent := `{"spec":{"featureDetectOverride": "SNATFullyRandom=false,MASQFullyRandom=false"}}`
patchFelixConfigCMD := fmt.Sprintf(
"%s patch felixconfiguration default -p '%s' --type='merge'",
@@ -466,19 +421,6 @@ func cloudValue(cloudInstance bool) string {
return ""
}
func getRedisPassword(client clientset.Client, runtime connector.Runtime) (string, error) {
secret, err := client.Kubernetes().CoreV1().Secrets(common.NamespaceKubesphereSystem).Get(context.Background(), "redis-secret", metav1.GetOptions{})
if err != nil {
return "", errors.Wrap(errors.WithStack(err), "get redis secret failed")
}
if secret == nil || secret.Data == nil || secret.Data["auth"] == nil {
return "", fmt.Errorf("redis secret not found")
}
return string(secret.Data["auth"]), nil
}
type UserEnvConfig struct {
APIVersion string `yaml:"apiVersion"`
UserEnvs []v1alpha1.EnvVarSpec `yaml:"userEnvs"`

View File

@@ -1,22 +0,0 @@
package terminus
import (
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
)
type NotEqualDesiredVersion struct {
common.KubePrepare
}
func (n *NotEqualDesiredVersion) PreCheck(runtime connector.Runtime) (bool, error) {
ksVersion, ok := n.PipelineCache.GetMustString(common.KubeSphereVersion)
if !ok {
ksVersion = ""
}
if n.KubeConf.Cluster.KubeSphere.Version == ksVersion {
return false, nil
}
return true, nil
}

View File

@@ -738,6 +738,19 @@ func (p *DetectPublicIPAddress) Execute(runtime connector.Runtime) error {
}
}
if util.IsOnAliyunECS() {
logger.Info("on Aliyun ECS instance, will try to check if a public IP address is bound")
aliyunPublicIP, err := util.GetPublicIPFromAliyunIMDS()
if err != nil {
return errors.Wrap(err, "failed to get public IP from Aliyun")
}
if aliyunPublicIP != nil {
logger.Info("retrieved public IP addresses from IMDS")
p.KubeConf.Arg.NetworkSettings.CloudProviderPublicIP = aliyunPublicIP
return nil
}
}
osPublicIPs, err := util.GetPublicIPsFromOS()
if err != nil {
return errors.Wrap(err, "failed to get public IPs from OS")

92
cli/pkg/upgrade/1_12_3.go Normal file
View File

@@ -0,0 +1,92 @@
package upgrade
import (
"time"
"github.com/Masterminds/semver/v3"
"github.com/beclab/Olares/cli/pkg/core/task"
"github.com/beclab/Olares/cli/version"
)
var version_1_12_3 = semver.MustParse("1.12.3")
type upgrader_1_12_3 struct {
breakingUpgraderBase
}
func (u upgrader_1_12_3) Version() *semver.Version {
cliVersion, err := semver.NewVersion(version.VERSION)
// tolerate local dev version
if err != nil {
return version_1_12_3
}
if samePatchLevelVersion(version_1_12_3, cliVersion) && getReleaseLineOfVersion(cliVersion) == mainLine {
return cliVersion
}
return version_1_12_3
}
func (u upgrader_1_12_3) AddedBreakingChange() bool {
if u.Version().Equal(version_1_12_3) {
return true
}
return false
}
func (u upgrader_1_12_3) NeedRestart() bool {
return true
}
func (u upgrader_1_12_3) PrepareForUpgrade() []task.Interface {
tasks := make([]task.Interface, 0)
tasks = append(tasks, upgradeKsConfig()...)
tasks = append(tasks, upgradePrometheusServiceMonitorKubelet()...)
tasks = append(tasks, upgradeKSCore()...)
tasks = append(tasks, upgradeNodeExporter()...)
tasks = append(tasks,
&task.LocalTask{
Name: "DeleteArgoProjV1alpha1CRDs",
Action: new(deleteArgoProjV1alpha1CRDs),
Retry: 3,
Delay: 5 * time.Second,
},
)
tasks = append(tasks, regenerateKubeFiles()...)
tasks = append(tasks, u.upgraderBase.PrepareForUpgrade()...)
return tasks
}
func (u upgrader_1_12_3) UpgradeSystemComponents() []task.Interface {
pre := []task.Interface{
&task.LocalTask{
Name: "UpgradeL4BFLProxy",
Action: &upgradeL4BFLProxy{Tag: "v0.3.9"},
Retry: 3,
Delay: 5 * time.Second,
},
}
return append(pre, u.upgraderBase.UpgradeSystemComponents()...)
}
func (u upgrader_1_12_3) UpdateOlaresVersion() []task.Interface {
var tasks []task.Interface
tasks = append(tasks,
&task.LocalTask{
Name: "UpgradeGPUDriver",
Action: new(upgradeGPUDriverIfNeeded),
},
)
tasks = append(tasks, u.upgraderBase.UpdateOlaresVersion()...)
tasks = append(tasks,
&task.LocalTask{
Name: "RebootIfNeeded",
Action: new(rebootIfNeeded),
},
)
return tasks
}
func init() {
registerMainUpgrader(upgrader_1_12_3{})
}

View File

@@ -0,0 +1,102 @@
package upgrade
import (
"context"
"fmt"
"time"
"github.com/beclab/Olares/cli/pkg/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/core/task"
"github.com/Masterminds/semver/v3"
apixclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
)
type upgrader_1_12_3_20251217 struct {
breakingUpgraderBase
}
func (u upgrader_1_12_3_20251217) Version() *semver.Version {
return semver.MustParse("1.12.3-20251217")
}
func (u upgrader_1_12_3_20251217) PrepareForUpgrade() []task.Interface {
tasks := make([]task.Interface, 0)
tasks = append(tasks,
&task.LocalTask{
Name: "DeleteArgoProjV1alpha1CRDs",
Action: new(deleteArgoProjV1alpha1CRDs),
Retry: 3,
Delay: 5 * time.Second,
},
)
tasks = append(tasks, u.upgraderBase.PrepareForUpgrade()...)
return tasks
}
func (u upgrader_1_12_3_20251217) NeedRestart() bool {
return true
}
func (u upgrader_1_12_3_20251217) UpdateOlaresVersion() []task.Interface {
var tasks []task.Interface
tasks = append(tasks,
&task.LocalTask{
Name: "UpgradeGPUDriver",
Action: new(upgradeGPUDriverIfNeeded),
},
)
tasks = append(tasks, u.upgraderBase.UpdateOlaresVersion()...)
tasks = append(tasks,
&task.LocalTask{
Name: "RebootIfNeeded",
Action: new(rebootIfNeeded),
},
)
return tasks
}
func init() {
registerDailyUpgrader(upgrader_1_12_3_20251217{})
}
type deleteArgoProjV1alpha1CRDs struct {
common.KubeAction
}
func (a *deleteArgoProjV1alpha1CRDs) Execute(runtime connector.Runtime) error {
config, err := ctrl.GetConfig()
if err != nil {
return fmt.Errorf("failed to get rest config: %s", err)
}
client, err := apixclientset.NewForConfig(config)
if err != nil {
return fmt.Errorf("failed to create crd client: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
crds, err := client.ApiextensionsV1().CustomResourceDefinitions().List(ctx, metav1.ListOptions{})
if err != nil {
return fmt.Errorf("failed to list CRDs: %v", err)
}
for _, crd := range crds.Items {
if crd.Spec.Group != "argoproj.io" {
continue
}
if crd.Annotations["meta.helm.sh/release-name"] != "knowledge" {
continue
}
if err := client.ApiextensionsV1().CustomResourceDefinitions().Delete(ctx, crd.Name, metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) {
return fmt.Errorf("failed to delete CRD %s: %v", crd.Name, err)
}
}
return nil
}

View File

@@ -71,11 +71,10 @@ func upgradeKSCore() []task.Interface {
Action: new(plugins.CopyEmbedFiles),
},
&task.LocalTask{
Name: "UpgradeKSCore",
Prepare: new(common.GetMasterNum),
Action: new(plugins.CreateKsCore),
Retry: 10,
Delay: 10 * time.Second,
Name: "UpgradeKSCore",
Action: new(plugins.CreateKsCore),
Retry: 10,
Delay: 10 * time.Second,
},
&task.LocalTask{
Name: "CheckKSCoreRunning",

View File

@@ -192,7 +192,8 @@ func CheckJWS(jws string, duration int64) (*CheckJWSResult, error) {
// Check timestamp
now := time.Now().UnixMilli()
if now-timestamp > duration {
diff := now - timestamp
if max(diff, -diff) > duration {
return nil, fmt.Errorf("timestamp is out of range")
}

View File

@@ -488,7 +488,6 @@ func (i *InstallTerminus) Execute(runtime connector.Runtime) error {
var envs = []string{
fmt.Sprintf("export %s=%s", common.ENV_KUBE_TYPE, i.KubeConf.Arg.Kubetype),
fmt.Sprintf("export %s=%s", common.ENV_REGISTRY_MIRRORS, i.KubeConf.Arg.RegistryMirrors),
fmt.Sprintf("export %s=%d", common.ENV_TOKEN_MAX_AGE, i.KubeConf.Arg.TokenMaxAge),
fmt.Sprintf("export %s=%s", common.ENV_PREINSTALL, os.Getenv(common.ENV_PREINSTALL)),
fmt.Sprintf("export %s=%s", common.ENV_HOST_IP, systemInfo.GetLocalIp()),
fmt.Sprintf("export %s=%s", common.ENV_DISABLE_HOST_IP_PROMPT, os.Getenv(common.ENV_DISABLE_HOST_IP_PROMPT)),

View File

@@ -30,7 +30,6 @@ type proxyServer struct {
func NewProxyServer() (*proxyServer, error) {
p := &proxyServer{
proxy: echo.New(),
dnsServer: "10.233.0.3:53", // default k8s dns service
}
return p, nil
@@ -38,6 +37,18 @@ func NewProxyServer() (*proxyServer, error) {
func (p *proxyServer) Start() error {
klog.Info("Starting intranet proxy server...")
if p.proxy != nil {
err := p.proxy.Close()
if err != nil {
klog.Error("close intranet proxy server error, ", err)
return err
}
p.proxy = nil
}
// closed echo proxy server cannot be restarted, so create a new one
p.proxy = echo.New()
config := middleware.DefaultProxyConfig
config.Balancer = p
config.Transport = p.initTransport()
@@ -109,8 +120,12 @@ func (p *proxyServer) Start() error {
func (p *proxyServer) Close() error {
if p.proxy != nil {
return p.proxy.Close()
err := p.proxy.Close()
if err != nil {
klog.Error("close intranet proxy server error, ", err)
}
}
p.proxy = nil
p.stopped = true
return nil
}

View File

@@ -5,12 +5,14 @@ import (
"fmt"
"os/exec"
"strings"
"time"
"github.com/beclab/Olares/daemon/internel/intranet"
"github.com/beclab/Olares/daemon/internel/watcher"
"github.com/beclab/Olares/daemon/pkg/cluster/state"
"github.com/beclab/Olares/daemon/pkg/nets"
"github.com/beclab/Olares/daemon/pkg/utils"
"github.com/miekg/dns"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -181,6 +183,9 @@ func (w *applicationWatcher) loadServerConfig(ctx context.Context, nodeIp string
return options, nil
}
var adguardDnsPodIp string
var adguardHealth bool
func (w *applicationWatcher) loadDnsPodConfig(ctx context.Context, o *intranet.ServerOptions) error {
// try to find adguard dns pod ip and mac
k8sClient, err := utils.GetKubeClient()
@@ -199,7 +204,36 @@ func (w *applicationWatcher) loadDnsPodConfig(ctx context.Context, o *intranet.S
const adguardDnsAppLabel = "applications.app.bytetrade.io/name"
for _, pod := range dnsPods.Items {
switch {
case pod.Labels[adguardDnsAppLabel] == "adguardhome", pod.Labels["k8s-app"] == "kube-dns":
case pod.Labels[adguardDnsAppLabel] == "adguardhome":
dnsPodIp = pod.Status.PodIP
// try to connect adguard dns pod port 53 to verify it's running
if adguardDnsPodIp != dnsPodIp || !adguardHealth {
adguardDnsPodIp = dnsPodIp
err := checkHealth(dnsPodIp)
if err != nil {
klog.Warning("dial adguard dns pod tcp 53 error, ", err)
adguardHealth = false
} else {
adguardHealth = true
}
}
if adguardHealth {
dnsPodMac, calicoRouteIface, err = getPodNeighborInfo(dnsPodIp)
if err != nil {
klog.Error("get adguard dns pod mac by ip error, ", err)
return err
}
// found adguard dns pod
o.DnsPodIp = dnsPodIp
o.DnsPodMac = dnsPodMac
o.DnsPodCalicoIface = calicoRouteIface
return nil
}
case pod.Labels["k8s-app"] == "kube-dns":
dnsPodIp = pod.Status.PodIP
dnsPodMac, calicoRouteIface, err = getPodNeighborInfo(dnsPodIp)
if err != nil {
@@ -208,13 +242,7 @@ func (w *applicationWatcher) loadDnsPodConfig(ctx context.Context, o *intranet.S
}
}
if pod.Labels[adguardDnsAppLabel] == "adguardhome" {
o.DnsPodIp = dnsPodIp
o.DnsPodMac = dnsPodMac
o.DnsPodCalicoIface = calicoRouteIface
return nil
}
}
} // end for pods
// not found adguard dns pod, but core dns pod exists
if dnsPodIp != "" {
@@ -261,3 +289,15 @@ func getPodNeighborInfo(podIp string) (mac, iface string, err error) {
return "", "", fmt.Errorf("not found pod neighbor info for ip %s", podIp)
}
func checkHealth(server string) error {
c := new(dns.Client)
c.Timeout = time.Second
msg := new(dns.Msg)
msg.SetQuestion(dns.Fqdn("coredns.kube-system.svc.cluster.local."), dns.TypeA)
msg.RecursionDesired = true
_, _, err := c.Exchange(msg, server+":53")
return err
}

View File

@@ -74,7 +74,7 @@ func NewUmountWatcher() *umountWatcher {
}
func (w *umountWatcher) Watch(ctx context.Context) {
if err := utils.UmountBrokenUsbMount(ctx, commands.MOUNT_BASE_DIR); err != nil {
if err := utils.UmountBrokenMount(ctx, commands.MOUNT_BASE_DIR); err != nil {
klog.Error("umount broken mount point error, ", err)
}
}

View File

@@ -114,6 +114,17 @@ func CheckCurrentStatus(ctx context.Context) error {
var currentTerminusState TerminusState = CurrentState.TerminusState
defer func() {
if currentTerminusState == SystemError {
restarting, err := utils.SystemStartLessThan(10 * time.Minute) // uptime less then 10 minutes
if err != nil {
klog.Error(err)
}
if restarting {
currentTerminusState = Restarting
}
}
CurrentState.TerminusState = currentTerminusState
TerminusStateMu.Unlock()
klog.Info("current state: ", CurrentState.TerminusState)
@@ -447,16 +458,6 @@ func CheckCurrentStatus(ctx context.Context) error {
return nil
}
restarting, err := utils.SystemStartLessThan(10 * time.Minute) // uptime less then 10 minutes
if err != nil {
return err
}
if restarting {
currentTerminusState = Restarting
return nil
}
currentTerminusState = SystemError
}

View File

@@ -12,6 +12,9 @@ import (
"github.com/beclab/Olares/daemon/pkg/cluster/state"
"github.com/beclab/Olares/daemon/pkg/containerd"
"github.com/dustin/go-humanize"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
v1 "k8s.io/cri-api/pkg/apis/runtime/v1"
"k8s.io/utils/strings/slices"
@@ -192,6 +195,55 @@ func (i *preCheck) Execute(ctx context.Context, p any) (res any, err error) {
return nil, fmt.Errorf("waiting for user to finish activation: %s", strings.Join(activatingUsers, ", "))
}
// the new MongoDB version has a different implementation from the old version.
// if an old MongoDB instance exists, it must be uninstalled before upgrading.
{
gvr := schema.GroupVersionResource{Group: "app.bytetrade.io", Version: "v1alpha1", Resource: "applicationmanagers"}
am, err := dynamicClient.Resource(gvr).Get(ctx, "os-platform-mongodb", metav1.GetOptions{})
if err != nil {
if !apierrors.IsNotFound(err) {
return nil, fmt.Errorf("failed to check mongodb application manager: %v", err)
}
} else if am != nil {
state, _, _ := unstructured.NestedString(am.Object, "status", "state")
switch strings.ToLower(state) {
case "installing", "running":
return nil, fmt.Errorf("mongodb is %s, please remove it before upgrade. if mongodb is installing, you can cancel it in market. if running, execute 'kubectl delete appmgr os-platform-mongodb' in control-hub -> olares shell", state)
}
}
}
// in v1.12.3, argo has been moved to os-platform.
// to avoid CRD resource conflicts, if wise is installed and includes argo crd, you must uninstall wise first, including sharedserver.
{
isKnowledgeSharedNsExist := false
if _, err := client.CoreV1().Namespaces().Get(ctx, "knowledge-shared", metav1.GetOptions{}); err == nil {
isKnowledgeSharedNsExist = true
} else if !apierrors.IsNotFound(err) {
return nil, fmt.Errorf("failed to check namespace 'knowledge-shared': %v", err)
}
xclient, err := utils.GetApixClient()
if err != nil {
err = fmt.Errorf("failed to get apix client: %v", err)
klog.Error(err.Error())
return nil, err
}
isKnowledgeArgoCRDExist := false
crds, err := xclient.ApiextensionsV1().CustomResourceDefinitions().List(ctx, metav1.ListOptions{})
if err != nil {
klog.Errorf("failed to list crds %v", err)
return nil, err
}
for _, crd := range crds.Items {
if crd.Spec.Group == "argoproj.io" && crd.Annotations["meta.helm.sh/release-name"] == "knowledge" {
isKnowledgeArgoCRDExist = true
break
}
}
if isKnowledgeSharedNsExist && isKnowledgeArgoCRDExist {
return nil, fmt.Errorf("namespace 'knowledge-shared' exists (wise); please uninstall Wise and Shared Server before upgrade")
}
}
klog.Info("pre checks passed for upgrade")
return newExecutionRes(true, nil), nil

View File

@@ -383,17 +383,7 @@ func UmountUsbDevice(ctx context.Context, path string) error {
return errors.New("not a mounted usb path")
}
func UmountBrokenUsbMount(ctx context.Context, baseDir string) error {
usbdevs, err := DetectdUsbDevices(ctx)
if err != nil {
return err
}
hdddevs, err := DetectdHddDevices(ctx)
if err != nil {
return err
}
func UmountBrokenMount(ctx context.Context, baseDir string) error {
mounter := mountutils.New("")
list, err := mounter.List()
if err != nil {
@@ -403,16 +393,9 @@ func UmountBrokenUsbMount(ctx context.Context, baseDir string) error {
for _, m := range list {
if strings.HasPrefix(m.Path, baseDir) && !strings.HasPrefix(m.Path, path.Join(baseDir, "ai")) {
if !slices.ContainsFunc(usbdevs, func(u storageDevice) bool { return u.DevPath == m.Device }) &&
!slices.ContainsFunc(hdddevs, func(u storageDevice) bool { return u.DevPath == m.Device }) {
if r := checkMount(m.Path, time.Second); r.Broken {
if m.Type == "cifs" {
if broken, _ := cifsBroken(&m); !broken {
continue
}
}
klog.Infof("broken mountpoint: %v, %v, %v", m.Path, m.Device, usbdevs)
klog.Infof("broken mountpoint: %v, %v, %v", m.Path, m.Device, r.Reason)
if err = umountAndRemovePath(ctx, m.Path); err != nil {
return err
@@ -608,3 +591,71 @@ func MountedPath(ctx context.Context) ([]mountedPath, error) {
return paths, nil
}
type result struct {
Mount string `json:"mount"`
Broken bool `json:"broken"`
Reason string `json:"reason,omitempty"`
Elapsed string `json:"elapsed,omitempty"`
}
func checkMount(mountPoint string, timeout time.Duration) result {
start := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
// Use /usr/bin/stat if exists, else fallback to ls -ld
statPath := "/usr/bin/stat"
if _, err := os.Stat(statPath); os.IsNotExist(err) {
statPath = "/bin/ls"
}
var cmd *exec.Cmd
// if stat exists, call stat <mountpoint>, else ls -ld <mountpoint>
if strings.HasSuffix(statPath, "stat") {
cmd = exec.CommandContext(ctx, statPath, mountPoint)
} else {
cmd = exec.CommandContext(ctx, statPath, "-ld", mountPoint)
}
out, err := cmd.CombinedOutput()
elapsed := time.Since(start)
res := result{
Mount: mountPoint,
Broken: false,
Reason: "",
Elapsed: elapsed.String(),
}
if ctx.Err() == context.DeadlineExceeded {
res.Broken = true
res.Reason = "timeout"
return res
}
if err != nil {
// check output or error for common broken indicators
outStr := strings.ToLower(string(out) + " " + err.Error())
switch {
case strings.Contains(outStr, "stale"):
res.Broken = true
res.Reason = "stale file handle"
case strings.Contains(outStr, "input/output error") || strings.Contains(outStr, "i/o error"):
res.Broken = true
res.Reason = "input/output error"
case strings.Contains(outStr, "transport endpoint is not connected"):
res.Broken = true
res.Reason = "transport endpoint not connected"
case strings.Contains(outStr, "permission denied"):
// permission denied doesn't mean broken; mark as not broken but note reason
res.Broken = false
res.Reason = "permission denied"
default:
// Unknown error - mark as broken (conservative), include text
res.Broken = true
res.Reason = "error: " + strings.TrimSpace(outStr)
}
}
return res
}

View File

@@ -44,7 +44,7 @@ func UmountUsbDevice(ctx context.Context, path string) error {
return nil
}
func UmountBrokenUsbMount(ctx context.Context, baseDir string) error {
func UmountBrokenMount(ctx context.Context, baseDir string) error {
klog.Warning("not implement")
return nil
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/beclab/Olares/daemon/pkg/nets"
"github.com/joho/godotenv"
corev1 "k8s.io/api/core/v1"
apixclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -582,3 +583,19 @@ func GetApplicationUrlAll(ctx context.Context) ([]string, error) {
return urls, nil
}
func GetApixClient() (apixclientset.Interface, error) {
config, err := ctrl.GetConfig()
if err != nil {
klog.Error("get k8s config error, ", err)
return nil, err
}
client, err := apixclientset.NewForConfig(config)
if err != nil {
klog.Error("get k8s apix client error, ", err)
return nil, err
}
return client, nil
}

View File

@@ -108,6 +108,10 @@ const side = {
text: "Back up mnemonics",
link: "/manual/larepass/back-up-mnemonics"
},
{
text: "Access Olares locally",
link: "/manual/get-started/local-access",
},
{
text: "What's next",
link: "/manual/get-started/next-steps",
@@ -128,7 +132,7 @@ const side = {
{text: "Manage integrations", link:"/manual/larepass/integrations"},
],
},
{text: "Manage VPN", link:"/manual/larepass/private-network"},
{text: "Use VPN", link:"/manual/larepass/private-network"},
{
text: "Manage device",
collapsed: true,
@@ -340,29 +344,6 @@ const side = {
},
{text: "Dashboard", link: "/manual/olares/resources-usage"},
{text: "Profile", link: "/manual/olares/profile"},
{
text: "Studio",
collapsed: true,
link: "/manual/olares/studio/",
items: [
{
text: "Deploy an app",
link: "/manual/olares/studio/deploy",
},
{
text: "Develop in a dev container",
link: "/manual/olares/studio/develop",
},
{
text: "Package and upload",
link: "/manual/olares/studio/package-upload",
},
{
text: "Add app assets",
link: "/manual/olares/studio/assets",
},
],
},
],
},
{
@@ -647,36 +628,29 @@ const side = {
],
},
{
text: "Develop Olares app",
text: "Develop Olares apps",
link: "/developer/develop/",
items: [
{
text: "Tutorial",
text: "Develop with Studio",
collapsed: true,
link: "/developer/develop/tutorial/",
items: [
{
text: "Learn Studio",
link: "/developer/develop/tutorial/studio",
text: "Deploy an app",
link: "/developer/develop/tutorial/deploy",
},
{
text: "Create your first app",
collapsed: true,
link: "/developer/develop/tutorial/note/",
items: [
{
text: "1. Create app",
link: "/developer/develop/tutorial/note/create",
},
{
text: "2. Develop backend",
link: "/developer/develop/tutorial/note/backend",
},
{
text: "3. Develop frontend",
link: "/developer/develop/tutorial/note/frontend",
},
],
text: "Develop in a dev container",
link: "/developer/develop/tutorial/develop",
},
{
text: "Package and upload",
link: "/developer/develop/tutorial/package-upload",
},
{
text: "Add app assets",
link: "/developer/develop/tutorial/assets",
},
],
},

View File

@@ -13,6 +13,7 @@ import mediumZoom from "medium-zoom";
import OSTabs from "./components/OStabs.vue";
import VersionSwitcher from "./components/VersionSwitcher.vue";
import _ from "lodash";
import { redirects } from './redirects';
const LANGUAGE_LOCAL_KEY = "language";
let isMenuChange = false;
@@ -20,14 +21,27 @@ let isMenuChange = false;
export default {
extends: DefaultTheme,
Layout,
enhanceApp({ app }: { app: App }) {
enhanceApp({ app, router }: { app: App; router: Router }) {
app.component("Tabs", Tabs);
app.component("LaunchCard", LaunchCard);
app.component("FilterableList", FilterableList);
app.component("OSTabs", OSTabs);
app.component("VersionSwitcher", VersionSwitcher);
router.onBeforeRouteChange = (to: string) => {
const path = to.replace(/\.html$/i, ''),
toPath = redirects[path];
if (toPath) {
setTimeout(() => { router.go(toPath); })
return false;
} else {
return true;
}
}
},
setup() {
const route = useRoute();
const router = useRouter();

View File

@@ -0,0 +1,12 @@
export const redirects = {
// Refactor studio
// index page
'/manual/olares/studio/': '/developer/develop/tutorial/',
'/manual/olares/studio/deploy': '/developer/develop/tutorial/deploy',
'/manual/olares/studio/develop': '/developer/develop/tutorial/develop',
'/manual/olares/studio/package-upload': '/developer/develop/tutorial/package-upload',
'/manual/olares/studio/assets': '/developer/develop/tutorial/assets',
'/developer/develop/tutorial/studio': '/developer/develop/tutorial',
'/zh/developer/develop/tutorial/studio': '/zh/developer/develop/tutorial',
}

View File

@@ -109,6 +109,10 @@ const side = {
text: "备份助记词",
link: "/zh/manual/larepass/back-up-mnemonics",
},
{
text: "内网访问 Olares",
link: "zh/manual/get-started/local-access",
},
{
text: "探索",
link: "/zh/manual/get-started/next-steps",
@@ -129,7 +133,7 @@ const side = {
{text: "管理集成", link:"/zh/manual/larepass/integrations"},
],
},
{text: "管理专用网络", link:"/zh/manual/larepass/private-network"},
{text: "使用专用网络", link:"/zh/manual/larepass/private-network"},
{
text: "管理设备",
collapsed: true,
@@ -616,32 +620,25 @@ const side = {
link: "/zh/developer/develop/",
items: [
{
text: "教程",
text: "使用 Studio 开发",
collapsed: true,
link: "/zh/developer/develop/tutorial/",
items: [
{
text: "了解 Studio",
link: "/zh/developer/develop/tutorial/studio",
text: "部署应用",
link: "/zh/developer/develop/tutorial/deploy",
},
{
text: "创建首个应用",
collapsed: true,
link: "/zh/developer/develop/tutorial/note/",
items: [
{
text: "1. 创建应用",
link: "/zh/developer/develop/tutorial/note/create",
},
{
text: "2. 开发后端",
link: "/zh/developer/develop/tutorial/note/backend",
},
{
text: "3. 开发前端",
link: "/zh/developer/develop/tutorial/note/frontend",
},
],
text: "使用开发容器",
link: "/zh/developer/develop/tutorial/develop",
},
{
text: "打包与上传",
link: "/zh/developer/develop/tutorial/package-upload",
},
{
text: "添加应用素材",
link: "/zh/developer/develop/tutorial/assets",
},
],
},

View File

@@ -1,4 +1,5 @@
---
outline: [2, 3]
description: Olares network architecture principles, covering application entrance types, local access mechanisms, endpoint configurations and internal network security policies.
---
# Network
@@ -9,29 +10,21 @@ Olares provides users with a barrier-free but secure and versatile network solut
Each Olares application can have one or more entrances that serve as access points. There are three types of entrances:
- **Public entrance**
### Public entrance
- Provides external services such as blogs, social media, etc.
- Accessible without authentication
- Basic security through Cloudflare
- Provides external services such as blogs, social media, etc.
- Accessible without authentication
- Basic security through Cloudflare
- **Private entrance**
### Private entrance
- Provides services exclusively for individual users, families, or teams
- Suitable for readers, entertainment, productivity tools, desktop applications, etc.
- Requires [authentication](account.md#multi-factor-authentication-mfa) for access
- Provides services exclusively for individual users, families, or teams
- Suitable for readers, entertainment, productivity tools, desktop applications, etc.
- Requires [authentication](account.md#multi-factor-authentication-mfa) for access
- **Internal entrance**
- Functions similarly to private entrance
- No authentication required when accessing applications through LarePass VPN
## Acccess to private entrances via VPN
Simply enable [LarePass VPN](/manual/larepass/private-network.md) on your device to securely and quickly access your private applications via their dedicated URLs (e.g., `https://vault.alice123.olares.com`).
::: tip Note
If LarePass VPN is not enabled, requests to your private entrances will be routed through your reverse proxy tunnel to Olares, which may cause network latency and incur charges.
:::
### Internal entrance
- Functions similarly to private entrance
- No authentication required when accessing applications through LarePass VPN
## Endpoints

View File

@@ -1,15 +1,30 @@
# Develop Olares application
# Develop Olares applications
Developing applications on Olares is not much different from regular website development. Once you learn a few basic Olares concepts, you can start creating applications on his platform.
Developing applications on Olares leverages standard web technologies and containerization. If you are familiar with building web applications or Docker containers, you already have the skills needed to build for Olares.
- [Core Concepts of Olares](../concepts/index.md)
- [Understanding the Format of Olares Application Chart](./package/chart.md)
- [The structure of the Olares Application Chart](./package/chart.md)
- [Configuration guide and field descriptions of `OlaresManifest.yaml`](./package/manifest.md)
- [Extensions field to Helm in Olares](./package/extension.md)
This guide takes you through the complete lifecycle of an Olares application, from your first line of code in Studio to publishing on the Market.
- [Exploring Our Tutorials](./tutorial/)
- [Learn about Studio, an Olares Development Tool](./tutorial/studio)
- [Creating your first application](./tutorial/note/)
- [Exploring Advanced Concepts](./advanced/)
- [Submitting Applications to the Olares Market](./submit/)
## Before you begin
Before getting started, it's helpful to review some concepts:
- [Application](../concepts/application.md)
- [Network](../concepts/network.md)
## Step 1: Develop with Studio
Olares Studio is a development platform that accelerates your build cycle. It provides a pre-configured workspace to build, debug, and test your applications directly on the platform.
* **[Deploy an app](./tutorial/deploy.md)**: Learn how to quickly deploy an app from an existing Docker image, configure it, and test it in Studio.
* **[Develop in a dev container](./tutorial/develop.md)**: Spin up a remote development environment (Dev Container) and connect it to VS Code for a seamless coding experience.
* **[Package and upload](./tutorial/package-upload.md)**: Convert your running application into an Olares-compatible package and upload it for testing.
* **[Add app assets](./tutorial/assets.md)**: Configure icons, screenshots, and descriptions to make your application store-ready.
## Step 2: Package your application
To publish your application to the Olares Market, you must structure it according to the Olares Application Chart (OAC) specification. This format extends Helm Charts to support Olares-specific features like permission management and sandboxing.
* **[Understand the Olares Application Chart](./package/chart.md)**: Understand the file structure and requirements of an application package.
* **[Understand `OlaresManifest.yaml`](./package/manifest.md)**: A comprehensive guide to the `OlaresManifest.yaml` file, which defines your app's metadata, permissions, and system integration points.
* **[Understand Helm extensions](./package/extension.md)**: Learn about the custom fields and capabilities Olares adds to standard Helm deployments.
## Step 3: Submit your application
Once your application is built and packaged, the final step is to share it with the Olares community.
* **[Submit to Market](./submit/index.md)**: Learn how to submit your application to the Olares Market for review and distribution.

View File

@@ -17,8 +17,8 @@ outline: [2, 3]
### 1. Develop and test your application
Before submitting an application, please ensure that it has been thoroughly tested on your Olares.
- Use DevBox's dev-container to test and debug your application in a real online environment. [Learn more about DevBox](../tutorial/studio).
- Use the [custom installation](/manual/olares/market.md#install-custom-applications) in the Market app for user testing.
- Use Studio's dev-container to test and debug your application in a real online environment. [Learn more about Studio](../tutorial/).
- Use the [custom installation](../tutorial/package-upload.md) in the Market app for user testing.
### 2. Submit an application
The submission of the application needs to be completed through a **Pull Request**. Here's how:

View File

@@ -6,7 +6,7 @@ description: Deploy a single-container Docker app to Olares using Studio.
This guide explains how to deploy a single-container Docker app to Olares using Studio.
:::info For single-container apps
This method supports apps that run from a single container image. For multi-container apps (for example, a web service plus a separate database), use the workflow in the [developer documentation](../../../developer/develop/tutorial/index.md) instead.
This method supports apps that run from a single container image.
:::
:::tip Recommended for testing
Studio-created deployments are best suited for development, testing, or temporary use. Upgrades and long-term data persistence can be limited compared to installing a packaged app from the Market. For production use, consider [packaging and uploading the app](package-upload.md) and installing it via the Market.
@@ -44,7 +44,6 @@ services:
- "8282:80/tcp"
environment:
TZ: 'America/Toronto'
# Volumes store your data between container upgrades
volumes:
- './db:/var/www/html/db'
- './logos:/var/www/html/images/uploads/logos'
@@ -67,7 +66,7 @@ These fields define the app's core components. You can find this information as
:::
3. For **Instance Specifications**, enter the minimum CPU and memory requirements. For example:
- **CPU**: 2 core
- **Memory**: 1 G
- **Memory**: 1 Gi
![Deploy Wallos](/images/manual/olares/studio-deploy-wallos.png#bordered)
### Add environment variables
@@ -83,7 +82,7 @@ Environment variables are used to pass configuration settings to your app. In th
Volumes connect storage on your Olares device to a path inside the app's container, which is essential for saving data permanently. These are defined using the `-v` flag or in the `volumes:` section.
:::info Host path options
The host path is where Olares stores the data, and the mount path is the path inside the container. Olares provides three managed host path prefixes:
The host path is where Olares stores the data, and the mount path is the path inside the container. Studio provides three managed host path prefixes:
- `/app/data`: App data directory. Data can be accessed across nodes and is not deleted when the app is uninstalled. Appears under `/Data/studio` in Files.
- `/app/cache`: App cache directory. Data is stored in the node's local disk and is deleted when the app is uninstalled. Appears under `/Cache/<device-name>/studio` in Files.
@@ -96,15 +95,23 @@ The host path is where Olares stores the data, and the mount path is the path in
This app requires two volumes. You will add them one by one.
1. Add the database volume. This data is for high-frequency I/O and does not need to be saved permanently. Map it to `/app/cache` so it will be automatically deleted when the app is uninstalled.
1. Click **Add** next to **Storage Volume**.
2. For **Host path**, select `/app/cache`, then enter `/db`.
3. For **Mount path**, enter `/var/www/html/db`.
4. Click **Submit**.
2. Add the logo volume. This is user-uploaded data that should be persistent and reusable, even if the app is reinstalled. Map it to `/app/data`.
1. Click **Add** next to **Storage Volume**.
2. For **Host path**, select `/app/data`, then enter `/logos`.
3. For **Mount path**, enter `/var/www/html/images/uploads/logos`
4. Click **Submit**.
a. Click **Add** next to **Storage Volume**.
b. For **Host path**, select `/app/cache`, then enter `/db`.
c. For **Mount path**, enter `/var/www/html/db`.
d. Click **Submit**.
2. Add the logo volume. This is user-uploaded data that should be persistent and reusable, even if the app is reinstalled. Map it to `/app/data`.
a. Click **Add** next to **Storage Volume**.
b. For **Host path**, select `/app/data`, then enter `/logos`.
c. For **Mount path**, enter `/var/www/html/images/uploads/logos`.
d. Click **Submit**.
![Add volumes](/images/manual/olares/studio-add-storage-volumes.png#bordered)
You can check Files later to verify the mounted paths.
@@ -118,37 +125,36 @@ If your app needs Postgres or Redis, enable it under **Instance Specifications**
![Enable databases](/images/manual/olares/studio-enable-databases.png#bordered)
When enabled, Studio provides dynamic variables. You must use these variables in the **Environment Variables** section for your app to connect to the database.
- **Postgres variables:**
- **Postgres variables**
| Variables | Description |
|--------------|-----------------------|
| $(PG_USER) | PostgreSQL username |
| $(PG_DBNAME) | Database name |
| $(PG_PASS) | Postgres Password |
| $(PG_HOST) | Postgres service host |
| $(PG_PORT) | Postgres service port |
| Variables | Description |
|----------------|-----------------------|
| `$(PG_USER)` | PostgreSQL username |
| `$(PG_DBNAME)` | Database name |
| `$(PG_PASS)` | Postgres Password |
| `$(PG_HOST)` | Postgres service host |
| `$(PG_PORT)` | Postgres service port |
- **Redis variables:**
- **Redis variables**
| Variables | Description |
|---------------|--------------------|
| $(REDIS_HOST) | Redis service host |
| $(REDIS_PORT) | Redis service port |
| $(REDIS_USER) | Redis username |
| $(REDIS_PASS) | Redis password |
| Variables | Description |
|-----------------|--------------------|
| `$(REDIS_HOST)` | Redis service host |
| `$(REDIS_PORT)` | Redis service port |
| `$(REDIS_USER)` | Redis username |
| `$(REDIS_PASS)` | Redis password |
### Generate the app project
1. Once all your configurations are set, click **Create**. This generates the app's project files.
2. After creation, Studio generates the package files for your app, and then automatically deploys the app. You can check the status in the bottom bar.
3. When the app is successfully deployed, click **Preview** in the top-right corner to launch it.
![Preveiw wallos](/images/manual/olares/studio-preview-wallos.png#bordered)
![Preview Wallos](/images/manual/olares/studio-preview-wallos.png#bordered)
## Review the package files and test the app
Apps deployed from Studio include a `-dev` suffix in the title to distinguish them from Market installations.
![Check deployed app](/images/manual/olares/studio-app-with-dev-suffix.png#bordered)
You can click on files like `OlaresManifest.yaml` to review and make changes. For example, to change the app's display name and logo.
You can click on files like `OlaresManifest.yaml` to review and make changes. For example, to change the app's display name and logo:
1. Click **<span class="material-symbols-outlined">box_edit</span>Edit** in the top-right to open the editor.
2. Click `OlaresManifest.yaml` to view the content.
@@ -164,7 +170,6 @@ You can click on files like `OlaresManifest.yaml` to review and make changes. Fo
:::
![Change app icon](/images/manual/olares/studio-change-app-icon1.png#bordered)
## Uninstall or delete the app
If you no longer need the app, you can remove it.
1. Click <span class="material-symbols-outlined">more_vert</span> in the top-right corner.
@@ -175,12 +180,11 @@ If you no longer need the app, you can remove it.
## Troubleshoot a deployment
### Cannot install the app
If installation fails, review the error at the bottom of the page and click **View** to expand details.
![Check app status](/images/manual/olares/studio-check-app-status.png#bordered)
If installation fails, review the error at the bottom of the page and click **View** to check details.
### Run into issues when the app is running
Once running, you can manage the app from its deployment details page in Studio. The interface of this page is similar to Control Hub. If details don't appear, refresh the page.
You can:
- Use the **Stop** and **Restart** controls to retry. This action can often resolve runtime issues like a frozen process.
- Check events or logs to investigate runtime errors. See [Export container logs for troubleshooting](../controlhub/manage-container.md#export-container-logs-for-troubleshooting) for details.
- Use the **Stop** or **Restart** controls to retry. This action can often resolve runtime issues like a frozen process.
- Check events or logs to investigate runtime errors. See [Export container logs for troubleshooting](../../../manual/olares/controlhub/manage-container.md#export-container-logs-for-troubleshooting) for details.
![App deployment details](/images/manual/olares/studio-app-deployment-details.png#bordered)

View File

@@ -5,10 +5,7 @@ description: Learn how to use Studio to set up a dev container, access it via VS
# Develop in a dev container
Olares Studio allows you to spin up a pre-configured dev container to write and debug code (such as Node.js scripts or CUDA programs) without managing local infrastructure. This provides an isolated environment identical to the production runtime.
The following guide shows the setup workflow using a Node.js project as an example.
:::info
This workflow is optimized for iterative coding and testing. If you intend to publish the application to the Olares Market, you must create your own image and follow the [developer documentation](../../../developer/develop/submit/index.md) for final configuration.
:::
The following guide shows the development and setup workflow using a Node.js project as an example.
## Prerequisite
- Olares version 1.12.2 or later.
@@ -56,7 +53,7 @@ If you prefer your local settings and extensions, you can tunnel into the contai
code tunnel
```
5. Follow the terminal prompts to authenticate using a Microsoft or GitHub account via the provided URL.
6. Assign a name to the tunnel when prompted (e.g., `myapp-demo`). This will output a vscode.dev URL tied to this remote workspace.
6. Assign a name to the tunnel when prompted (e.g., `myapp-demo`). This will output a `vscode.dev` URL tied to this remote workspace.
![Create a secure tunnel](/images/manual/olares/studio-create-a-secure-tunnel.png#bordered)
7. Open VS Code on your local machine, click the **><** icon in the bottom-left, and select **Tunnel**.
@@ -183,6 +180,9 @@ You can follow the same steps to modify `OlaresManifest.yaml` and `deployment.ya
- name: "80"
port: 80
targetPort: 80
- name: myweb-dev-8080
port: 8080
targetPort: 8080
# Add the following
- name: myweb-dev-8081 # Must match entrance name
port: 8081
@@ -195,10 +195,10 @@ You can follow the same steps to modify `OlaresManifest.yaml` and `deployment.ya
4. Click **Apply** to redeploy the container.
You can verify the active ports in **Services** > **Ports**.
Once deployed, go to **Services** > **Ports**. You can see your new port listed here.
![Verify active ports](/images/manual/olares/studio-verify-active-ports.png#bordered)
### Verify the new port
### Test the connection
1. Update `index.js` to listen on the new port:
```js
const express = require('express');

View File

@@ -1,15 +1,26 @@
# Tutorial
---
description: Get started with Studio to deploy Docker-based apps, develop new apps, package and upload locally, and manage assets on your Olares device.
---
# Deploy and develop apps in Olares
Welcome to the Olares developer guides. These detailed tutorials offer a step-by-step guide on building an Olares Application from scratch.
Studio provides a real Olares environment for building, porting, and testing apps when cloud features and the sandbox system are hard to simulate locally. With Studio you can:
- Create a new Olares app in an online development container.
- Port an existing app, adjust its configurations, and test the installation flow.
- Package your app into a chart and download it when your app is ready.
To get started, you can learn some basic concepts of Olares, such as:
- [Olares architectural components](../../concepts/architecture.md)
- [Olares Application Chart](../../develop/package/chart.md)
- [Olares Extension on Helm](../package/extension.md)
## Access Studio
You must manually install Studio:
1. Open **Market**, and search for "Studio".
![Studio](/images/manual/olares/studio.png#bordered)
These fundamentals will help you grasp our development process more effectively.
2. Click **Get**, then **Install**, and wait for installation to complete.
You can also [learn about DevBox](studio.md), a built-in app that Olares provides for developers to build Olares applications.
After installation, launch Studio from Market or from Launchpad.
If you're brand new to Olares development and want to jump straight into coding, start with the [**Create your first Olares app**](./note/index.md). This tutorial will step you through the process of building a small note application.
## Understand the Studio UI
The sidebar and **Home** page organize your main tasks in Studio:
- **Home**: A welcome page with shortcuts to common actions and documentation.
- **Applications**: A list of apps you have created and deployed with Studio.
- **Start**: You can start deploying or developing apps, or uploading an app from a local chart file.
![Understand Studio user interface](/images/manual/olares/studio-ui.png#bordered)

View File

@@ -8,7 +8,7 @@ Apps created in Studio are ideal for development and testing. For stable, long-t
## Download the App package from Studio
After confirming that your app works as expected, you can download its complete installation package.
After confirming that your app works as expected, you can download its complete installation package:
1. Open your app project in **Studio**.
2. Click <span class="material-symbols-outlined">more_vert</span> in the top-right corner.
@@ -24,6 +24,4 @@ After confirming that your app works as expected, you can download its complete
Once finished, you can click **Open** to launch it.
All custom-installed apps will appear under the **My Olares** > **Upload** tab.
All custom-installed apps will appear under the **My Olares** > **Upload** tab.

View File

@@ -1,13 +0,0 @@
# Learn about Studio
At Olares, we provide a development tool called Studio. It helps developers create applications for **Olares**.
- Why is Studio necessary for developers?
Olares has many cloud-based features that are difficult to simulate in a standalone development environment. Furthermore, the unique sandbox system of **Olares** requires a real system environment for end-to-end testing. To simplify app simulation for developers and minimize system integration efforts during development, we provide the **Studio**. **Studio** is a quick, automatic toolset for creating app sandboxes.
- What features does Studio have?
- In Studio, you can build an app and generate a corresponding Olares Application Configuration* This deployment files can be modified, allowing you to port an existing app and deploy it to the Olares. During the modification process, you can continually attempt installation and resolve any issues that arise. Once the app passes your tests, you can download your Application Chart and submit it to the [Olares Market Repository](https://github.com/beclab/apps).
- In addition to porting existing apps, you can also create a native Olares application in Studio. Studio provides an online development container where coders can work in a real environment, utilize other system interfaces, database clusters, and more.

View File

@@ -0,0 +1,235 @@
---
outline: [2,3]
description: Learn how to access Olares apps and services directly via your local network (LAN) for maximum speed, privacy, and offline reliability.
---
# Access Olares services locally
Typically, you access Olares services through a browser using a URL like `https://desktop.<username>.olares.com`. This way, you can reach your services from any device at any time.
However, accessing your devices directly over your Local Area Network (LAN) provides several advantages:
- **Maximum performance**: Transfer files at full speed without the latency and potential bottlenecks of the internet.
- **Enhanced privacy**: Keep your traffic contained within your home network for added security.
- **Offline independence**: Access your data and apps even when your internet service is unavailable.
This guide covers several methods to establish a local connection:
- [Enable LarePass VPN (Recommended)](#method-1-enable-larepass-vpn)<br/>This method is the easiest solution, as it automatically establishes the fastest connection without manual configuration.
- [Use `.local` domain](#method-2-use-local-domain)<br/>This method requires no installation, though you must use specific URL formats based on your operating system.
- [Configure local DNS (Advanced)](#method-3-configure-local-dns)<br/>This method allows standard URLs to work locally by updating DNS settings on your router or individual computer.
- [Modify host files (Fallback)](#method-4-modify-host-files)<br/>This method manually maps standard URLs to your local IP on a single computer, ensuring access even without an internet connection.
## Method 1: Enable LarePass VPN
The most robust way to connect, whether you are sitting next to the device or traveling, is using the LarePass VPN. It intelligently detects when you are on the same network and switches to a direct **Intranet** mode for maximum speed.
:::tip Always enable VPN for remote access
Keep LarePass VPN enabled. It automatically prioritizes the fastest available route to ensure you always get the best speed possible without manual switching.
:::
:::info iOS and macOS setup
On iOS or macOS, you may be prompted to add a VPN Configuration to your system settings the first time you enable the feature. Allow this to complete the setup.
:::
Enable the LarePass VPN directly on the device you are currently using to access Olares.
<tabs>
<template #On-LarePass-mobile-client>
1. Open the LarePass app, and go to **Settings**.
2. In the **My Olares** card, toggle on the VPN switch.
![Enable LarePass VPN on mobile](/images/manual/get-started/larepass-vpn-mobile.png#bordered)
</template>
<template #On-LarePass-desktop-client>
1. Open the LarePass app, and click your avatar in the top-left corner to open the user menu.
2. Toggle on the switch for **VPN connection**.
![Enable LarePass VPN on desktop](/images/manual/get-started/larepass-vpn-desktop.png#bordered)
</template>
</tabs>
Once enabled, check the status indicator in LarePass to verify the connection type:
| Status | Description |
|:-------------|:---------------------------------------------------------|
| **Intranet** | Direct connection via your local LAN IP. Fastest speeds. |
| **P2P** | Direct encrypted tunnel between devices. High speed. |
| **DERP** | Routed via a secure relay server. Used as a fallback. |
## Method 2: Use `.local` domain
If you prefer not to use a VPN, you can access services using the `.local` domain. There are two domain formats available depending on your compatibility needs.
### Single-level domain (All operating systems)
:::warning Supported for community apps only
Olares system apps such as Desktop and Files do not support this URL format and will not load correctly.
:::
This format uses a single-level domain by connecting the entrance ID and the username with hyphens (`-`).
- **Default URL**:
```plain
https://<entrance_id>.<username>.olares.com
```
- **Local-access URL**:
```plain
http://<entrance_id>-<username>-olares.local
```
### Multi-level domain (macOS and iOS only)
Apple devices support local service discovery via [Bonjour](https://developer.apple.com/bonjour/) (zeroconfiguration networking), which can resolve multilabel domains under `.local` on macOS and iOS. This allows a local URL format that mirrors the remote address.
- **Default URL**:
```plain
https://<entrance_id>.<username>.olares.com
```
- **Local-access URL**:
```plain
http://<entrance_id>.<username>.olares.local
```
![Multi-level local domain](/images/manual/get-started/multilevel-local-domain-mac.png#bordered)
## Method 3: Configure local DNS
For a seamless experience where standard URLs resolve to your local IP address automatically, you can configure your network DNS. This configuration ensures consistent access across all devices on the network without requiring individual client setup.
### Find the internal IP for Olares device
To configure DNS, first you need to find the internal IP for your Olares device.
<tabs>
<template #Check-via-the-LarePass-mobile-client>
If your phone and Olares device are on the same network:
1. Open the LarePass app, and go to **Settings** > **System** to navigate to the **Olares management** page
![Tap the System card](/images/manual/get-started/larepass-system.png#bordered)
2. Tap on the device card.
![Tap the device card](/images/manual/get-started/larepass-device-card.png#bordered)
3. Scroll down to the **Network** section. You can find the **Intranet IP** there.
![Find Network section](/images/manual/get-started/larepass-network.png#bordered)
</template>
<template #Check-via-Olares-Terminal>
Control Hub provides a built-in terminal that allows you to run system commands directly from the browser, without needing an external SSH client.
1. Open the Control Hub app, and under **Terminal**, select **Olares**in the left navigation bar.
![Find internal IP from Control Hub](/images/manual/get-started/find-internal-ip-from-controlhub.png#bordered)
2. Type `ifconfig` in the terminal and press **Enter**.
3. Look for your active connection, typically named `enp3s0` (wired) or `wlo1` (wireless). The IP address follows `inet`.
Example output:
```bash
enp3s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.50.116 netmask 255.255.255.0 broadcast 192.168.50.255
inet6 fe80::4194:4045:c35e:7b32 prefixlen 64 scopeid 0x20<link>
ether d8:43:ae:54:ce:fc txqueuelen 1000 (Ethernet)
RX packets 80655321 bytes 71481515308 (71.4 GB)
RX errors 0 dropped 136 overruns 0 frame 0
TX packets 51867817 bytes 15924740708 (15.9 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
```
In this example, `192.168.50.116` is the internal IP.
</template>
</tabs>
### Configure DNS
With the internal IP address identified, you must now configure your DNS settings to route traffic correctly. You can apply this configuration to a single computer for individual access, or update your router to enable seamless local resolution for all devices on your network.
<tabs>
<template #Configure-for-local-device>
Update the DNS settings on your specific computer. For example, on macOS:
1. Open Apple menu and go to **System Settings**.
2. Select **Wi-Fi**, then click **Details** on your connected network.
3. Select **DNS** and update the server list:
a. Click the **+** button under **DNS Servers** to add your Olares device's internal IP (e.g., `192.168.x.x`).
b. Ensure the Olares IP is listed at the top. Add your original DNS (or `1.1.1.1`) below it as a fallback. <br/>This ensures that if your Olares device shuts down, the router will automatically switch to the secondary DNS, keeping your internet connection alive.
4. Click **OK** to save changes.
</template>
<template #Configure-for-all-devices>
Update the DNS on your router to apply changes to every device in your network.
1. Log in to your router's admin panel.
2. Navigate to **DHCP / DNS Settings**.
3. Set **Primary DNS** to your Olares device's internal IP (e.g., `192.168.x.x`).
4. Set **Secondary DNS** to your current Primary DNS (or a public provider like `1.1.1.1`). <br/>This ensures that if your Olares device shuts down, the router will automatically switch to the secondary DNS, keeping your internet connection alive.
5. Save and reconnect your devices to refresh the DNS cache.
</template>
</tabs>
Once configured, you can access Olares using both your standard public address and your local address.
:::tip
You can install AdGuard Home from the Olares Market to monitor traffic and manage DNS mappings graphically.
:::
## Method 4: Modify host files
If you cannot change router settings and need immediate offline access on a specific computer, you can manually map the domains in your hosts file.
1. Locate your hosts file:
- **Windows:** `C:\Windows\System32\drivers\etc\hosts`
- **macOS/Linux:** `/etc/hosts`
2. Open the file with a text editor, which requires Administrator privileges.
3. Add the mapping lines:
```plain
# Replace with the actual internal IP and the username
# Olares apps
192.168.31.208 desktop.<username>.olares.com
192.168.31.208 auth.<username>.olares.com
192.168.31.208 files.<username>.olares.com
192.168.31.208 market.<username>.olares.com
192.168.31.208 settings.<username>.olares.com
192.168.31.208 dashboard.<username>.olares.com
192.168.31.208 control-hub.<username>.olares.com
192.168.31.208 profile.<username>.olares.com
192.168.31.208 vault.<username>.olares.com
# Add other community apps as needed
192.168.31.208 <entrance_id>.<username>.olares.com
```
4. Save the file to apply changes and ensure local access without an internet connection.
Verify the changes by checking the URL for quick loading or using the terminal:
```bash
ping desktop.<username>.olares.com
```
If the IP address starts with `192.168`, it indicates successful configuration.
## Learn more
- [Access Olares services remotely via LarePass VPN](../../manual/larepass/private-network.md): Understand how to use LarePass VPN.
- [Network](../../developer/concepts/network.md): Learn about the different entry points in Olares.
## FAQs
### Why doesn't LarePass VPN work on my Mac anymore?
If you successfully enabled the VPN previously, but it has stopped working, you might need to reset the system extension.
:::info
Depending on your macOS version, the UI might look slightly different.
:::
1. Open **System Settings**, search for "Extension", and select **Login Items & Extensions**.
2. Scroll to the **Network Extensions** section and click the info icon (ⓘ) to view loaded extensions.
3. Find LarePass, click the three dots (...), and select **Delete Extension**.
4. Confirm the uninstallation.
5. Restart your Mac and re-enable the VPN in the LarePass desktop client.
### Why I cannot enable LarePass VPN on Windows?
Third-party antivirus software might mistakenly flag the LarePass desktop client as suspicious, preventing it from launching the VPN service.
If prompted by your antivirus when opening LarePass for the first time, allow the application to continue.
If the VPN still fails to enable:
1. Open your security software and check if LarePass was blocked.
2. Add the main LarePass executable to the allowlist** or exclusions of your antivirus.
3. Restart LarePass and enable the VPN.
### Why the `.local` domain does not work in Chrome (macOS)?
Chrome may fail to access local URLs if macOS blocks local network permissions.
To enable access:
1. Open Apple menu and go to **System Settings**.
2. Go to **Privacy & Security** > **Local Network**.
3. Find Google Chrome and Google Chrome Helper in the list and enable the toggles.
![Enable local network](/images/manual/larepass/mac-chrome-local-access.png#bordered){width=400}
4. Restart Chrome and try accessing the local URL again.
### Why does the application fail to load in an iFrame when using a `.local` domain on Chrome (macOS)?
Chrome might default to HTTPS when using local domains, and you might see a "connection not secure" warning.
![Incorrect local address](/images/manual/get-started/incorrect-local-address.png#bordered)
To address this, explicitly add the HTTP protocol (`http://`) to the beginning of the URL. This tells Chrome it's a local, non-encrypted connection, which is expected on your home network.

View File

@@ -15,7 +15,6 @@ Keep your mnemonic phrase safe and secret, and never share it with anyone. It is
When exporting or backing up your mnemonic phrase for the first time, you may be prompted to set a local password for LarePass. This password is only used to unlock LarePass services on the current device.
After setting up, you can choose to enable biometric unlock for more secure and convenient access using face recognition or fingerprint.
![Set up local password](/images/manual/get-started/set-up-local-password.png)
:::info
@@ -52,4 +51,4 @@ To prevent this, we strongly recommend taking these precautions:
* **Multi-device backup**: Use LarePass's Vault to encrypt and save your mnemonic phrase on multiple devices. You will lose your mnemonic phrase only if all these devices are lost.
### I've activated Olares, why do I get a password error when trying to view my mnemonic phrase in LarePass?
If you encounter a password error, it may be because you haven't set a local password. Open the LarePass app, go to **Settings** > **LarePass settings** > **Security**, and set a local password. Then try the backup process again.
If you encounter a password error, it may be because you haven't set a local password. Open the LarePass app, go to **Settings** > **LarePass settings** > **Security**, and set a local password. Then try the backup process again.

View File

@@ -1,77 +1,38 @@
---
outline: [2, 3]
description: Learn how to securely access your Olares from anywhere. This guide explains public vs. private entrances, when to use LarePass VPN, how to enable VPN on mobile and desktop.
description: Learn how to securely access your Olares from anywhere.
---
# Access Olares services remotely via LarePass VPN
Your Olares device hosts critical applications intended for personal or internal use, such as Vault and Ollama. To ensure security, these applications are accessed via [private or internal entrances](../../developer/concepts/network.md#private-entrance).
# Access Olares anywhere
To ensure the best connection to these apps, it's recommended to enable LarePass VPN. Once enabled, LarePass uses Tailscale to establish a secure network and automatically selects the fastest route based on location:
This guide explains **how to reach your Olares from anywhere**. You will learn:
- **At home**: The app connects directly via the local network for maximum speed.
- **Remote**: The app creates a direct, encrypted P2P tunnel to the device.
1) The access paths for public vs. private entrances.
2) How to enable LarePass VPN on your mobile and desktop.
3) Interpret connection status and know when to troubleshoot.
## How access works in Olares
In Olares, you access each app or service via its own URL (`https://app.olares-id.olares.com`, for example, `https://desktop.nicholas.olares.com/`). Depending on who should reach it, there are two entrance types.
### Public entrance
* Accessible to anyone on the internet without authentication. For example, a public blog hosted on WordPress.
* Traffic is securely routed from the internet to Olares via Cloudflare Tunnel or FRP.
### Private entrance
Application entrances intended only for you, such as Desktop, Vault, and the management console of WordPress. Depending on where you are, there are two scenarios when accessing private entrances:
- **Remote access** (Outside your local network)
- **With LarePass VPN (Recommended):** Traffic is routed directly and securely through the VPN (Tailscale), no matter where you are.
- **Without LarePass VPN:** Traffic is routed through the same internet tunnel as public access (Cloudflare/FRP).
- **Local access** (On the same network)
Use the local URL (`http://app.yourname.olares.local`) for a direct, local connection that bypasses the VPN and internet tunnels.
:::tip For macOS users
Chrome may fail to access local URLs if macOS blocks local network permissions.
To enable access:
1. Open Apple menu and go to **System Settings**.
2. Go to **Privacy & Security** > **Local Network**.
3. Find Google Chrome and Google Chrome Helper in the list and enable the toggles.
![Enable local network](/public/images/manual/larepass/mac-chrome-local-access.png#bordered){width=400}
Restart Chrome and try accessing the local URL again.
:::
:::info For Windows users
Currently, local access via `.local` domains is not supported on Windows.
:::
:::warning Always enable VPN for remote access
For the best experience with private apps when you're away from your network, enable **LarePass VPN**. It keeps your connection to Olares encrypted, direct, and fast.
:::
If the VPN is disabled, traffic routes through standard public internet tunnels using Cloudflare or FRP.
## Enable VPN on LarePass
:::tip
For different LarePass download options, visit [the official page](https://www.olares.com/larepass).
:::info iOS and macOS setup
On iOS or macOS, you may be prompted to add a VPN Configuration to your system settings the first time you enable the feature. Allow this to complete the setup.
:::
![VPN](/images/manual/larepass/vpn.jpg)
<tabs>
<template #On-LarePass-mobile-client>
### On LarePass mobile client
1. Open LarePass, and go to **Settings**.
1. Open the LarePass app, and go to **Settings**.
2. In the **My Olares** card, toggle on the VPN switch.
### On LarePass desktop client
1. Open LarePass, click on the avatar area in the top left corner of the main interface.
2. Toggle on the switch for **VPN connection** in the pop-up panel.
![Enable LarePass VPN on mobile](/images/manual/get-started/larepass-vpn-mobile.png#bordered)
</template>
<template #On-LarePass-desktop-client>
Devices with activated VPN will use the VPN connection to access Olares, whether through the LarePass client or a browser.
1. Open the LarePass app, and click your avatar in the top-left corner to open the user menu.
2. Toggle on the switch for **VPN connection**.
:::info
iOS or macOS versions of LarePass will require adding a VPN configuration file to the system when turning on the VPN. Follow the prompts to complete the setup.
:::
![Enable LarePass VPN on desktop](/images/manual/get-started/larepass-vpn-desktop.png#bordered)
</template>
</tabs>
## Understand connection status
LarePass displays the connection status between your device and Olares, helping you understand or diagnose your current network connection.

View File

@@ -1,49 +0,0 @@
---
description: Get started with Studio to deploy Docker-based apps, develop new apps, package and upload locally, and manage assets on your Olares device.
---
# Deploy and develop apps in Olares
Studio provides a real Olares environment for building, porting, and testing apps when cloud features and the sandbox system are hard to simulate locally. With Studio you can:
- Create a new Olares app in an online development container.
- Port an existing app, adjust its configurations, and test the installation flow.
-Package your app into a chart and download it when your app is ready.
## Access Studio
Studio is available in Olares Market and must be installed manually.
1. Open **Market**, and search for "Studio".
![Studio](/images/manual/olares/studio.png#bordered)
2. Click **Get**, then **Install**, and wait for installation to complete.
After installation, launch Studio from Market or from Launchpad.
## Understand the Studio UI
The sidebar and **Home** page organize your main tasks in Studio:
- **Home**: A welcome page with shortcuts to common actions and documentation.
- **Applications**: A list of apps you have created and deployed with Studio.
- **Start**: You can start deploying or developing apps, or uploading an app from a local chart file.
![Understand Studio user interface](/images/manual/olares/studio-ui.png#bordered)
---
<div>
<h4><a href="./deploy">Deploy an app from Docker image</a></h4>
Deploy an app from an existing Docker image, configure it, and test it in Studio.
</div>
<div>
<h4><a href="./develop">Develop in a dev container</a></h4>
Build and debug a new app using the Studio development environment.
</div>
<div>
<h4><a href="./package-upload">Package and upload the app to Market</a></h4>
Download an installable package and upload it to Market for local use.
</div>
<div>
<h4><a href="./assets">Add app assets</a></h4>
Use Olares image hosting to add and manage creative assets for your app.
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 KiB

Some files were not shown because too many files have changed in this diff Show More