Compare commits

...

7 Commits

Author SHA1 Message Date
dkeven
063a82b2b5 fix(cli): only (un)label current node in multi-node cluster 2025-12-17 16:57:19 +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
33 changed files with 217 additions and 461 deletions

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.23
image: beclab/system-frontend:v1.6.24
imagePullPolicy: IfNotPresent
command:
- /bin/sh

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

@@ -169,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"

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

@@ -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

@@ -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

@@ -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")

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

@@ -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

@@ -170,7 +170,7 @@ spec:
priorityClassName: "system-cluster-critical"
containers:
- name: app-service
image: beclab/app-service:0.4.62
image: beclab/app-service:0.4.63
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 0
@@ -393,7 +393,7 @@ spec:
priorityClassName: "system-cluster-critical"
containers:
- name: image-service
image: beclab/image-service:0.4.48
image: beclab/image-service:0.4.63
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 0

View File

@@ -174,12 +174,6 @@ func (p *DownloadingApp) exec(ctx context.Context) error {
return err
}
values["sysVersion"] = terminus.Spec.Version
refs, err := p.getRefsForImageManager(appConfig, values)
if err != nil {
klog.Errorf("get image refs from resources failed %v", err)
return err
}
nodeInfo, err := utils.GetNodeInfo(ctx)
if err != nil {
klog.Errorf("failed to get node info %v", err)
@@ -187,6 +181,12 @@ func (p *DownloadingApp) exec(ctx context.Context) error {
}
values["nodes"] = nodeInfo
refs, err := p.getRefsForImageManager(appConfig, values)
if err != nil {
klog.Errorf("get image refs from resources failed %v", err)
return err
}
err = p.imageClient.Create(ctx, p.manager, refs)
if err != nil {

View File

@@ -7,7 +7,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
var _ OperationApp = &UpgradeFailedApp{}
var _ OperationApp = &InstallingCancelFailedApp{}
type InstallingCancelFailedApp struct {
UninstallFailedApp

View File

@@ -7,10 +7,10 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
var _ OperationApp = &UpgradeFailedApp{}
var _ StatefulApp = &UpgradeFailedApp{}
type UpgradeFailedApp struct {
SuspendFailedApp
*DoNothingApp
}
func NewUpgradeFailedApp(c client.Client,
@@ -18,13 +18,10 @@ func NewUpgradeFailedApp(c client.Client,
return appFactory.New(c, manager, 0,
func(c client.Client, manager *appsv1.ApplicationManager, ttl time.Duration) StatefulApp {
return &UpgradeFailedApp{
SuspendFailedApp: SuspendFailedApp{
&baseOperationApp{
ttl: ttl,
baseStatefulApp: &baseStatefulApp{
manager: manager,
client: c,
},
DoNothingApp: &DoNothingApp{
baseStatefulApp: &baseStatefulApp{
manager: manager,
client: c,
},
},
}

View File

@@ -87,6 +87,7 @@ func UpgradeCharts(ctx context.Context, actionConfig *action.Configuration, sett
client.Namespace = namespace
client.Timeout = 300 * time.Second
client.Recreate = false
client.Atomic = true
if reuseValue {
client.ReuseValues = true
}

View File

@@ -199,7 +199,7 @@ func (imc *ImageManagerClient) PollDownloadProgress(ctx context.Context, am *app
}
err = imc.updateProgress(ctx, am, &lastProgress, ret*100, am.Spec.OpType == appv1alpha1.UpgradeOp)
if err == nil {
if err == nil && im.Status.State == "completed" {
return nil
}

View File

@@ -3,12 +3,12 @@ package security
import (
"bytetrade.io/web3os/app-service/pkg/constants"
"bytetrade.io/web3os/app-service/pkg/utils"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
netv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
)
const (

View File

@@ -29,7 +29,7 @@ spec:
name: check-auth
containers:
- name: auth-front
image: beclab/login:v1.6.22
image: beclab/login:v1.6.24
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80

View File

@@ -266,7 +266,7 @@ spec:
containers:
- name: api
image: beclab/bfl:v0.4.35
image: beclab/bfl:v0.4.36
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 1000

View File

@@ -2,8 +2,6 @@ package v1
import (
"fmt"
"math"
"net/http"
"strconv"
"time"
@@ -11,17 +9,12 @@ import (
"bytetrade.io/web3os/bfl/pkg/api"
"bytetrade.io/web3os/bfl/pkg/api/response"
"bytetrade.io/web3os/bfl/pkg/apis"
"bytetrade.io/web3os/bfl/pkg/apis/backend/v1/metrics"
iamV1alpha1 "bytetrade.io/web3os/bfl/pkg/apis/iam/v1alpha1"
"bytetrade.io/web3os/bfl/pkg/apis/iam/v1alpha1/operator"
monitov1alpha1 "bytetrade.io/web3os/bfl/pkg/apis/monitor/v1alpha1"
"bytetrade.io/web3os/bfl/pkg/apiserver/runtime"
"bytetrade.io/web3os/bfl/pkg/app_service/v1"
"bytetrade.io/web3os/bfl/pkg/client/clientset/v1alpha1"
"bytetrade.io/web3os/bfl/pkg/constants"
"bytetrade.io/web3os/bfl/pkg/utils"
"bytetrade.io/web3os/bfl/pkg/utils/certmanager"
"bytetrade.io/web3os/bfl/pkg/utils/k8sutil"
iamV1alpha2 "github.com/beclab/api/iam/v1alpha2"
"github.com/emicklei/go-restful/v3"
@@ -42,53 +35,6 @@ func New() *Handler {
}
}
func (h *Handler) handleGetIPAddress(req *restful.Request, resp *restful.Response) {
ctx := req.Request.Context()
master := req.QueryParameter("master")
var masterInternalIP string
if master == "true" {
ip, err := k8sutil.GetL4ProxyNodeIP(ctx, 10*time.Second)
if err != nil {
log.Warnf("no master hostIP: %v", err)
}
if ip != nil && *ip != "" {
masterInternalIP = *ip
}
resp.Write([]byte(masterInternalIP))
return
}
ipAddr := IPAddress{
IsNatted: constants.IsNatted,
Internal: utils.RemoteIp(req.Request),
}
if masterInternalIP != "" {
ipAddr.MasterInternalIP = masterInternalIP
}
// master external ip
masterExternalIP := k8sutil.GetMasterExternalIP(ctx)
if masterExternalIP == nil {
response.HandleError(resp, errors.New("no master external ip"))
return
}
ipAddr.MasterExternalIP = *masterExternalIP
external := utils.GetMyExternalIPAddr()
if external == "" {
response.HandleInternalError(resp, errors.New("no external ip address"))
return
}
ipAddr.External = external
response.Success(resp, ipAddr)
}
func (h *Handler) handleUserInfo(req *restful.Request, resp *restful.Response) {
var (
isEphemeral bool
@@ -154,50 +100,6 @@ func (h *Handler) handleUserInfo(req *restful.Request, resp *restful.Response) {
response.Success(resp, uInfo)
}
func (h *Handler) handleVerifyUserPassword(req *restful.Request, resp *restful.Response) {
var u iamV1alpha1.UserPassword
err := req.ReadEntity(&u)
if err != nil {
response.HandleBadRequest(resp, errors.Errorf("verify password: %v", err))
return
}
log.Info("verify user password")
if u.UserName == "" {
u.UserName = constants.Username
}
// the user's password must be provided
if u.Password == "" {
response.HandleBadRequest(resp, errors.New("verify password: no password provided"))
return
}
data := map[string]string{
"username": u.UserName,
"password": u.Password,
"client_id": constants.KubeSphereClientID,
"client_secret": constants.KubeSphereClientSecret,
"grant_type": "password",
}
token, code, err := iamV1alpha1.RequestToken("", data)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusOK, response.Header{
Code: code,
Message: err.Error(),
})
return
}
if token.AccessToken != "" {
response.SuccessNoData(resp)
return
}
response.HandleUnauthorized(resp, errors.New(response.UnexpectedError))
}
func (h *Handler) handleReDownloadCert(req *restful.Request, resp *restful.Response) {
var (
ctx = req.Request.Context()
@@ -469,68 +371,3 @@ func (h *Handler) myapps(req *restful.Request, resp *restful.Response) {
response.Success(resp, api.NewListResult(list))
}
func (h *Handler) getClusterMetric(req *restful.Request, resp *restful.Response) {
prome, err := metrics.NewPrometheus(metrics.PrometheusEndpoint)
if err != nil {
response.HandleError(resp, err)
return
}
opts := metrics.QueryOptions{
Level: metrics.LevelCluster,
}
metricsResult := prome.GetNamedMetrics(req.Request.Context(), []string{
"cluster_cpu_usage",
"cluster_cpu_total",
"cluster_disk_size_usage",
"cluster_disk_size_capacity",
"cluster_memory_total",
"cluster_memory_usage_wo_cache",
"cluster_net_bytes_transmitted",
"cluster_net_bytes_received",
}, time.Now(), opts)
var clusterMetrics monitov1alpha1.ClusterMetrics
for _, m := range metricsResult {
switch m.MetricName {
case "cluster_cpu_usage":
clusterMetrics.CPU.Usage = metrics.GetValue(&m)
case "cluster_cpu_total":
clusterMetrics.CPU.Total = metrics.GetValue(&m)
case "cluster_disk_size_usage":
clusterMetrics.Disk.Usage = metrics.GetValue(&m)
case "cluster_disk_size_capacity":
clusterMetrics.Disk.Total = metrics.GetValue(&m)
case "cluster_memory_total":
clusterMetrics.Memory.Total = metrics.GetValue(&m)
case "cluster_memory_usage_wo_cache":
clusterMetrics.Memory.Usage = metrics.GetValue(&m)
case "cluster_net_bytes_transmitted":
clusterMetrics.Net.Transmitted = metrics.GetValue(&m)
case "cluster_net_bytes_received":
clusterMetrics.Net.Received = metrics.GetValue(&m)
}
}
roundToGB := func(v float64) float64 { return math.Round((v/1000000000.00)*100.00) / 100.00 }
fmtMetricsValue(&clusterMetrics.CPU, "Cores", func(v float64) float64 { return v })
fmtMetricsValue(&clusterMetrics.Memory, "GB", roundToGB)
fmtMetricsValue(&clusterMetrics.Disk, "GB", roundToGB)
response.Success(resp, clusterMetrics)
}
func fmtMetricsValue(v *monitov1alpha1.MetricV, unit string, unitFunc func(float64) float64) {
v.Unit = unit
v.Usage = unitFunc(v.Usage)
v.Total = unitFunc(v.Total)
v.Ratio = math.Round((v.Usage / v.Total) * 100)
}

View File

@@ -4,7 +4,6 @@ import (
"net/http"
"bytetrade.io/web3os/bfl/pkg/api/response"
iamV1alpha1 "bytetrade.io/web3os/bfl/pkg/apis/iam/v1alpha1"
"bytetrade.io/web3os/bfl/pkg/apiserver/runtime"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
@@ -23,13 +22,6 @@ func AddContainer(c *restful.Container) error {
handler := New()
ws.Route(ws.POST("/verify-password").
To(handler.handleVerifyUserPassword).
Doc("Verify user password.").
Reads(iamV1alpha1.UserPassword{}).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(http.StatusOK, "", response.Response{}))
ws.Route(ws.GET("/user-info").
To(handler.handleUserInfo).
Doc("User information.").
@@ -48,13 +40,6 @@ func AddContainer(c *restful.Container) error {
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(http.StatusOK, "", response.Response{}))
ws.Route(ws.GET("/ip").
To(handler.handleGetIPAddress).
Doc("IP Address.").
Param(ws.QueryParameter("master", "get master nodeIP only").DataType("string").Required(false)).
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(http.StatusOK, "", response.Response{}))
ws.Route(ws.GET("/re-download-cert").
To(handler.handleReDownloadCert).
Doc("Re-download ssl certificate").
@@ -67,12 +52,6 @@ func AddContainer(c *restful.Container) error {
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(http.StatusOK, "", response.Response{}))
ws.Route(ws.GET("/cluster").
To(handler.getClusterMetric).
Doc("get the cluster current metrics ( cpu, memory, disk ).").
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(http.StatusOK, "", response.Response{}))
ws.Route(ws.GET("/config-system").
To(handler.HandleGetSysConfig).
Doc("get user locale.").
@@ -85,12 +64,6 @@ func AddContainer(c *restful.Container) error {
wsWizard.Consumes(restful.MIME_JSON)
wsWizard.Produces(restful.MIME_JSON)
wsWizard.Route(wsWizard.GET("/terminus-info").
To(handler.handleTerminusInfo).
Doc("terminus information.").
Metadata(restfulspec.KeyOpenAPITags, tags).
Returns(http.StatusOK, "", response.Response{}))
wsWizard.Route(wsWizard.GET("/olares-info").
To(handler.handleOlaresInfo).
Doc("olares information.").

View File

@@ -1,43 +0,0 @@
package v1alpha1
import (
"bytetrade.io/web3os/bfl/pkg/api/response"
"github.com/emicklei/go-restful/v3"
"k8s.io/klog/v2"
)
const BackupCancelCode = 493
type handler struct {
}
func newHandler() *handler {
return &handler{}
}
func (h *handler) backupNew(req *restful.Request, resp *restful.Response) {
klog.Info("backup start callback")
for _, cb := range callbackHandlers {
err := cb.BackupNew()
if err != nil {
klog.Error("backup start response error, ", err)
resp.WriteError(BackupCancelCode, err)
return
}
}
response.SuccessNoData(resp)
}
func (h *handler) backupFinish(req *restful.Request, resp *restful.Response) {
klog.Info("backup finished callback")
for _, cb := range callbackHandlers {
err := cb.BackupFinish()
if err != nil {
klog.Warning("backup finished callback error, ", err)
}
}
response.SuccessNoData(resp)
}

View File

@@ -1,51 +0,0 @@
package v1alpha1
import (
"net/http"
"bytetrade.io/web3os/bfl/pkg/api/response"
"bytetrade.io/web3os/bfl/pkg/apiserver/runtime"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
type CallbackHandler struct {
BackupNew func() error
BackupFinish func() error
}
var (
MODULE_TAGS = []string{"callbacks"}
callbackHandlers []*CallbackHandler
)
var ModuleVersion = runtime.ModuleVersion{Name: "callback", Version: "v1alpha1"}
func AddToContainer(c *restful.Container) error {
ws := runtime.NewWebService(ModuleVersion)
handler := newHandler()
ws.Route(ws.POST("/backup/new").
To(handler.backupNew).
Doc("Provide system backup phase-new to callback").
Metadata(restfulspec.KeyOpenAPITags, MODULE_TAGS).
Returns(http.StatusOK, "Success", response.Response{}))
ws.Route(ws.POST("/backup/finish").
To(handler.backupFinish).
Doc("Provide system backup phase-success / failed / canceled to callback").
Metadata(restfulspec.KeyOpenAPITags, MODULE_TAGS).
Returns(http.StatusOK, "Success", response.Response{}))
c.Add(ws)
return nil
}
func AddBackupCallbackHandler(backupNew func() error, backupFinish func() error) {
callbackHandlers = append(callbackHandlers, &CallbackHandler{
BackupNew: backupNew,
BackupFinish: backupFinish,
})
}

View File

@@ -55,41 +55,6 @@ func New(ctrlClient client.Client) *Handler {
}
}
func (h *Handler) handleUserLogin(req *restful.Request, resp *restful.Response) {
var u UserPassword
err := req.ReadEntity(&u)
if err != nil {
response.HandleBadRequest(resp, errors.Errorf("login user, read entity: %v", err))
return
}
log.Infow("read user entity", "userPassword", u)
if u.UserName != constants.Username {
response.HandleBadRequest(resp, errors.New("login user: mismatch input username and userspace"))
return
}
data := map[string]string{
"username": u.UserName,
"password": u.Password,
"client_id": constants.KubeSphereClientID,
"client_secret": constants.KubeSphereClientSecret,
"grant_type": "password",
}
token, code, err := RequestToken("", data)
if err != nil {
// response.HandleError(resp, errors.Errorf("login user, request token: %v", err))
resp.WriteHeaderAndEntity(http.StatusOK, response.Header{
Code: code,
Message: err.Error(),
})
return
}
response.Success(resp, token)
}
func (h *Handler) getRolesByUserName(ctx context.Context, name string) ([]string, error) {
var globalRoleBindings iamV1alpha2.GlobalRoleBindingList
err := h.ctrlClient.List(ctx, &globalRoleBindings)
@@ -374,18 +339,6 @@ func RequestToken(token string, data map[string]string) (*TokenResponse, int, er
return nil, -1, err
}
func (h *Handler) isUserCreating() bool {
return h.userCreatingCount.Load() > 0
}
func (h *Handler) lockUserCreating() {
h.userCreatingCount.Store(-1)
}
func (h *Handler) unlockUserCreating() {
h.userCreatingCount.Store(0)
}
func (h *Handler) handleGetUserMetrics(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user")
token := req.HeaderParameter(constants.UserAuthorizationTokenKey)

View File

@@ -41,11 +41,6 @@ type LoginRecord struct {
LoginTime *int64 `json:"login_time"`
}
type UserPassword struct {
UserName string `json:"username,omitempty"`
Password string `json:"password"`
}
type KubesphereError struct {
Error string `json:"error"`
ErrorDescription string `json:"error_description"`

View File

@@ -1,7 +1,6 @@
package v1alpha1
import (
"errors"
"net/http"
"bytetrade.io/web3os/bfl/pkg/api/response"
@@ -32,7 +31,7 @@ var (
userTags = []string{"users"}
)
func AddToContainer(c *restful.Container, addCallback func(func() error, func() error)) error {
func AddToContainer(c *restful.Container) error {
ws := runtime.NewWebService(ModuleVersion)
config, err := ctrl.GetConfig()
if err != nil {
@@ -85,22 +84,5 @@ func AddToContainer(c *restful.Container, addCallback func(func() error, func()
Returns(http.StatusOK, "", response.Response{}))
c.Add(ws)
// add user creating event to backup callback
addCallback(
func() error { // phase backup-new
if handler.isUserCreating() {
return errors.New("user createing")
}
handler.lockUserCreating()
return nil
},
func() error { // phase backup-finished
handler.unlockUserCreating()
return nil
},
)
return nil
}

View File

@@ -7,7 +7,6 @@ import (
"bytetrade.io/web3os/bfl/internal/log"
"bytetrade.io/web3os/bfl/pkg/api/response"
backendv1 "bytetrade.io/web3os/bfl/pkg/apis/backend/v1"
callbackV1alpha1 "bytetrade.io/web3os/bfl/pkg/apis/callback/v1alpha1"
iamV1alpha1 "bytetrade.io/web3os/bfl/pkg/apis/iam/v1alpha1"
monitov1alpha1 "bytetrade.io/web3os/bfl/pkg/apis/monitor/v1alpha1"
@@ -114,8 +113,7 @@ func (s *APIServer) installAPIDocs() {
}
func (s *APIServer) installModuleAPI() {
urlruntime.Must(callbackV1alpha1.AddToContainer(s.container))
urlruntime.Must(iamV1alpha1.AddToContainer(s.container, callbackV1alpha1.AddBackupCallbackHandler))
urlruntime.Must(iamV1alpha1.AddToContainer(s.container))
urlruntime.Must(backendv1.AddContainer(s.container))
urlruntime.Must(settingsV1alpha1.AddContainer(s.container))
urlruntime.Must(monitov1alpha1.AddContainer(s.container))

View File

@@ -140,7 +140,7 @@ spec:
name: check-chart-repo
containers:
- name: appstore-backend
image: beclab/market-backend:v0.6.7
image: beclab/market-backend:v0.6.8
imagePullPolicy: IfNotPresent
ports:
- containerPort: 81

View File

@@ -25,10 +25,7 @@ metadata:
provider-service-ref: search3-provider-svc.{{ .Release.Namespace }}:28080
rules:
- nonResourceURLs:
- "/document/get_by_resource_uri"
- "/document/add"
- "/document/delete/*"
- "/document/update/*"
- "/document/*"
verbs: ["*"]
---

View File

@@ -240,7 +240,7 @@ spec:
value: os_framework_search3
containers:
- name: search3
image: beclab/search3:v0.0.92
image: beclab/search3:v0.0.93
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
@@ -301,7 +301,7 @@ spec:
priorityClassName: "system-cluster-critical"
containers:
- name: search3monitor
image: beclab/search3monitor:v0.0.92
image: beclab/search3monitor:v0.0.93
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8081