Compare commits
32 Commits
v3.4.0-rc.
...
release-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a95626cc7 | ||
|
|
8b5488ffa9 | ||
|
|
01b45542b4 | ||
|
|
d938161ad3 | ||
|
|
c8e131fc13 | ||
|
|
839a31ac1d | ||
|
|
a0ba5f6085 | ||
|
|
658497aa0a | ||
|
|
a47bf848df | ||
|
|
dbb3f04b9e | ||
|
|
705ea4af40 | ||
|
|
366d1e16e4 | ||
|
|
690d5be824 | ||
|
|
c0419ddab5 | ||
|
|
80b0301f79 | ||
|
|
7162d41310 | ||
|
|
6b10d346ca | ||
|
|
6a0d5ba93c | ||
|
|
d87a782257 | ||
|
|
82e55578a8 | ||
|
|
5b9c357160 | ||
|
|
c385dd92e4 | ||
|
|
1e1b2bd594 | ||
|
|
951b86648c | ||
|
|
04433c139d | ||
|
|
3b8c28d21e | ||
|
|
9489718270 | ||
|
|
54df6b8c8c | ||
|
|
d917905529 | ||
|
|
cd6f940f1d | ||
|
|
921a8f068b | ||
|
|
641aa1dfcf |
@@ -121,7 +121,7 @@ KubeSphere 使用前后端分离的架构,将 [前端](https://github.com/kube
|
||||
🎉 KubeSphere 3.2.1 全新发布!!多项功能优化,带来更好的用户体验,详见 [v3.2.1 发行记录](https://kubesphere.com.cn/docs/release/release-v321/) 。
|
||||
## 安装
|
||||
|
||||
KubeSphere 支持在任意平台运行,从本地数据中心到混合多云再走向边缘。此外,KubeSphere 可以部署在任何版本兼容的 Kubernetes 集群上。Installer 默认将执行最小化安装,您可以在安装前或安装后自定义[安装可插拔功能组件](https://kubesphere.com.cn/docs/quick-start/enable-pluggable-components/)。
|
||||
KubeSphere 支持在任意平台运行,从本地数据中心到混合多云再走向边缘。此外,KubeSphere 可以部署在任何版本兼容的 Kubernetes 集群上。Installer 默认将执行最小化安装,您可以在安装前或安装后自定义[安装可插拔功能组件](https://kubesphere.io/zh/docs/quick-start/enable-pluggable-components/)。
|
||||
### 快速入门
|
||||
#### 在 K8s/K3s 上安装
|
||||
|
||||
@@ -180,7 +180,7 @@ KubeSphere 托管在以下云供应商上,您可以通过在其托管的 Kuber
|
||||
|
||||
## 谁在使用 KubeSphere
|
||||
|
||||
[用户案例学习](https://kubesphere.com.cn/case/) 列出了哪些企业在使用 KubeSphere。欢迎 [发表评论](https://github.com/kubesphere/kubesphere/issues/4123) 来分享您的使用案例。
|
||||
[用户案例学习](https://kubesphere.io/zh/case/) 列出了哪些企业在使用 KubeSphere。欢迎 [发表评论](https://github.com/kubesphere/kubesphere/issues/4123) 来分享您的使用案例。
|
||||
|
||||
## Landscapes
|
||||
|
||||
|
||||
@@ -242,4 +242,5 @@ func (s *KubeSphereControllerManagerOptions) MergeConfig(cfg *controllerconfig.C
|
||||
s.MultiClusterOptions = cfg.MultiClusterOptions
|
||||
s.ServiceMeshOptions = cfg.ServiceMeshOptions
|
||||
s.GatewayOptions = cfg.GatewayOptions
|
||||
s.MonitoringOptions = cfg.MonitoringOptions
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
openpitrixv1 "kubesphere.io/kubesphere/pkg/kapis/openpitrix/v1"
|
||||
"kubesphere.io/kubesphere/pkg/utils/clusterclient"
|
||||
@@ -41,9 +44,6 @@ import (
|
||||
auditingclient "kubesphere.io/kubesphere/pkg/simple/client/auditing/elasticsearch"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/cache"
|
||||
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins"
|
||||
eventsclient "kubesphere.io/kubesphere/pkg/simple/client/events/elasticsearch"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
@@ -59,9 +59,8 @@ type ServerRunOptions struct {
|
||||
ConfigFile string
|
||||
GenericServerRunOptions *genericoptions.ServerRunOptions
|
||||
*apiserverconfig.Config
|
||||
|
||||
//
|
||||
DebugMode bool
|
||||
schemeOnce sync.Once
|
||||
DebugMode bool
|
||||
|
||||
// Enable gops or not.
|
||||
GOPSEnabled bool
|
||||
@@ -71,6 +70,7 @@ func NewServerRunOptions() *ServerRunOptions {
|
||||
s := &ServerRunOptions{
|
||||
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
|
||||
Config: apiserverconfig.New(),
|
||||
schemeOnce: sync.Once{},
|
||||
}
|
||||
|
||||
return s
|
||||
@@ -87,7 +87,6 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) {
|
||||
s.AuthorizationOptions.AddFlags(fss.FlagSet("authorization"), s.AuthorizationOptions)
|
||||
s.DevopsOptions.AddFlags(fss.FlagSet("devops"), s.DevopsOptions)
|
||||
s.SonarQubeOptions.AddFlags(fss.FlagSet("sonarqube"), s.SonarQubeOptions)
|
||||
s.RedisOptions.AddFlags(fss.FlagSet("redis"), s.RedisOptions)
|
||||
s.S3Options.AddFlags(fss.FlagSet("s3"), s.S3Options)
|
||||
s.OpenPitrixOptions.AddFlags(fss.FlagSet("openpitrix"), s.OpenPitrixOptions)
|
||||
s.NetworkOptions.AddFlags(fss.FlagSet("network"), s.NetworkOptions)
|
||||
@@ -176,21 +175,23 @@ func (s *ServerRunOptions) NewAPIServer(stopCh <-chan struct{}) (*apiserver.APIS
|
||||
apiServer.SonarClient = sonarqube.NewSonar(sonarClient.SonarQube())
|
||||
}
|
||||
|
||||
var cacheClient cache.Interface
|
||||
if s.RedisOptions != nil && len(s.RedisOptions.Host) != 0 {
|
||||
if s.RedisOptions.Host == fakeInterface && s.DebugMode {
|
||||
apiServer.CacheClient = cache.NewSimpleCache()
|
||||
} else {
|
||||
cacheClient, err = cache.NewRedisClient(s.RedisOptions, stopCh)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to redis service, please check redis status, error: %v", err)
|
||||
}
|
||||
apiServer.CacheClient = cacheClient
|
||||
// If debug mode is on or CacheOptions is nil, will create a fake cache.
|
||||
if s.CacheOptions.Type != "" {
|
||||
if s.DebugMode {
|
||||
s.CacheOptions.Type = cache.DefaultCacheType
|
||||
}
|
||||
cacheClient, err := cache.New(s.CacheOptions, stopCh)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create cache, error: %v", err)
|
||||
}
|
||||
apiServer.CacheClient = cacheClient
|
||||
} else {
|
||||
klog.Warning("ks-apiserver starts without redis provided, it will use in memory cache. " +
|
||||
"This may cause inconsistencies when running ks-apiserver with multiple replicas.")
|
||||
apiServer.CacheClient = cache.NewSimpleCache()
|
||||
s.CacheOptions = &cache.Options{Type: cache.DefaultCacheType}
|
||||
// fake cache has no error to return
|
||||
cacheClient, _ := cache.New(s.CacheOptions, stopCh)
|
||||
apiServer.CacheClient = cacheClient
|
||||
klog.Warning("ks-apiserver starts without cache provided, it will use in memory cache. " +
|
||||
"This may cause inconsistencies when running ks-apiserver with multiple replicas, and memory leak risk")
|
||||
}
|
||||
|
||||
if s.EventsOptions.Host != "" {
|
||||
@@ -222,7 +223,7 @@ func (s *ServerRunOptions) NewAPIServer(stopCh <-chan struct{}) (*apiserver.APIS
|
||||
apiServer.ClusterClient = cc
|
||||
}
|
||||
|
||||
apiServer.OpenpitrixClient = openpitrixv1.NewOpenpitrixClient(informerFactory, apiServer.KubernetesClient.KubeSphere(), s.OpenPitrixOptions, apiServer.ClusterClient, stopCh)
|
||||
apiServer.OpenpitrixClient = openpitrixv1.NewOpenpitrixClient(informerFactory, apiServer.KubernetesClient.KubeSphere(), s.OpenPitrixOptions, apiServer.ClusterClient)
|
||||
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", s.GenericServerRunOptions.InsecurePort),
|
||||
@@ -241,9 +242,11 @@ func (s *ServerRunOptions) NewAPIServer(stopCh <-chan struct{}) (*apiserver.APIS
|
||||
}
|
||||
|
||||
sch := scheme.Scheme
|
||||
if err := apis.AddToScheme(sch); err != nil {
|
||||
klog.Fatalf("unable add APIs to scheme: %v", err)
|
||||
}
|
||||
s.schemeOnce.Do(func() {
|
||||
if err := apis.AddToScheme(sch); err != nil {
|
||||
klog.Fatalf("unable add APIs to scheme: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
apiServer.RuntimeCache, err = runtimecache.New(apiServer.KubernetesClient.Config(), runtimecache.Options{Scheme: sch})
|
||||
if err != nil {
|
||||
|
||||
16
go.mod
16
go.mod
@@ -56,7 +56,7 @@ require (
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/json-iterator/go v1.1.11
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/jszwec/csvutil v1.5.0
|
||||
github.com/kelseyhightower/envconfig v1.4.0 // indirect
|
||||
github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0
|
||||
@@ -82,8 +82,6 @@ require (
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/prometheus/common v0.26.0
|
||||
github.com/prometheus/prometheus v1.8.2-0.20200907175821-8219b442c864
|
||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 // indirect
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
|
||||
github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009
|
||||
github.com/speps/go-hashids v2.0.0+incompatible
|
||||
github.com/spf13/cobra v1.2.1
|
||||
@@ -182,6 +180,7 @@ replace (
|
||||
github.com/Shopify/logrus-bugsnag => github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d
|
||||
github.com/Shopify/sarama => github.com/Shopify/sarama v1.19.0
|
||||
github.com/Shopify/toxiproxy => github.com/Shopify/toxiproxy v2.1.4+incompatible
|
||||
github.com/StackExchange/wmi => github.com/StackExchange/wmi v1.2.1
|
||||
github.com/VividCortex/gohistogram => github.com/VividCortex/gohistogram v1.0.0
|
||||
github.com/afex/hystrix-go => github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
|
||||
github.com/agnivade/levenshtein => github.com/agnivade/levenshtein v1.0.1
|
||||
@@ -345,6 +344,7 @@ replace (
|
||||
github.com/go-logfmt/logfmt => github.com/go-logfmt/logfmt v0.5.0
|
||||
github.com/go-logr/logr => github.com/go-logr/logr v0.4.0
|
||||
github.com/go-logr/zapr => github.com/go-logr/zapr v0.4.0
|
||||
github.com/go-ole/go-ole => github.com/go-ole/go-ole v1.2.6-0.20210915003542-8b1f7f90f6b1
|
||||
github.com/go-openapi/analysis => github.com/go-openapi/analysis v0.19.10
|
||||
github.com/go-openapi/errors => github.com/go-openapi/errors v0.19.4
|
||||
github.com/go-openapi/jsonpointer => github.com/go-openapi/jsonpointer v0.19.3
|
||||
@@ -407,6 +407,7 @@ replace (
|
||||
github.com/google/go-github => github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/google/go-querystring => github.com/google/go-querystring v1.0.0
|
||||
github.com/google/gofuzz => github.com/google/gofuzz v1.1.0
|
||||
github.com/google/gops => github.com/google/gops v0.3.23
|
||||
github.com/google/martian => github.com/google/martian v2.1.0+incompatible
|
||||
github.com/google/pprof => github.com/google/pprof v0.0.0-20200417002340-c6e0a841f49a
|
||||
github.com/google/renameio => github.com/google/renameio v0.1.0
|
||||
@@ -478,7 +479,7 @@ replace (
|
||||
github.com/jonboulle/clockwork => github.com/jonboulle/clockwork v0.1.0
|
||||
github.com/jpillora/backoff => github.com/jpillora/backoff v1.0.0
|
||||
github.com/jsimonetti/rtnetlink => github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4
|
||||
github.com/json-iterator/go => github.com/json-iterator/go v1.1.10
|
||||
github.com/json-iterator/go => github.com/json-iterator/go v1.1.12
|
||||
github.com/jstemmer/go-junit-report => github.com/jstemmer/go-junit-report v0.9.1
|
||||
github.com/jsternberg/zap-logfmt => github.com/jsternberg/zap-logfmt v1.0.0
|
||||
github.com/jszwec/csvutil => github.com/jszwec/csvutil v1.5.0
|
||||
@@ -490,6 +491,7 @@ replace (
|
||||
github.com/karrick/godirwalk => github.com/karrick/godirwalk v1.10.3
|
||||
github.com/kelseyhightower/envconfig => github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/kevinburke/ssh_config => github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e
|
||||
github.com/keybase/go-ps => github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19
|
||||
github.com/kisielk/errcheck => github.com/kisielk/errcheck v1.2.0
|
||||
github.com/kisielk/gotool => github.com/kisielk/gotool v1.0.0
|
||||
github.com/kisielk/sqlstruct => github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49
|
||||
@@ -558,7 +560,7 @@ replace (
|
||||
github.com/moby/spdystream => github.com/moby/spdystream v0.2.0
|
||||
github.com/moby/term => github.com/moby/term v0.0.0-20201216013528-df9cb8a40635
|
||||
github.com/modern-go/concurrent => github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
|
||||
github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.1
|
||||
github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.2
|
||||
github.com/monochromegane/go-gitignore => github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00
|
||||
github.com/montanaflynn/stats => github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe
|
||||
github.com/morikuni/aec => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c
|
||||
@@ -654,6 +656,7 @@ replace (
|
||||
github.com/segmentio/kafka-go => github.com/segmentio/kafka-go v0.2.0
|
||||
github.com/sercand/kuberesolver => github.com/sercand/kuberesolver v2.4.0+incompatible
|
||||
github.com/sergi/go-diff => github.com/sergi/go-diff v1.0.0
|
||||
github.com/shirou/gopsutil/v3 => github.com/shirou/gopsutil/v3 v3.21.9
|
||||
github.com/shopspring/decimal => github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24
|
||||
github.com/shurcooL/httpfs => github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
|
||||
github.com/shurcooL/sanitized_anchor_name => github.com/shurcooL/sanitized_anchor_name v1.0.0
|
||||
@@ -682,6 +685,8 @@ replace (
|
||||
github.com/thanos-io/thanos => github.com/thanos-io/thanos v0.13.1-0.20200910143741-e0b7f7b32e9c
|
||||
github.com/tidwall/pretty => github.com/tidwall/pretty v1.0.0
|
||||
github.com/tinylib/msgp => github.com/tinylib/msgp v1.1.0
|
||||
github.com/tklauser/go-sysconf => github.com/tklauser/go-sysconf v0.3.9
|
||||
github.com/tklauser/numcpus => github.com/tklauser/numcpus v0.3.0
|
||||
github.com/tmc/grpc-websocket-proxy => github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5
|
||||
github.com/tv42/httpunix => github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926
|
||||
github.com/uber/jaeger-client-go => github.com/uber/jaeger-client-go v2.23.0+incompatible
|
||||
@@ -813,6 +818,7 @@ replace (
|
||||
kubesphere.io/client-go => ./staging/src/kubesphere.io/client-go
|
||||
kubesphere.io/monitoring-dashboard => kubesphere.io/monitoring-dashboard v0.2.2
|
||||
rsc.io/binaryregexp => rsc.io/binaryregexp v0.2.0
|
||||
rsc.io/goversion => rsc.io/goversion v1.2.0
|
||||
rsc.io/letsencrypt => rsc.io/letsencrypt v0.0.1
|
||||
rsc.io/pdf => rsc.io/pdf v0.1.1
|
||||
rsc.io/quote/v3 => rsc.io/quote/v3 v3.1.0
|
||||
|
||||
11
go.sum
11
go.sum
@@ -288,7 +288,6 @@ github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
|
||||
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
|
||||
github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.2.6-0.20210915003542-8b1f7f90f6b1/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-openapi/analysis v0.19.10 h1:5BHISBAXOc/aJK25irLZnx2D3s6WyYaY9D4gmuz9fdE=
|
||||
github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ=
|
||||
@@ -488,8 +487,8 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||
github.com/jszwec/csvutil v1.5.0 h1:ErLnF1Qzzt9svk8CUY7CyLl/W9eET+KWPIZWkE1o6JM=
|
||||
@@ -606,8 +605,8 @@ github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0
|
||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
@@ -747,9 +746,7 @@ github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfP
|
||||
github.com/sercand/kuberesolver v2.4.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil/v3 v3.21.9/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
|
||||
@@ -39,6 +39,7 @@ find_files() {
|
||||
-o -wholename '*/third_party/*' \
|
||||
-o -wholename '*/vendor/*' \
|
||||
-o -wholename './staging/src/kubesphere.io/client-go/*vendor/*' \
|
||||
-o -wholename './staging/src/kubesphere.io/api/*/zz_generated.deepcopy.go' \
|
||||
\) -prune \
|
||||
\) -name '*.go'
|
||||
}
|
||||
|
||||
1
hack/verify-gofmt.sh
Normal file → Executable file
1
hack/verify-gofmt.sh
Normal file → Executable file
@@ -44,6 +44,7 @@ find_files() {
|
||||
-o -wholename '*/third_party/*' \
|
||||
-o -wholename '*/vendor/*' \
|
||||
-o -wholename './staging/src/kubesphere.io/client-go/*vendor/*' \
|
||||
-o -wholename './staging/src/kubesphere.io/api/*/zz_generated.deepcopy.go' \
|
||||
-o -wholename '*/bindata.go' \
|
||||
\) -prune \
|
||||
\) -name '*.go'
|
||||
|
||||
@@ -394,6 +394,10 @@ func waitForCacheSync(discoveryClient discovery.DiscoveryInterface, sharedInform
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
klog.Warningf("group version %s not exists in the cluster", groupVersion)
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("failed to fetch group version resources %s: %s", groupVersion, err)
|
||||
}
|
||||
for _, resourceName := range resourceNames {
|
||||
|
||||
@@ -141,6 +141,7 @@ func (b *Backend) sendEvents(events *v1alpha1.EventList) {
|
||||
defer cancel()
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
skipReturnSender := false
|
||||
|
||||
send := func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.getSenderTimeout)
|
||||
@@ -149,6 +150,7 @@ func (b *Backend) sendEvents(events *v1alpha1.EventList) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
klog.Error("Get auditing event sender timeout")
|
||||
skipReturnSender = true
|
||||
return
|
||||
case b.senderCh <- struct{}{}:
|
||||
}
|
||||
@@ -182,7 +184,9 @@ func (b *Backend) sendEvents(events *v1alpha1.EventList) {
|
||||
go send()
|
||||
|
||||
defer func() {
|
||||
<-b.senderCh
|
||||
if !skipReturnSender {
|
||||
<-b.senderCh
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
|
||||
@@ -33,8 +33,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/klog"
|
||||
|
||||
devopsv1alpha3 "kubesphere.io/api/devops/v1alpha3"
|
||||
"kubesphere.io/api/iam/v1alpha2"
|
||||
|
||||
auditv1alpha1 "kubesphere.io/kubesphere/pkg/apiserver/auditing/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
@@ -192,7 +192,7 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo
|
||||
}
|
||||
}
|
||||
|
||||
if (e.Level.GreaterOrEqual(audit.LevelRequest) || e.Verb == "create") && req.ContentLength > 0 {
|
||||
if a.needAnalyzeRequestBody(e, req) {
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
@@ -212,11 +212,45 @@ func (a *auditing) LogRequestObject(req *http.Request, info *request.RequestInfo
|
||||
e.ObjectRef.Name = obj.Name
|
||||
}
|
||||
}
|
||||
|
||||
// for recording disable and enable user
|
||||
if e.ObjectRef.Resource == "users" && e.Verb == "update" {
|
||||
u := &v1alpha2.User{}
|
||||
if err := json.Unmarshal(body, u); err == nil {
|
||||
if u.Status.State == v1alpha2.UserActive {
|
||||
e.Verb = "enable"
|
||||
} else if u.Status.State == v1alpha2.UserDisabled {
|
||||
e.Verb = "disable"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func (a *auditing) needAnalyzeRequestBody(e *auditv1alpha1.Event, req *http.Request) bool {
|
||||
|
||||
if req.ContentLength <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if e.Level.GreaterOrEqual(audit.LevelRequest) {
|
||||
return true
|
||||
}
|
||||
|
||||
if e.Verb == "create" {
|
||||
return true
|
||||
}
|
||||
|
||||
// for recording disable and enable user
|
||||
if e.ObjectRef.Resource == "users" && e.Verb == "update" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *auditing) LogResponseObject(e *auditv1alpha1.Event, resp *ResponseCapture) {
|
||||
|
||||
e.StageTimestamp = metav1.NowMicro()
|
||||
|
||||
@@ -45,7 +45,7 @@ func init() {
|
||||
type ldapProvider struct {
|
||||
// Host and optional port of the LDAP server in the form "host:port".
|
||||
// If the port is not supplied, 389 for insecure or StartTLS connections, 636
|
||||
Host string `json:"host,omitempty" yaml:"managerDN"`
|
||||
Host string `json:"host,omitempty" yaml:"host"`
|
||||
// Timeout duration when reading data from remote server. Default to 15s.
|
||||
ReadTimeout int `json:"readTimeout" yaml:"readTimeout"`
|
||||
// If specified, connections will use the ldaps:// protocol
|
||||
|
||||
@@ -160,7 +160,7 @@ type Config struct {
|
||||
ServiceMeshOptions *servicemesh.Options `json:"servicemesh,omitempty" yaml:"servicemesh,omitempty" mapstructure:"servicemesh"`
|
||||
NetworkOptions *network.Options `json:"network,omitempty" yaml:"network,omitempty" mapstructure:"network"`
|
||||
LdapOptions *ldap.Options `json:"-,omitempty" yaml:"ldap,omitempty" mapstructure:"ldap"`
|
||||
RedisOptions *cache.Options `json:"redis,omitempty" yaml:"redis,omitempty" mapstructure:"redis"`
|
||||
CacheOptions *cache.Options `json:"cache,omitempty" yaml:"cache,omitempty" mapstructure:"cache"`
|
||||
S3Options *s3.Options `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"`
|
||||
OpenPitrixOptions *openpitrix.Options `json:"openpitrix,omitempty" yaml:"openpitrix,omitempty" mapstructure:"openpitrix"`
|
||||
MonitoringOptions *prometheus.Options `json:"monitoring,omitempty" yaml:"monitoring,omitempty" mapstructure:"monitoring"`
|
||||
@@ -189,7 +189,7 @@ func New() *Config {
|
||||
ServiceMeshOptions: servicemesh.NewServiceMeshOptions(),
|
||||
NetworkOptions: network.NewNetworkOptions(),
|
||||
LdapOptions: ldap.NewOptions(),
|
||||
RedisOptions: cache.NewRedisOptions(),
|
||||
CacheOptions: cache.NewCacheOptions(),
|
||||
S3Options: s3.NewS3Options(),
|
||||
OpenPitrixOptions: openpitrix.NewOptions(),
|
||||
MonitoringOptions: prometheus.NewPrometheusOptions(),
|
||||
@@ -292,8 +292,8 @@ func (conf *Config) ToMap() map[string]bool {
|
||||
// Remove invalid options before serializing to json or yaml
|
||||
func (conf *Config) stripEmptyOptions() {
|
||||
|
||||
if conf.RedisOptions != nil && conf.RedisOptions.Host == "" {
|
||||
conf.RedisOptions = nil
|
||||
if conf.CacheOptions != nil && conf.CacheOptions.Type == "" {
|
||||
conf.CacheOptions = nil
|
||||
}
|
||||
|
||||
if conf.DevopsOptions != nil && conf.DevopsOptions.Host == "" {
|
||||
|
||||
@@ -88,11 +88,9 @@ func newTestConfig() (*Config, error) {
|
||||
MaxCap: 100,
|
||||
PoolName: "ldap",
|
||||
},
|
||||
RedisOptions: &cache.Options{
|
||||
Host: "localhost",
|
||||
Port: 6379,
|
||||
Password: "KUBESPHERE_REDIS_PASSWORD",
|
||||
DB: 0,
|
||||
CacheOptions: &cache.Options{
|
||||
Type: "redis",
|
||||
Options: map[string]interface{}{},
|
||||
},
|
||||
S3Options: &s3.Options{
|
||||
Endpoint: "http://minio.openpitrix-system.svc",
|
||||
@@ -236,9 +234,6 @@ func TestGet(t *testing.T) {
|
||||
saveTestConfig(t, conf)
|
||||
defer cleanTestConfig(t)
|
||||
|
||||
conf.RedisOptions.Password = "P@88w0rd"
|
||||
os.Setenv("KUBESPHERE_REDIS_PASSWORD", "P@88w0rd")
|
||||
|
||||
conf2, err := TryLoadFromDisk()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -251,7 +246,7 @@ func TestGet(t *testing.T) {
|
||||
func TestStripEmptyOptions(t *testing.T) {
|
||||
var config Config
|
||||
|
||||
config.RedisOptions = &cache.Options{Host: ""}
|
||||
config.CacheOptions = &cache.Options{Type: ""}
|
||||
config.DevopsOptions = &jenkins.Options{Host: ""}
|
||||
config.MonitoringOptions = &prometheus.Options{Endpoint: ""}
|
||||
config.SonarQubeOptions = &sonarqube.Options{Host: ""}
|
||||
@@ -284,7 +279,7 @@ func TestStripEmptyOptions(t *testing.T) {
|
||||
|
||||
config.stripEmptyOptions()
|
||||
|
||||
if config.RedisOptions != nil ||
|
||||
if config.CacheOptions != nil ||
|
||||
config.DevopsOptions != nil ||
|
||||
config.MonitoringOptions != nil ||
|
||||
config.SonarQubeOptions != nil ||
|
||||
|
||||
@@ -246,8 +246,6 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
|
||||
// parsing successful, so we now know the proper value for .Parts
|
||||
requestInfo.Parts = currentParts
|
||||
|
||||
requestInfo.ResourceScope = r.resolveResourceScope(requestInfo)
|
||||
|
||||
// parts look like: resource/resourceName/subresource/other/stuff/we/don't/interpret
|
||||
switch {
|
||||
case len(requestInfo.Parts) >= 3 && !specialVerbsNoSubresources.Has(requestInfo.Verb):
|
||||
@@ -260,6 +258,8 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
|
||||
requestInfo.Resource = requestInfo.Parts[0]
|
||||
}
|
||||
|
||||
requestInfo.ResourceScope = r.resolveResourceScope(requestInfo)
|
||||
|
||||
// if there's no name on the request and we thought it was a get before, then the actual verb is a list or a watch
|
||||
if len(requestInfo.Name) == 0 && requestInfo.Verb == "get" {
|
||||
opts := metainternalversion.ListOptions{}
|
||||
|
||||
@@ -407,6 +407,11 @@ func (c *clusterController) syncCluster(key string) error {
|
||||
} else { // join federation
|
||||
_, err = c.joinFederation(clusterConfig, cluster.Name, cluster.Labels)
|
||||
if err != nil {
|
||||
if errors.IsConflict(err) {
|
||||
klog.Warningf("update KubeFedCluster %s conflicted, retrying", cluster.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
klog.Errorf("Failed to join federation for cluster %s, error %v", cluster.Name, err)
|
||||
|
||||
federationNotReadyCondition := clusterv1alpha1.ClusterCondition{
|
||||
@@ -418,6 +423,15 @@ func (c *clusterController) syncCluster(key string) error {
|
||||
Message: "Cluster can not join federation control plane",
|
||||
}
|
||||
c.updateClusterCondition(cluster, federationNotReadyCondition)
|
||||
notReadyCondition := clusterv1alpha1.ClusterCondition{
|
||||
Type: clusterv1alpha1.ClusterReady,
|
||||
Status: v1.ConditionFalse,
|
||||
LastUpdateTime: metav1.Now(),
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "Cluster join federation control plane failed",
|
||||
Message: "Cluster is Not Ready now",
|
||||
}
|
||||
c.updateClusterCondition(cluster, notReadyCondition)
|
||||
|
||||
_, err = c.ksClient.ClusterV1alpha1().Clusters().Update(context.TODO(), cluster, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
kubeclient "k8s.io/client-go/kubernetes"
|
||||
k8sscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/retry"
|
||||
"k8s.io/klog"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
fedapis "sigs.k8s.io/kubefed/pkg/apis"
|
||||
@@ -199,25 +200,25 @@ func createKubeFedCluster(clusterConfig *rest.Config, client client.Client, join
|
||||
case err == nil && errorOnExisting:
|
||||
return nil, errors.Errorf("federated cluster %s already exists in host cluster", joiningClusterName)
|
||||
case err == nil:
|
||||
existingFedCluster.Spec = fedCluster.Spec
|
||||
existingFedCluster.Labels = labels
|
||||
err = client.Update(context.TODO(), existingFedCluster)
|
||||
if err != nil {
|
||||
if retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
if err = client.Get(context.TODO(), key, existingFedCluster); err != nil {
|
||||
return err
|
||||
}
|
||||
existingFedCluster.Spec = fedCluster.Spec
|
||||
existingFedCluster.Labels = labels
|
||||
return client.Update(context.TODO(), existingFedCluster)
|
||||
}); retryErr != nil {
|
||||
klog.V(2).Infof("Could not update federated cluster %s due to %v", fedCluster.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
return existingFedCluster, nil
|
||||
default:
|
||||
|
||||
err = checkWorkspaces(clusterConfig, client, fedCluster)
|
||||
|
||||
if err != nil {
|
||||
if err = checkWorkspaces(clusterConfig, client, fedCluster); err != nil {
|
||||
klog.V(2).Infof("Validate federated cluster %s failed due to %v", fedCluster.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = client.Create(context.TODO(), fedCluster)
|
||||
if err != nil {
|
||||
if err = client.Create(context.TODO(), fedCluster); err != nil {
|
||||
klog.V(2).Infof("Could not create federated cluster %s due to %v", fedCluster.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -380,6 +380,7 @@ func (h *iamHandler) ListWorkspaceRoles(request *restful.Request, response *rest
|
||||
queryParam.Filters[iamv1alpha2.ScopeWorkspace] = query.Value(workspace)
|
||||
// shared workspace role template
|
||||
if string(queryParam.Filters[query.FieldLabel]) == fmt.Sprintf("%s=%s", iamv1alpha2.RoleTemplateLabel, "true") ||
|
||||
strings.Contains(queryParam.LabelSelector, iamv1alpha2.RoleTemplateLabel) ||
|
||||
queryParam.Filters[iamv1alpha2.AggregateTo] != "" {
|
||||
delete(queryParam.Filters, iamv1alpha2.ScopeWorkspace)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ type openpitrixHandler struct {
|
||||
openpitrix openpitrix.Interface
|
||||
}
|
||||
|
||||
func NewOpenpitrixClient(ksInformers informers.InformerFactory, ksClient versioned.Interface, option *openpitrixoptions.Options, cc clusterclient.ClusterClients, stopCh <-chan struct{}) openpitrix.Interface {
|
||||
func NewOpenpitrixClient(ksInformers informers.InformerFactory, ksClient versioned.Interface, option *openpitrixoptions.Options, cc clusterclient.ClusterClients) openpitrix.Interface {
|
||||
var s3Client s3.Interface
|
||||
if option != nil && option.S3Options != nil && len(option.S3Options.Endpoint) != 0 {
|
||||
var err error
|
||||
@@ -62,7 +62,7 @@ func NewOpenpitrixClient(ksInformers informers.InformerFactory, ksClient version
|
||||
}
|
||||
}
|
||||
|
||||
return openpitrix.NewOpenpitrixOperator(ksInformers, ksClient, s3Client, cc, stopCh)
|
||||
return openpitrix.NewOpenpitrixOperator(ksInformers, ksClient, s3Client, cc)
|
||||
}
|
||||
|
||||
func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
@@ -48,15 +48,17 @@ func NewHandler(o *servicemesh.Options, client kubernetes.Interface, cache cache
|
||||
if o != nil && o.KialiQueryHost != "" {
|
||||
sa, err := client.CoreV1().ServiceAccounts(KubesphereNamespace).Get(context.TODO(), KubeSphereServiceAccount, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
secret, err := client.CoreV1().Secrets(KubesphereNamespace).Get(context.TODO(), sa.Secrets[0].Name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return &Handler{
|
||||
opt: o,
|
||||
client: kiali.NewDefaultClient(
|
||||
cache,
|
||||
string(secret.Data["token"]),
|
||||
o.KialiQueryHost,
|
||||
),
|
||||
if len(sa.Secrets) > 0 {
|
||||
secret, err := client.CoreV1().Secrets(KubesphereNamespace).Get(context.TODO(), sa.Secrets[0].Name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return &Handler{
|
||||
opt: o,
|
||||
client: kiali.NewDefaultClient(
|
||||
cache,
|
||||
string(secret.Data["token"]),
|
||||
o.KialiQueryHost,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
klog.Warningf("get ServiceAccount's Secret failed %v", err)
|
||||
|
||||
@@ -202,30 +202,40 @@ func (h *tenantHandler) CreateNamespace(request *restful.Request, response *rest
|
||||
response.WriteEntity(created)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) CreateWorkspaceTemplate(request *restful.Request, response *restful.Response) {
|
||||
func (h *tenantHandler) CreateWorkspaceTemplate(req *restful.Request, resp *restful.Response) {
|
||||
var workspace tenantv1alpha2.WorkspaceTemplate
|
||||
|
||||
err := request.ReadEntity(&workspace)
|
||||
err := req.ReadEntity(&workspace)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
api.HandleBadRequest(resp, req, err)
|
||||
return
|
||||
}
|
||||
requestUser, ok := request.UserFrom(req.Request.Context())
|
||||
if !ok {
|
||||
err := fmt.Errorf("cannot obtain user info")
|
||||
klog.Errorln(err)
|
||||
api.HandleForbidden(resp, req, err)
|
||||
}
|
||||
|
||||
created, err := h.tenant.CreateWorkspaceTemplate(&workspace)
|
||||
created, err := h.tenant.CreateWorkspaceTemplate(requestUser, &workspace)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
api.HandleNotFound(resp, req, err)
|
||||
return
|
||||
}
|
||||
api.HandleBadRequest(response, request, err)
|
||||
if errors.IsForbidden(err) {
|
||||
api.HandleForbidden(resp, req, err)
|
||||
return
|
||||
}
|
||||
api.HandleBadRequest(resp, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(created)
|
||||
resp.WriteEntity(created)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) DeleteWorkspaceTemplate(request *restful.Request, response *restful.Response) {
|
||||
@@ -253,42 +263,53 @@ func (h *tenantHandler) DeleteWorkspaceTemplate(request *restful.Request, respon
|
||||
response.WriteEntity(servererr.None)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) UpdateWorkspaceTemplate(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
func (h *tenantHandler) UpdateWorkspaceTemplate(req *restful.Request, resp *restful.Response) {
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
var workspace tenantv1alpha2.WorkspaceTemplate
|
||||
|
||||
err := request.ReadEntity(&workspace)
|
||||
err := req.ReadEntity(&workspace)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
api.HandleBadRequest(resp, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
if workspaceName != workspace.Name {
|
||||
err := fmt.Errorf("the name of the object (%s) does not match the name on the URL (%s)", workspace.Name, workspaceName)
|
||||
klog.Errorf("%+v", err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
api.HandleBadRequest(resp, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
updated, err := h.tenant.UpdateWorkspaceTemplate(&workspace)
|
||||
requestUser, ok := request.UserFrom(req.Request.Context())
|
||||
if !ok {
|
||||
err := fmt.Errorf("cannot obtain user info")
|
||||
klog.Errorln(err)
|
||||
api.HandleForbidden(resp, req, err)
|
||||
}
|
||||
|
||||
updated, err := h.tenant.UpdateWorkspaceTemplate(requestUser, &workspace)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
api.HandleNotFound(resp, req, err)
|
||||
return
|
||||
}
|
||||
if errors.IsBadRequest(err) {
|
||||
api.HandleBadRequest(response, request, err)
|
||||
api.HandleBadRequest(resp, req, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
if errors.IsForbidden(err) {
|
||||
api.HandleForbidden(resp, req, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(updated)
|
||||
resp.WriteEntity(updated)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) DescribeWorkspaceTemplate(request *restful.Request, response *restful.Response) {
|
||||
@@ -520,33 +541,44 @@ func (h *tenantHandler) PatchNamespace(request *restful.Request, response *restf
|
||||
response.WriteEntity(patched)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) PatchWorkspaceTemplate(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
func (h *tenantHandler) PatchWorkspaceTemplate(req *restful.Request, resp *restful.Response) {
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
var data json.RawMessage
|
||||
err := request.ReadEntity(&data)
|
||||
err := req.ReadEntity(&data)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
api.HandleBadRequest(resp, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
patched, err := h.tenant.PatchWorkspaceTemplate(workspaceName, data)
|
||||
requestUser, ok := request.UserFrom(req.Request.Context())
|
||||
if !ok {
|
||||
err := fmt.Errorf("cannot obtain user info")
|
||||
klog.Errorln(err)
|
||||
api.HandleForbidden(resp, req, err)
|
||||
}
|
||||
|
||||
patched, err := h.tenant.PatchWorkspaceTemplate(requestUser, workspaceName, data)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
api.HandleNotFound(resp, req, err)
|
||||
return
|
||||
}
|
||||
if errors.IsBadRequest(err) {
|
||||
api.HandleBadRequest(response, request, err)
|
||||
api.HandleBadRequest(resp, req, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleForbidden(resp, req, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(patched)
|
||||
resp.WriteEntity(patched)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListClusters(r *restful.Request, response *restful.Response) {
|
||||
|
||||
@@ -47,12 +47,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MasterLabel = "node-role.kubernetes.io/master"
|
||||
SidecarInject = "sidecar.istio.io/inject"
|
||||
gatewayPrefix = "kubesphere-router-"
|
||||
workingNamespace = "kubesphere-controls-system"
|
||||
globalGatewayname = gatewayPrefix + "kubesphere-system"
|
||||
helmPatch = `{"metadata":{"annotations":{"meta.helm.sh/release-name":"%s-ingress","meta.helm.sh/release-namespace":"%s"},"labels":{"helm.sh/chart":"ingress-nginx-3.35.0","app.kubernetes.io/managed-by":"Helm","app":null,"component":null,"tier":null}},"spec":{"selector":null}}`
|
||||
MasterLabel = "node-role.kubernetes.io/master"
|
||||
SidecarInject = "sidecar.istio.io/inject"
|
||||
gatewayPrefix = "kubesphere-router-"
|
||||
workingNamespace = "kubesphere-controls-system"
|
||||
globalGatewayNameSuffix = "kubesphere-system"
|
||||
globalGatewayName = gatewayPrefix + globalGatewayNameSuffix
|
||||
helmPatch = `{"metadata":{"annotations":{"meta.helm.sh/release-name":"%s-ingress","meta.helm.sh/release-namespace":"%s"},"labels":{"helm.sh/chart":"ingress-nginx-3.35.0","app.kubernetes.io/managed-by":"Helm","app":null,"component":null,"tier":null}},"spec":{"selector":null}}`
|
||||
)
|
||||
|
||||
type GatewayOperator interface {
|
||||
@@ -90,6 +91,10 @@ func (c *gatewayOperator) getWorkingNamespace(namespace string) string {
|
||||
if ns == "" {
|
||||
ns = namespace
|
||||
}
|
||||
// Convert the global gateway query parameter
|
||||
if namespace == globalGatewayNameSuffix {
|
||||
ns = workingNamespace
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
@@ -97,7 +102,7 @@ func (c *gatewayOperator) getWorkingNamespace(namespace string) string {
|
||||
func (c *gatewayOperator) overrideDefaultValue(gateway *v1alpha1.Gateway, namespace string) *v1alpha1.Gateway {
|
||||
// override default name
|
||||
gateway.Name = fmt.Sprint(gatewayPrefix, namespace)
|
||||
if gateway.Name != globalGatewayname {
|
||||
if gateway.Name != globalGatewayName {
|
||||
gateway.Spec.Controller.Scope = v1alpha1.Scope{Enabled: true, Namespace: namespace}
|
||||
}
|
||||
gateway.Namespace = c.getWorkingNamespace(namespace)
|
||||
@@ -108,7 +113,7 @@ func (c *gatewayOperator) overrideDefaultValue(gateway *v1alpha1.Gateway, namesp
|
||||
func (c *gatewayOperator) getGlobalGateway() *v1alpha1.Gateway {
|
||||
globalkey := types.NamespacedName{
|
||||
Namespace: workingNamespace,
|
||||
Name: globalGatewayname,
|
||||
Name: globalGatewayName,
|
||||
}
|
||||
|
||||
global := &v1alpha1.Gateway{}
|
||||
@@ -331,7 +336,7 @@ func (c *gatewayOperator) UpgradeGateway(namespace string) (*v1alpha1.Gateway, e
|
||||
if l == nil {
|
||||
return nil, fmt.Errorf("invalid operation, no legacy gateway was found")
|
||||
}
|
||||
if l.Namespace != c.options.Namespace {
|
||||
if l.Namespace != c.getWorkingNamespace(namespace) {
|
||||
return nil, fmt.Errorf("invalid operation, can't upgrade legacy gateway when working namespace changed")
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ package openpitrix
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
@@ -104,7 +105,7 @@ func newApplicationOperator(cached reposcache.ReposCache, informers externalvers
|
||||
}
|
||||
|
||||
// save icon data and helm application
|
||||
func (c *applicationOperator) createApp(app *v1alpha1.HelmApplication, iconData []byte) (*v1alpha1.HelmApplication, error) {
|
||||
func (c *applicationOperator) createApp(app *v1alpha1.HelmApplication, iconData string) (*v1alpha1.HelmApplication, error) {
|
||||
exists, err := c.getHelmAppByName(app.GetWorkspace(), app.GetTrueName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -112,11 +113,18 @@ func (c *applicationOperator) createApp(app *v1alpha1.HelmApplication, iconData
|
||||
if exists != nil {
|
||||
return nil, appItemExists
|
||||
}
|
||||
|
||||
if len(iconData) != 0 {
|
||||
if strings.HasPrefix(iconData, "http://") || strings.HasPrefix(iconData, "https://") {
|
||||
app.Spec.Icon = iconData
|
||||
} else if len(iconData) != 0 {
|
||||
// save icon attachment
|
||||
iconId := idutils.GetUuid(v1alpha1.HelmAttachmentPrefix)
|
||||
err = c.backingStoreClient.Upload(iconId, iconId, bytes.NewBuffer(iconData), len(iconData))
|
||||
decodeString, err := base64.StdEncoding.DecodeString(iconData)
|
||||
if err != nil {
|
||||
klog.Errorf("decodeString icon failed, error: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.backingStoreClient.Upload(iconId, iconId, bytes.NewBuffer(decodeString), len(iconData))
|
||||
if err != nil {
|
||||
klog.Errorf("save icon attachment failed, error: %s", err)
|
||||
return nil, err
|
||||
@@ -168,6 +176,7 @@ func (c *applicationOperator) ValidatePackage(request *ValidatePackageRequest) (
|
||||
result.VersionName = chrt.GetVersionName()
|
||||
result.Description = chrt.GetDescription()
|
||||
result.URL = chrt.GetUrls()
|
||||
result.Icon = chrt.GetIcon()
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
@@ -46,7 +46,7 @@ type openpitrixOperator struct {
|
||||
CategoryInterface
|
||||
}
|
||||
|
||||
func NewOpenpitrixOperator(ksInformers ks_informers.InformerFactory, ksClient versioned.Interface, s3Client s3.Interface, cc clusterclient.ClusterClients, stopCh <-chan struct{}) Interface {
|
||||
func NewOpenpitrixOperator(ksInformers ks_informers.InformerFactory, ksClient versioned.Interface, s3Client s3.Interface, cc clusterclient.ClusterClients) Interface {
|
||||
klog.Infof("start helm repo informer")
|
||||
cachedReposData := reposcache.NewReposCache()
|
||||
helmReposInformer := ksInformers.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmRepos().Informer()
|
||||
|
||||
@@ -302,7 +302,7 @@ func (c *repoOperator) ListRepos(conditions *params.Conditions, orderBy string,
|
||||
start, end := (&query.Pagination{Limit: limit, Offset: offset}).GetValidPagination(totalCount)
|
||||
repos = repos[start:end]
|
||||
items := make([]interface{}, 0, len(repos))
|
||||
for i, j := offset, 0; i < len(repos) && j < limit; i, j = i+1, j+1 {
|
||||
for i := range repos {
|
||||
items = append(items, convertRepo(repos[i]))
|
||||
}
|
||||
return &models.PageableResponse{Items: items, TotalCount: totalCount}, nil
|
||||
|
||||
@@ -288,7 +288,7 @@ type AppVersionReview struct {
|
||||
type CreateAppRequest struct {
|
||||
|
||||
// app icon
|
||||
Icon strfmt.Base64 `json:"icon,omitempty"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
|
||||
// isv
|
||||
Isv string `json:"isv,omitempty"`
|
||||
@@ -413,6 +413,8 @@ type ValidatePackageResponse struct {
|
||||
|
||||
// app version name.eg.[0.1.0]
|
||||
VersionName string `json:"version_name,omitempty"`
|
||||
|
||||
Icon string `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
type CreateAppVersionRequest struct {
|
||||
@@ -713,7 +715,7 @@ type Repo struct {
|
||||
// selectors
|
||||
Selectors RepoSelectors `json:"selectors"`
|
||||
|
||||
// status eg.[active|deleted]
|
||||
// status eg.[successful|failed|syncing]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
|
||||
@@ -399,6 +399,7 @@ func convertAppVersion(in *v1alpha1.HelmApplicationVersion) *AppVersion {
|
||||
if in.Spec.Metadata != nil {
|
||||
out.Description = in.Spec.Description
|
||||
out.Icon = in.Spec.Icon
|
||||
out.Home = in.Spec.Home
|
||||
}
|
||||
|
||||
// The field Maintainers and Sources were a string field, so I encode the helm field's maintainers and sources,
|
||||
@@ -431,6 +432,10 @@ func convertRepo(in *v1alpha1.HelmRepo) *Repo {
|
||||
out.Name = in.GetTrueName()
|
||||
|
||||
out.Status = in.Status.State
|
||||
// set default status `syncing` when helmrepo not reconcile yet
|
||||
if out.Status == "" {
|
||||
out.Status = v1alpha1.RepoStateSyncing
|
||||
}
|
||||
date := strfmt.DateTime(time.Unix(in.CreationTimestamp.Unix(), 0))
|
||||
out.CreateTime = &date
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ limitations under the License.
|
||||
package pod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -31,7 +34,13 @@ const (
|
||||
fieldNodeName = "nodeName"
|
||||
fieldPVCName = "pvcName"
|
||||
fieldServiceName = "serviceName"
|
||||
fieldPhase = "phase"
|
||||
fieldStatus = "status"
|
||||
|
||||
statusTypeWaitting = "Waiting"
|
||||
statusTypeRunning = "Running"
|
||||
statusTypeError = "Error"
|
||||
statusTypeCompleted = "Completed"
|
||||
)
|
||||
|
||||
type podsGetter struct {
|
||||
@@ -90,6 +99,9 @@ func (p *podsGetter) filter(object runtime.Object, filter query.Filter) bool {
|
||||
case fieldServiceName:
|
||||
return p.podBelongToService(pod, string(filter.Value))
|
||||
case fieldStatus:
|
||||
_, statusType := p.getPodStatus(pod)
|
||||
return statusType == string(filter.Value)
|
||||
case fieldPhase:
|
||||
return string(pod.Status.Phase) == string(filter.Value)
|
||||
default:
|
||||
return v1alpha3.DefaultObjectMetaFilter(pod.ObjectMeta, filter)
|
||||
@@ -117,3 +129,133 @@ func (p *podsGetter) podBelongToService(item *corev1.Pod, serviceName string) bo
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// getPodStatus refer to `kubectl get po` result.
|
||||
// https://github.com/kubernetes/kubernetes/blob/45279654db87f4908911569c07afc42804f0e246/pkg/printers/internalversion/printers.go#L820-920
|
||||
// podStatusPhase = []string("Pending", "Running","Succeeded","Failed","Unknown")
|
||||
// podStatusReasons = []string{"Evicted", "NodeAffinity", "NodeLost", "Shutdown", "UnexpectedAdmissionError"}
|
||||
// containerWaitingReasons = []string{"ContainerCreating", "CrashLoopBackOff", "CreateContainerConfigError", "ErrImagePull", "ImagePullBackOff", "CreateContainerError", "InvalidImageName"}
|
||||
// containerTerminatedReasons = []string{"OOMKilled", "Completed", "Error", "ContainerCannotRun", "DeadlineExceeded", "Evicted"}
|
||||
func (p *podsGetter) getPodStatus(pod *corev1.Pod) (string, string) {
|
||||
reason := string(pod.Status.Phase)
|
||||
|
||||
if pod.Status.Reason != "" {
|
||||
reason = pod.Status.Reason
|
||||
}
|
||||
|
||||
/*
|
||||
todo: upgrade k8s.io/api version
|
||||
|
||||
// If the Pod carries {type:PodScheduled, reason:WaitingForGates}, set reason to 'SchedulingGated'.
|
||||
for _, condition := range pod.Status.Conditions {
|
||||
if condition.Type == corev1.PodScheduled && condition.Reason == corev1.PodReasonSchedulingGated {
|
||||
reason = corev1.PodReasonSchedulingGated
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
initializing := false
|
||||
for i := range pod.Status.InitContainerStatuses {
|
||||
container := pod.Status.InitContainerStatuses[i]
|
||||
|
||||
switch {
|
||||
case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
|
||||
continue
|
||||
case container.State.Terminated != nil:
|
||||
// initialization is failed
|
||||
if len(container.State.Terminated.Reason) == 0 {
|
||||
if container.State.Terminated.Signal != 0 {
|
||||
reason = fmt.Sprintf("Init:Signal:%d", container.State.Terminated.Signal)
|
||||
} else {
|
||||
reason = fmt.Sprintf("Init:ExitCode:%d", container.State.Terminated.ExitCode)
|
||||
}
|
||||
} else {
|
||||
reason = "Init:" + container.State.Terminated.Reason
|
||||
}
|
||||
initializing = true
|
||||
case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing":
|
||||
reason = "Init:" + container.State.Waiting.Reason
|
||||
initializing = true
|
||||
default:
|
||||
reason = fmt.Sprintf("Init:%d/%d", i, len(pod.Spec.InitContainers))
|
||||
initializing = true
|
||||
}
|
||||
break
|
||||
}
|
||||
if !initializing {
|
||||
|
||||
hasRunning := false
|
||||
for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
|
||||
container := pod.Status.ContainerStatuses[i]
|
||||
|
||||
if container.State.Waiting != nil && container.State.Waiting.Reason != "" {
|
||||
reason = container.State.Waiting.Reason
|
||||
} else if container.State.Terminated != nil && container.State.Terminated.Reason != "" {
|
||||
reason = container.State.Terminated.Reason
|
||||
} else if container.State.Terminated != nil && container.State.Terminated.Reason == "" {
|
||||
if container.State.Terminated.Signal != 0 {
|
||||
reason = fmt.Sprintf("Signal:%d", container.State.Terminated.Signal)
|
||||
} else {
|
||||
reason = fmt.Sprintf("ExitCode:%d", container.State.Terminated.ExitCode)
|
||||
}
|
||||
} else if container.Ready && container.State.Running != nil {
|
||||
hasRunning = true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// change pod status back to "Running" if there is at least one container still reporting as "Running" status
|
||||
if reason == "Completed" && hasRunning {
|
||||
if hasPodReadyCondition(pod.Status.Conditions) {
|
||||
reason = "Running"
|
||||
} else {
|
||||
reason = "NotReady"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pod.DeletionTimestamp != nil && pod.Status.Reason == "NodeLost" {
|
||||
reason = "Unknown"
|
||||
} else if pod.DeletionTimestamp != nil {
|
||||
reason = "Terminating"
|
||||
}
|
||||
|
||||
statusType := statusTypeWaitting
|
||||
switch reason {
|
||||
case "Running":
|
||||
statusType = statusTypeRunning
|
||||
case "Failed":
|
||||
statusType = statusTypeError
|
||||
case "Error":
|
||||
statusType = statusTypeError
|
||||
case "Completed":
|
||||
statusType = statusTypeCompleted
|
||||
case "Succeeded":
|
||||
if isPodReadyConditionReason(pod.Status.Conditions, "PodCompleted") {
|
||||
statusType = statusTypeCompleted
|
||||
}
|
||||
default:
|
||||
if strings.HasPrefix(reason, "OutOf") {
|
||||
statusType = statusTypeError
|
||||
}
|
||||
}
|
||||
return reason, statusType
|
||||
}
|
||||
|
||||
func hasPodReadyCondition(conditions []corev1.PodCondition) bool {
|
||||
for _, condition := range conditions {
|
||||
if condition.Type == corev1.PodReady && condition.Status == corev1.ConditionTrue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isPodReadyConditionReason(conditions []corev1.PodCondition, reason string) bool {
|
||||
for _, condition := range conditions {
|
||||
if condition.Type == corev1.PodReady && condition.Reason != reason {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func TestListPods(t *testing.T) {
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"test status filter",
|
||||
"test phase filter",
|
||||
"default",
|
||||
&query.Query{
|
||||
Pagination: &query.Pagination{
|
||||
@@ -89,7 +89,7 @@ func TestListPods(t *testing.T) {
|
||||
Ascending: false,
|
||||
Filters: map[query.Field]query.Value{
|
||||
query.FieldNamespace: query.Value("default"),
|
||||
fieldStatus: query.Value(corev1.PodRunning),
|
||||
fieldPhase: query.Value(corev1.PodRunning),
|
||||
},
|
||||
},
|
||||
&api.ListResult{
|
||||
@@ -163,6 +163,7 @@ var (
|
||||
Phase: corev1.PodRunning,
|
||||
},
|
||||
}
|
||||
|
||||
pods = []interface{}{foo1, foo2, foo3, foo4, foo5}
|
||||
)
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@@ -69,6 +71,8 @@ import (
|
||||
loggingclient "kubesphere.io/kubesphere/pkg/simple/client/logging"
|
||||
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
|
||||
monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
"kubesphere.io/kubesphere/pkg/utils/clusterclient"
|
||||
jsonpatchutil "kubesphere.io/kubesphere/pkg/utils/josnpatchutil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/stringutils"
|
||||
)
|
||||
|
||||
@@ -78,10 +82,10 @@ type Interface interface {
|
||||
ListWorkspaces(user user.Info, queryParam *query.Query) (*api.ListResult, error)
|
||||
GetWorkspace(workspace string) (*tenantv1alpha1.Workspace, error)
|
||||
ListWorkspaceTemplates(user user.Info, query *query.Query) (*api.ListResult, error)
|
||||
CreateWorkspaceTemplate(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error)
|
||||
CreateWorkspaceTemplate(user user.Info, workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error)
|
||||
DeleteWorkspaceTemplate(workspace string, opts metav1.DeleteOptions) error
|
||||
UpdateWorkspaceTemplate(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error)
|
||||
PatchWorkspaceTemplate(workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error)
|
||||
UpdateWorkspaceTemplate(user user.Info, workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error)
|
||||
PatchWorkspaceTemplate(user user.Info, workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error)
|
||||
DescribeWorkspaceTemplate(workspace string) (*tenantv1alpha2.WorkspaceTemplate, error)
|
||||
ListNamespaces(user user.Info, workspace string, query *query.Query) (*api.ListResult, error)
|
||||
ListDevOpsProjects(user user.Info, workspace string, query *query.Query) (*api.ListResult, error)
|
||||
@@ -117,6 +121,7 @@ type tenantOperator struct {
|
||||
auditing auditing.Interface
|
||||
mo monitoring.MonitoringOperator
|
||||
opRelease openpitrix.ReleaseInterface
|
||||
clusterClient clusterclient.ClusterClients
|
||||
}
|
||||
|
||||
func New(informers informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, evtsClient eventsclient.Client, loggingClient loggingclient.Client, auditingclient auditingclient.Client, am am.AccessManagementInterface, im im.IdentityManagementInterface, authorizer authorizer.Authorizer, monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, opClient openpitrix.Interface) Interface {
|
||||
@@ -132,6 +137,7 @@ func New(informers informers.InformerFactory, k8sclient kubernetes.Interface, ks
|
||||
auditing: auditing.NewEventsOperator(auditingclient),
|
||||
mo: monitoring.NewMonitoringOperator(monitoringclient, nil, k8sclient, informers, resourceGetter, nil),
|
||||
opRelease: opClient,
|
||||
clusterClient: clusterclient.NewClusterClient(informers.KubeSphereSharedInformerFactory().Cluster().V1alpha1().Clusters()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,15 +476,111 @@ func (t *tenantOperator) PatchNamespace(workspace string, namespace *corev1.Name
|
||||
return t.k8sclient.CoreV1().Namespaces().Patch(context.Background(), namespace.Name, types.MergePatchType, data, metav1.PatchOptions{})
|
||||
}
|
||||
|
||||
func (t *tenantOperator) PatchWorkspaceTemplate(workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error) {
|
||||
return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Patch(context.Background(), workspace, types.MergePatchType, data, metav1.PatchOptions{})
|
||||
func (t *tenantOperator) PatchWorkspaceTemplate(user user.Info, workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error) {
|
||||
var manageWorkspaceTemplateRequest bool
|
||||
clusterNames := sets.NewString()
|
||||
|
||||
patchs, err := jsonpatchutil.Parse(data)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(patchs) > 0 {
|
||||
for _, patch := range patchs {
|
||||
path, err := patch.Path()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the request path is cluster, just collecting cluster name to set and continue to check cluster permission later.
|
||||
// Or indicate that want to manage the workspace templates, so check if user has the permission to manage workspace templates.
|
||||
if strings.HasPrefix(path, "/spec/placement") {
|
||||
if patch.Kind() != "add" && patch.Kind() != "remove" {
|
||||
err := errors.NewBadRequest("not support operation type")
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
clusterValue := make(map[string]interface{})
|
||||
err := jsonpatchutil.GetValue(patch, &clusterValue)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if the placement is empty, the first patch need fill with "clusters" field.
|
||||
if cName := clusterValue["name"]; cName != nil {
|
||||
cn, ok := cName.(string)
|
||||
if ok {
|
||||
clusterNames.Insert(cn)
|
||||
}
|
||||
} else if cluster := clusterValue["clusters"]; cluster != nil {
|
||||
clusterRefrences := []typesv1beta1.GenericClusterReference{}
|
||||
err := mapstructure.Decode(cluster, &clusterRefrences)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range clusterRefrences {
|
||||
clusterNames.Insert(v.Name)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
manageWorkspaceTemplateRequest = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if manageWorkspaceTemplateRequest {
|
||||
err := t.checkWorkspaceTemplatePermission(user, workspace)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if clusterNames.Len() > 0 {
|
||||
err := t.checkClusterPermission(user, clusterNames.List())
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Patch(context.Background(), workspace, types.JSONPatchType, data, metav1.PatchOptions{})
|
||||
}
|
||||
|
||||
func (t *tenantOperator) CreateWorkspaceTemplate(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) {
|
||||
func (t *tenantOperator) CreateWorkspaceTemplate(user user.Info, workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) {
|
||||
if len(workspace.Spec.Placement.Clusters) != 0 {
|
||||
clusters := make([]string, 0)
|
||||
for _, v := range workspace.Spec.Placement.Clusters {
|
||||
clusters = append(clusters, v.Name)
|
||||
}
|
||||
err := t.checkClusterPermission(user, clusters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Create(context.Background(), workspace, metav1.CreateOptions{})
|
||||
}
|
||||
|
||||
func (t *tenantOperator) UpdateWorkspaceTemplate(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) {
|
||||
func (t *tenantOperator) UpdateWorkspaceTemplate(user user.Info, workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) {
|
||||
if len(workspace.Spec.Placement.Clusters) != 0 {
|
||||
clusters := make([]string, 0)
|
||||
for _, v := range workspace.Spec.Placement.Clusters {
|
||||
clusters = append(clusters, v.Name)
|
||||
}
|
||||
err := t.checkClusterPermission(user, clusters)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
return t.ksclient.TenantV1alpha2().WorkspaceTemplates().Update(context.Background(), workspace, metav1.UpdateOptions{})
|
||||
}
|
||||
|
||||
@@ -1081,6 +1183,16 @@ func (t *tenantOperator) MeteringHierarchy(user user.Info, queryParam *meteringv
|
||||
return resourceStats, nil
|
||||
}
|
||||
|
||||
func (t *tenantOperator) getClusterRoleBindingsByUser(clusterName, user string) (*rbacv1.ClusterRoleBindingList, error) {
|
||||
kubernetesClientSet, err := t.clusterClient.GetKubernetesClientSet(clusterName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kubernetesClientSet.RbacV1().ClusterRoleBindings().
|
||||
List(context.Background(),
|
||||
metav1.ListOptions{LabelSelector: labels.FormatLabels(map[string]string{"iam.kubesphere.io/user-ref": user})})
|
||||
}
|
||||
|
||||
func contains(objects []runtime.Object, object runtime.Object) bool {
|
||||
for _, item := range objects {
|
||||
if item == object {
|
||||
@@ -1106,3 +1218,78 @@ func stringContains(str string, subStrs []string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *tenantOperator) checkWorkspaceTemplatePermission(user user.Info, workspace string) error {
|
||||
deleteWST := authorizer.AttributesRecord{
|
||||
User: user,
|
||||
Verb: authorizer.VerbDelete,
|
||||
APIGroup: tenantv1alpha2.SchemeGroupVersion.Group,
|
||||
APIVersion: tenantv1alpha2.SchemeGroupVersion.Version,
|
||||
Resource: tenantv1alpha2.ResourcePluralWorkspaceTemplate,
|
||||
ResourceRequest: true,
|
||||
ResourceScope: request.GlobalScope,
|
||||
}
|
||||
authorize, reason, err := t.authorizer.Authorize(deleteWST)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if authorize != authorizer.DecisionAllow {
|
||||
return errors.NewForbidden(tenantv1alpha2.Resource(tenantv1alpha2.ResourcePluralWorkspaceTemplate), workspace, fmt.Errorf(reason))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *tenantOperator) checkClusterPermission(user user.Info, clusters []string) error {
|
||||
// Checking whether the user can manage the cluster requires authentication from two aspects.
|
||||
// First check whether the user has relevant global permissions,
|
||||
// and then check whether the user has relevant cluster permissions in the target cluster
|
||||
|
||||
for _, clusterName := range clusters {
|
||||
|
||||
cluster, err := t.ksclient.ClusterV1alpha1().Clusters().Get(context.Background(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cluster.Labels["cluster.kubesphere.io/visibility"] == "public" {
|
||||
continue
|
||||
}
|
||||
|
||||
deleteCluster := authorizer.AttributesRecord{
|
||||
User: user,
|
||||
Verb: authorizer.VerbDelete,
|
||||
APIGroup: clusterv1alpha1.SchemeGroupVersion.Group,
|
||||
APIVersion: clusterv1alpha1.SchemeGroupVersion.Version,
|
||||
Resource: clusterv1alpha1.ResourcesPluralCluster,
|
||||
Cluster: clusterName,
|
||||
ResourceRequest: true,
|
||||
ResourceScope: request.GlobalScope,
|
||||
}
|
||||
authorize, _, err := t.authorizer.Authorize(deleteCluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if authorize == authorizer.DecisionAllow {
|
||||
continue
|
||||
}
|
||||
|
||||
list, err := t.getClusterRoleBindingsByUser(clusterName, user.GetName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allowed := false
|
||||
for _, clusterRolebinding := range list.Items {
|
||||
if clusterRolebinding.RoleRef.Name == iamv1alpha2.ClusterAdmin {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !allowed {
|
||||
return errors.NewForbidden(clusterv1alpha1.Resource(clusterv1alpha1.ResourcesPluralCluster), clusterName, fmt.Errorf("user is not allowed to use the cluster %s", clusterName))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ import (
|
||||
const (
|
||||
// Time allowed to write a message to the peer.
|
||||
writeWait = 10 * time.Second
|
||||
// ctrl+d to close terminal.
|
||||
endOfTransmission = "\u0004"
|
||||
)
|
||||
|
||||
// PtyHandler is what remotecommand expects from a pty
|
||||
@@ -76,7 +78,7 @@ type TerminalMessage struct {
|
||||
Rows, Cols uint16
|
||||
}
|
||||
|
||||
// TerminalSize handles pty->process resize events
|
||||
// Next handles pty->process resize events
|
||||
// Called in a loop from remotecommand as long as the process is running
|
||||
func (t TerminalSession) Next() *remotecommand.TerminalSize {
|
||||
select {
|
||||
@@ -95,7 +97,7 @@ func (t TerminalSession) Read(p []byte) (int, error) {
|
||||
var msg TerminalMessage
|
||||
err := t.conn.ReadJSON(&msg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return copy(p, endOfTransmission), err
|
||||
}
|
||||
|
||||
switch msg.Op {
|
||||
@@ -105,7 +107,7 @@ func (t TerminalSession) Read(p []byte) (int, error) {
|
||||
t.sizeChan <- remotecommand.TerminalSize{Width: msg.Cols, Height: msg.Rows}
|
||||
return 0, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown message type '%s'", msg.Op)
|
||||
return copy(p, endOfTransmission), fmt.Errorf("unknown message type '%s'", msg.Op)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +217,7 @@ func (n *NodeTerminaler) getNSEnterPod() (*v1.Pod, error) {
|
||||
pod, err := n.client.CoreV1().Pods(n.Namespace).Get(context.Background(), n.PodName, metav1.GetOptions{})
|
||||
|
||||
if err != nil || (pod.Status.Phase != v1.PodRunning && pod.Status.Phase != v1.PodPending) {
|
||||
//pod has timed out, but has not been cleaned up
|
||||
// pod has timed out, but has not been cleaned up
|
||||
if pod.Status.Phase == v1.PodSucceeded || pod.Status.Phase == v1.PodFailed {
|
||||
err := n.client.CoreV1().Pods(n.Namespace).Delete(context.Background(), n.PodName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
@@ -328,7 +330,7 @@ func isValidShell(validShells []string, shell string) bool {
|
||||
|
||||
func (t *terminaler) HandleSession(shell, namespace, podName, containerName string, conn *websocket.Conn) {
|
||||
var err error
|
||||
validShells := []string{"sh", "bash"}
|
||||
validShells := []string{"bash", "sh"}
|
||||
|
||||
session := &TerminalSession{conn: conn, sizeChan: make(chan remotecommand.TerminalSize)}
|
||||
|
||||
|
||||
41
pkg/simple/client/cache/cache.go
vendored
41
pkg/simple/client/cache/cache.go
vendored
@@ -16,7 +16,17 @@ limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
var (
|
||||
cacheFactories = make(map[string]CacheFactory)
|
||||
)
|
||||
|
||||
var NeverExpire = time.Duration(0)
|
||||
|
||||
@@ -39,3 +49,32 @@ type Interface interface {
|
||||
// Expires updates object's expiration time, return err if key doesn't exist
|
||||
Expire(key string, duration time.Duration) error
|
||||
}
|
||||
|
||||
// DynamicOptions the options of the cache. For redis, options key can be "host", "port", "db", "password".
|
||||
// For InMemoryCache, options key can be "cleanupperiod"
|
||||
type DynamicOptions map[string]interface{}
|
||||
|
||||
func (o DynamicOptions) MarshalJSON() ([]byte, error) {
|
||||
|
||||
data, err := json.Marshal(o)
|
||||
return data, err
|
||||
}
|
||||
|
||||
func RegisterCacheFactory(factory CacheFactory) {
|
||||
cacheFactories[factory.Type()] = factory
|
||||
}
|
||||
|
||||
func New(option *Options, stopCh <-chan struct{}) (Interface, error) {
|
||||
if cacheFactories[option.Type] == nil {
|
||||
err := fmt.Errorf("cache with type %s is not supported", option.Type)
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cache, err := cacheFactories[option.Type].Create(option.Options, stopCh)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to create cache, error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
8
pkg/simple/client/cache/factory.go
vendored
Normal file
8
pkg/simple/client/cache/factory.go
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
package cache
|
||||
|
||||
type CacheFactory interface {
|
||||
// Type unique type of the cache
|
||||
Type() string
|
||||
// Create relevant caches by type
|
||||
Create(options DynamicOptions, stopCh <-chan struct{}) (Interface, error)
|
||||
}
|
||||
200
pkg/simple/client/cache/inmemory_cache.go
vendored
Normal file
200
pkg/simple/client/cache/inmemory_cache.go
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
Copyright 2019 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 cache
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
)
|
||||
|
||||
var ErrNoSuchKey = errors.New("no such key")
|
||||
|
||||
const (
|
||||
typeInMemoryCache = "InMemoryCache"
|
||||
DefaultCacheType = typeInMemoryCache
|
||||
|
||||
defaultCleanupPeriod = 2 * time.Hour
|
||||
)
|
||||
|
||||
type simpleObject struct {
|
||||
value string
|
||||
neverExpire bool
|
||||
expiredAt time.Time
|
||||
}
|
||||
|
||||
func (so *simpleObject) IsExpired() bool {
|
||||
if so.neverExpire {
|
||||
return false
|
||||
}
|
||||
if time.Now().After(so.expiredAt) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InMemoryCacheOptions used to create inMemoryCache in memory.
|
||||
// CleanupPeriod specifies cleans up expired token every period.
|
||||
// Note the SimpleCache cannot be used in multi-replicas apiserver,
|
||||
// which will lead to data inconsistency.
|
||||
type InMemoryCacheOptions struct {
|
||||
CleanupPeriod time.Duration `json:"cleanupPeriod" yaml:"cleanupPeriod" mapstructure:"cleanupperiod"`
|
||||
}
|
||||
|
||||
// imMemoryCache implements cache.Interface use memory objects, it should be used only for testing
|
||||
type inMemoryCache struct {
|
||||
store map[string]simpleObject
|
||||
}
|
||||
|
||||
func NewInMemoryCache(options *InMemoryCacheOptions, stopCh <-chan struct{}) (Interface, error) {
|
||||
var cleanupPeriod time.Duration
|
||||
cache := &inMemoryCache{
|
||||
store: make(map[string]simpleObject),
|
||||
}
|
||||
|
||||
if options == nil || options.CleanupPeriod == 0 {
|
||||
cleanupPeriod = defaultCleanupPeriod
|
||||
} else {
|
||||
cleanupPeriod = options.CleanupPeriod
|
||||
}
|
||||
go wait.Until(cache.cleanInvalidToken, cleanupPeriod, stopCh)
|
||||
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
func (s *inMemoryCache) cleanInvalidToken() {
|
||||
for k, v := range s.store {
|
||||
if v.IsExpired() {
|
||||
delete(s.store, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *inMemoryCache) Keys(pattern string) ([]string, error) {
|
||||
// There is a little difference between go regexp and redis key pattern
|
||||
// In redis, * means any character, while in go . means match everything.
|
||||
pattern = strings.Replace(pattern, "*", ".", -1)
|
||||
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var keys []string
|
||||
for k := range s.store {
|
||||
if re.MatchString(k) {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (s *inMemoryCache) Set(key string, value string, duration time.Duration) error {
|
||||
sobject := simpleObject{
|
||||
value: value,
|
||||
neverExpire: false,
|
||||
expiredAt: time.Now().Add(duration),
|
||||
}
|
||||
|
||||
if duration == NeverExpire {
|
||||
sobject.neverExpire = true
|
||||
}
|
||||
|
||||
s.store[key] = sobject
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *inMemoryCache) Del(keys ...string) error {
|
||||
for _, key := range keys {
|
||||
delete(s.store, key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *inMemoryCache) Get(key string) (string, error) {
|
||||
if sobject, ok := s.store[key]; ok {
|
||||
if sobject.neverExpire || time.Now().Before(sobject.expiredAt) {
|
||||
return sobject.value, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", ErrNoSuchKey
|
||||
}
|
||||
|
||||
func (s *inMemoryCache) Exists(keys ...string) (bool, error) {
|
||||
for _, key := range keys {
|
||||
if _, ok := s.store[key]; !ok {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *inMemoryCache) Expire(key string, duration time.Duration) error {
|
||||
value, err := s.Get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sobject := simpleObject{
|
||||
value: value,
|
||||
neverExpire: false,
|
||||
expiredAt: time.Now().Add(duration),
|
||||
}
|
||||
|
||||
if duration == NeverExpire {
|
||||
sobject.neverExpire = true
|
||||
}
|
||||
|
||||
s.store[key] = sobject
|
||||
return nil
|
||||
}
|
||||
|
||||
type inMemoryCacheFactory struct {
|
||||
}
|
||||
|
||||
func (sf *inMemoryCacheFactory) Type() string {
|
||||
return typeInMemoryCache
|
||||
}
|
||||
|
||||
func (sf *inMemoryCacheFactory) Create(options DynamicOptions, stopCh <-chan struct{}) (Interface, error) {
|
||||
var sOptions InMemoryCacheOptions
|
||||
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
|
||||
WeaklyTypedInput: true,
|
||||
Result: &sOptions,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := decoder.Decode(options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewInMemoryCache(&sOptions, stopCh)
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterCacheFactory(&inMemoryCacheFactory{})
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func TestDeleteAndExpireCache(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
cacheClient := NewSimpleCache()
|
||||
cacheClient, _ := NewInMemoryCache(nil, nil)
|
||||
|
||||
t.Run(testCase.description, func(t *testing.T) {
|
||||
err := load(cacheClient, dataSet)
|
||||
33
pkg/simple/client/cache/options.go
vendored
33
pkg/simple/client/cache/options.go
vendored
@@ -18,25 +18,19 @@ package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Host string `json:"host" yaml:"host"`
|
||||
Port int `json:"port" yaml:"port"`
|
||||
Password string `json:"password" yaml:"password"`
|
||||
DB int `json:"db" yaml:"db"`
|
||||
Type string `json:"type"`
|
||||
Options DynamicOptions `json:"options"`
|
||||
}
|
||||
|
||||
// NewRedisOptions returns options points to nowhere,
|
||||
// NewCacheOptions returns options points to nowhere,
|
||||
// because redis is not required for some components
|
||||
func NewRedisOptions() *Options {
|
||||
func NewCacheOptions() *Options {
|
||||
return &Options{
|
||||
Host: "",
|
||||
Port: 0,
|
||||
Password: "",
|
||||
DB: 0,
|
||||
Type: "",
|
||||
Options: map[string]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,20 +38,9 @@ func NewRedisOptions() *Options {
|
||||
func (r *Options) Validate() []error {
|
||||
errors := make([]error, 0)
|
||||
|
||||
if r.Port == 0 {
|
||||
errors = append(errors, fmt.Errorf("invalid service port number"))
|
||||
if r.Type == "" {
|
||||
errors = append(errors, fmt.Errorf("invalid cache type"))
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
// AddFlags add option flags to command line flags,
|
||||
// if redis-host left empty, the following options will be ignored.
|
||||
func (r *Options) AddFlags(fs *pflag.FlagSet, s *Options) {
|
||||
fs.StringVar(&r.Host, "redis-host", s.Host, "Redis connection URL. If left blank, means redis is unnecessary, "+
|
||||
"redis will be disabled.")
|
||||
|
||||
fs.IntVar(&r.Port, "redis-port", s.Port, "")
|
||||
fs.StringVar(&r.Password, "redis-password", s.Password, "")
|
||||
fs.IntVar(&r.DB, "redis-db", s.DB, "")
|
||||
}
|
||||
|
||||
58
pkg/simple/client/cache/redis.go
vendored
58
pkg/simple/client/cache/redis.go
vendored
@@ -17,19 +17,31 @@ limitations under the License.
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
const typeRedis = "redis"
|
||||
|
||||
type redisClient struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func NewRedisClient(option *Options, stopCh <-chan struct{}) (Interface, error) {
|
||||
var r Client
|
||||
// redisOptions used to create a redis client.
|
||||
type redisOptions struct {
|
||||
Host string `json:"host" yaml:"host" mapstructure:"host"`
|
||||
Port int `json:"port" yaml:"port" mapstructure:"port"`
|
||||
Password string `json:"password" yaml:"password" mapstructure:"password"`
|
||||
DB int `json:"db" yaml:"db" mapstructure:"db"`
|
||||
}
|
||||
|
||||
func NewRedisClient(option *redisOptions, stopCh <-chan struct{}) (Interface, error) {
|
||||
var r redisClient
|
||||
|
||||
redisOptions := &redis.Options{
|
||||
Addr: fmt.Sprintf("%s:%d", option.Host, option.Port),
|
||||
@@ -61,23 +73,23 @@ func NewRedisClient(option *Options, stopCh <-chan struct{}) (Interface, error)
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func (r *Client) Get(key string) (string, error) {
|
||||
func (r *redisClient) Get(key string) (string, error) {
|
||||
return r.client.Get(key).Result()
|
||||
}
|
||||
|
||||
func (r *Client) Keys(pattern string) ([]string, error) {
|
||||
func (r *redisClient) Keys(pattern string) ([]string, error) {
|
||||
return r.client.Keys(pattern).Result()
|
||||
}
|
||||
|
||||
func (r *Client) Set(key string, value string, duration time.Duration) error {
|
||||
func (r *redisClient) Set(key string, value string, duration time.Duration) error {
|
||||
return r.client.Set(key, value, duration).Err()
|
||||
}
|
||||
|
||||
func (r *Client) Del(keys ...string) error {
|
||||
func (r *redisClient) Del(keys ...string) error {
|
||||
return r.client.Del(keys...).Err()
|
||||
}
|
||||
|
||||
func (r *Client) Exists(keys ...string) (bool, error) {
|
||||
func (r *redisClient) Exists(keys ...string) (bool, error) {
|
||||
existedKeys, err := r.client.Exists(keys...).Result()
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -86,6 +98,34 @@ func (r *Client) Exists(keys ...string) (bool, error) {
|
||||
return len(keys) == int(existedKeys), nil
|
||||
}
|
||||
|
||||
func (r *Client) Expire(key string, duration time.Duration) error {
|
||||
func (r *redisClient) Expire(key string, duration time.Duration) error {
|
||||
return r.client.Expire(key, duration).Err()
|
||||
}
|
||||
|
||||
type redisFactory struct{}
|
||||
|
||||
func (rf *redisFactory) Type() string {
|
||||
return typeRedis
|
||||
}
|
||||
|
||||
func (rf *redisFactory) Create(options DynamicOptions, stopCh <-chan struct{}) (Interface, error) {
|
||||
var rOptions redisOptions
|
||||
if err := mapstructure.Decode(options, &rOptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rOptions.Port == 0 {
|
||||
return nil, errors.New("invalid service port number")
|
||||
}
|
||||
if len(rOptions.Host) == 0 {
|
||||
return nil, errors.New("invalid service host")
|
||||
}
|
||||
client, err := NewRedisClient(&rOptions, stopCh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterCacheFactory(&redisFactory{})
|
||||
}
|
||||
|
||||
123
pkg/simple/client/cache/simple_cache.go
vendored
123
pkg/simple/client/cache/simple_cache.go
vendored
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 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 cache
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
)
|
||||
|
||||
var ErrNoSuchKey = errors.New("no such key")
|
||||
|
||||
type simpleObject struct {
|
||||
value string
|
||||
neverExpire bool
|
||||
expiredAt time.Time
|
||||
}
|
||||
|
||||
// SimpleCache implements cache.Interface use memory objects, it should be used only for testing
|
||||
type simpleCache struct {
|
||||
store map[string]simpleObject
|
||||
}
|
||||
|
||||
func NewSimpleCache() Interface {
|
||||
return &simpleCache{store: make(map[string]simpleObject)}
|
||||
}
|
||||
|
||||
func (s *simpleCache) Keys(pattern string) ([]string, error) {
|
||||
// There is a little difference between go regexp and redis key pattern
|
||||
// In redis, * means any character, while in go . means match everything.
|
||||
pattern = strings.Replace(pattern, "*", ".", -1)
|
||||
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var keys []string
|
||||
for k := range s.store {
|
||||
if re.MatchString(k) {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (s *simpleCache) Set(key string, value string, duration time.Duration) error {
|
||||
sobject := simpleObject{
|
||||
value: value,
|
||||
neverExpire: false,
|
||||
expiredAt: time.Now().Add(duration),
|
||||
}
|
||||
|
||||
if duration == NeverExpire {
|
||||
sobject.neverExpire = true
|
||||
}
|
||||
|
||||
s.store[key] = sobject
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *simpleCache) Del(keys ...string) error {
|
||||
for _, key := range keys {
|
||||
delete(s.store, key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *simpleCache) Get(key string) (string, error) {
|
||||
if sobject, ok := s.store[key]; ok {
|
||||
if sobject.neverExpire || time.Now().Before(sobject.expiredAt) {
|
||||
return sobject.value, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", ErrNoSuchKey
|
||||
}
|
||||
|
||||
func (s *simpleCache) Exists(keys ...string) (bool, error) {
|
||||
for _, key := range keys {
|
||||
if _, ok := s.store[key]; !ok {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *simpleCache) Expire(key string, duration time.Duration) error {
|
||||
value, err := s.Get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sobject := simpleObject{
|
||||
value: value,
|
||||
neverExpire: false,
|
||||
expiredAt: time.Now().Add(duration),
|
||||
}
|
||||
|
||||
if duration == NeverExpire {
|
||||
sobject.neverExpire = true
|
||||
}
|
||||
|
||||
s.store[key] = sobject
|
||||
return nil
|
||||
}
|
||||
28
pkg/simple/client/es/query/query_test.go
Normal file
28
pkg/simple/client/es/query/query_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQueryBuilder(t *testing.T) {
|
||||
testCase := func() *Query {
|
||||
var mini int32 = 1
|
||||
aaa := NewTerms("aaa", []string{})
|
||||
b := NewBool()
|
||||
b.AppendFilter(NewBool().
|
||||
AppendShould(aaa).
|
||||
WithMinimumShouldMatch(mini))
|
||||
|
||||
return NewQuery().WithBool(b)
|
||||
}
|
||||
|
||||
b := NewBuilder().
|
||||
WithQuery(testCase())
|
||||
|
||||
fmt.Printf("aaaaaa: %+v\n", b)
|
||||
_, err := b.Bytes()
|
||||
if err != nil {
|
||||
t.Fatalf("err jsoniter.Marshal: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,11 @@ func TestClient_Get(t *testing.T) {
|
||||
type args struct {
|
||||
url string
|
||||
}
|
||||
|
||||
inMemoryCache, err := cache.NewInMemoryCache(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
token, _ := json.Marshal(
|
||||
&TokenResponse{
|
||||
Username: "test",
|
||||
@@ -92,7 +97,7 @@ func TestClient_Get(t *testing.T) {
|
||||
name: "Token",
|
||||
fields: fields{
|
||||
Strategy: AuthStrategyToken,
|
||||
cache: cache.NewSimpleCache(),
|
||||
cache: inMemoryCache,
|
||||
client: &MockClient{
|
||||
TokenResult: token,
|
||||
RequestResult: "fake",
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-ldap/ldap"
|
||||
@@ -63,8 +62,6 @@ type ldapInterfaceImpl struct {
|
||||
groupSearchBase string
|
||||
managerDN string
|
||||
managerPassword string
|
||||
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
var _ Interface = &ldapInterfaceImpl{}
|
||||
@@ -95,7 +92,6 @@ func NewLdapClient(options *Options, stopCh <-chan struct{}) (Interface, error)
|
||||
groupSearchBase: options.GroupSearchBase,
|
||||
managerDN: options.ManagerDN,
|
||||
managerPassword: options.ManagerPassword,
|
||||
once: sync.Once{},
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -103,9 +99,7 @@ func NewLdapClient(options *Options, stopCh <-chan struct{}) (Interface, error)
|
||||
client.close()
|
||||
}()
|
||||
|
||||
client.once.Do(func() {
|
||||
_ = client.createSearchBase()
|
||||
})
|
||||
_ = client.createSearchBase()
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ var promQLTemplates = map[string]string{
|
||||
"ingress_success_rate": `sum(rate(nginx_ingress_controller_requests{$1,$2,status!~"[4-5].*"}[$3])) / sum(rate(nginx_ingress_controller_requests{$1,$2}[$3]))`,
|
||||
"ingress_request_duration_average": `sum_over_time(nginx_ingress_controller_request_duration_seconds_sum{$1,$2}[$3])/sum_over_time(nginx_ingress_controller_request_duration_seconds_count{$1,$2}[$3])`,
|
||||
"ingress_request_duration_50percentage": `histogram_quantile(0.50, sum by (le) (rate(nginx_ingress_controller_request_duration_seconds_bucket{$1,$2}[$3])))`,
|
||||
"ingress_request_duration_95percentage": `histogram_quantile(0.90, sum by (le) (rate(nginx_ingress_controller_request_duration_seconds_bucket{$1,$2}[$3])))`,
|
||||
"ingress_request_duration_95percentage": `histogram_quantile(0.95, sum by (le) (rate(nginx_ingress_controller_request_duration_seconds_bucket{$1,$2}[$3])))`,
|
||||
"ingress_request_duration_99percentage": `histogram_quantile(0.99, sum by (le) (rate(nginx_ingress_controller_request_duration_seconds_bucket{$1,$2}[$3])))`,
|
||||
"ingress_request_volume": `round(sum(irate(nginx_ingress_controller_requests{$1,$2}[$3])), 0.001)`,
|
||||
"ingress_request_volume_by_ingress": `round(sum(irate(nginx_ingress_controller_requests{$1,$2}[$3])) by (ingress), 0.001)`,
|
||||
|
||||
@@ -74,6 +74,10 @@ func (h HelmVersionWrapper) GetKeywords() string {
|
||||
return strings.Join(h.ChartVersion.Keywords, ",")
|
||||
}
|
||||
|
||||
func (h HelmVersionWrapper) GetRawKeywords() []string {
|
||||
return h.ChartVersion.Keywords
|
||||
}
|
||||
|
||||
func (h HelmVersionWrapper) GetRawMaintainers() []*v1alpha1.Maintainer {
|
||||
mt := make([]*v1alpha1.Maintainer, 0, len(h.Maintainers))
|
||||
for _, value := range h.Maintainers {
|
||||
|
||||
@@ -99,6 +99,9 @@ func MergeRepoIndex(repo *v1alpha1.HelmRepo, index *helmrepo.IndexFile, existsSa
|
||||
|
||||
allAppNames := make(map[string]struct{}, len(index.Entries))
|
||||
for name, versions := range index.Entries {
|
||||
if len(versions) == 0 {
|
||||
continue
|
||||
}
|
||||
// add new applications
|
||||
if application, exists := saved.Applications[name]; !exists {
|
||||
application = &Application{
|
||||
|
||||
@@ -50,5 +50,102 @@ func TestLoadRepo(t *testing.T) {
|
||||
_ = chartData
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var indexData1 = `
|
||||
apiVersion: v1
|
||||
entries:
|
||||
apisix: []
|
||||
apisix-dashboard:
|
||||
- apiVersion: v2
|
||||
appVersion: 2.9.0
|
||||
created: "2021-11-15T08:23:00.343784368Z"
|
||||
description: A Helm chart for Apache APISIX Dashboard
|
||||
digest: 76f794b1300f7bfb756ede352fe71eb863b89f1995b495e8b683990709e310ad
|
||||
icon: https://apache.org/logos/res/apisix/apisix.png
|
||||
maintainers:
|
||||
- email: zhangjintao@apache.org
|
||||
name: tao12345666333
|
||||
name: apisix-dashboard
|
||||
type: application
|
||||
urls:
|
||||
- https://charts.kubesphere.io/main/apisix-dashboard-0.3.0.tgz
|
||||
version: 0.3.0
|
||||
`
|
||||
var indexData2 = `
|
||||
apiVersion: v1
|
||||
entries:
|
||||
apisix:
|
||||
- apiVersion: v2
|
||||
appVersion: 2.10.0
|
||||
created: "2021-11-15T08:23:00.343234584Z"
|
||||
dependencies:
|
||||
- condition: etcd.enabled
|
||||
name: etcd
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
version: 6.2.6
|
||||
- alias: dashboard
|
||||
condition: dashboard.enabled
|
||||
name: apisix-dashboard
|
||||
repository: https://charts.apiseven.com
|
||||
version: 0.3.0
|
||||
- alias: ingress-controller
|
||||
condition: ingress-controller.enabled
|
||||
name: apisix-ingress-controller
|
||||
repository: https://charts.apiseven.com
|
||||
version: 0.8.0
|
||||
description: A Helm chart for Apache APISIX
|
||||
digest: fed38a11c0fb54d385144767227e43cb2961d1b50d36ea207fdd122bddd3de28
|
||||
icon: https://apache.org/logos/res/apisix/apisix.png
|
||||
maintainers:
|
||||
- email: zhangjintao@apache.org
|
||||
name: tao12345666333
|
||||
name: apisix
|
||||
type: application
|
||||
urls:
|
||||
- https://charts.kubesphere.io/main/apisix-0.7.2.tgz
|
||||
version: 0.7.2
|
||||
apisix-dashboard:
|
||||
- apiVersion: v2
|
||||
appVersion: 2.9.0
|
||||
created: "2021-11-15T08:23:00.343784368Z"
|
||||
description: A Helm chart for Apache APISIX Dashboard
|
||||
digest: 76f794b1300f7bfb756ede352fe71eb863b89f1995b495e8b683990709e310ad
|
||||
icon: https://apache.org/logos/res/apisix/apisix.png
|
||||
maintainers:
|
||||
- email: zhangjintao@apache.org
|
||||
name: tao12345666333
|
||||
name: apisix-dashboard
|
||||
type: application
|
||||
urls:
|
||||
- https://charts.kubesphere.io/main/apisix-dashboard-0.3.0.tgz
|
||||
version: 0.3.0
|
||||
`
|
||||
|
||||
func TestMergeRepo(t *testing.T) {
|
||||
repoIndex1, err := loadIndex([]byte(indexData1))
|
||||
if err != nil {
|
||||
t.Errorf("failed to load repo index")
|
||||
t.Failed()
|
||||
}
|
||||
existsSavedIndex := &SavedIndex{}
|
||||
repoCR := &v1alpha1.HelmRepo{}
|
||||
|
||||
savedIndex1 := MergeRepoIndex(repoCR, repoIndex1, existsSavedIndex)
|
||||
if len(savedIndex1.Applications) != 1 {
|
||||
t.Errorf("faied to merge repo index with empty repo")
|
||||
t.Failed()
|
||||
}
|
||||
|
||||
repoIndex2, err := loadIndex([]byte(indexData2))
|
||||
if err != nil {
|
||||
t.Errorf("failed to load repo index")
|
||||
t.Failed()
|
||||
}
|
||||
|
||||
savedIndex2 := MergeRepoIndex(repoCR, repoIndex2, savedIndex1)
|
||||
if len(savedIndex2.Applications) != 2 {
|
||||
t.Errorf("faied to merge two repo index")
|
||||
t.Failed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"sync"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
@@ -30,6 +31,7 @@ import (
|
||||
|
||||
clusterv1alpha1 "kubesphere.io/api/cluster/v1alpha1"
|
||||
|
||||
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
clusterinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/cluster/v1alpha1"
|
||||
clusterlister "kubesphere.io/kubesphere/pkg/client/listers/cluster/v1alpha1"
|
||||
)
|
||||
@@ -54,6 +56,8 @@ type ClusterClients interface {
|
||||
GetClusterKubeconfig(string) (string, error)
|
||||
Get(string) (*clusterv1alpha1.Cluster, error)
|
||||
GetInnerCluster(string) *innerCluster
|
||||
GetKubernetesClientSet(string) (*kubernetes.Clientset, error)
|
||||
GetKubeSphereClientSet(string) (*kubesphere.Clientset, error)
|
||||
}
|
||||
|
||||
func NewClusterClient(clusterInformer clusterinformer.ClusterInformer) ClusterClients {
|
||||
@@ -182,3 +186,45 @@ func (c *clusterClients) IsHostCluster(cluster *clusterv1alpha1.Cluster) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *clusterClients) GetKubeSphereClientSet(name string) (*kubesphere.Clientset, error) {
|
||||
kubeconfig, err := c.GetClusterKubeconfig(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
restConfig, err := newRestConfigFromString(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clientSet, err := kubesphere.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return clientSet, nil
|
||||
}
|
||||
|
||||
func (c *clusterClients) GetKubernetesClientSet(name string) (*kubernetes.Clientset, error) {
|
||||
kubeconfig, err := c.GetClusterKubeconfig(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
restConfig, err := newRestConfigFromString(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clientSet, err := kubernetes.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return clientSet, nil
|
||||
}
|
||||
|
||||
func newRestConfigFromString(kubeconfig string) (*rest.Config, error) {
|
||||
bytes, err := clientcmd.NewClientConfigFromBytes([]byte(kubeconfig))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes.ClientConfig()
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
)
|
||||
|
||||
var sf *sonyflake.Sonyflake
|
||||
var upperMachineID uint16
|
||||
|
||||
func init() {
|
||||
var st sonyflake.Settings
|
||||
@@ -37,11 +36,18 @@ func init() {
|
||||
sf = sonyflake.NewSonyflake(sonyflake.Settings{
|
||||
MachineID: lower16BitIP,
|
||||
})
|
||||
upperMachineID, _ = upper16BitIP()
|
||||
}
|
||||
if sf == nil {
|
||||
sf = sonyflake.NewSonyflake(sonyflake.Settings{
|
||||
MachineID: lower16BitIPv6,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func GetIntId() uint64 {
|
||||
if sf == nil {
|
||||
panic(errors.New("invalid snowflake instance"))
|
||||
}
|
||||
id, err := sf.NextID()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -93,15 +99,6 @@ func lower16BitIP() (uint16, error) {
|
||||
return uint16(ip[2])<<8 + uint16(ip[3]), nil
|
||||
}
|
||||
|
||||
func upper16BitIP() (uint16, error) {
|
||||
ip, err := IPv4()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uint16(ip[0])<<8 + uint16(ip[1]), nil
|
||||
}
|
||||
|
||||
func IPv4() (net.IP, error) {
|
||||
as, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
@@ -123,3 +120,34 @@ func IPv4() (net.IP, error) {
|
||||
}
|
||||
return nil, errors.New("no ip address")
|
||||
}
|
||||
|
||||
func lower16BitIPv6() (uint16, error) {
|
||||
ip, err := IPv6()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint16(ip[14])<<8 + uint16(ip[15]), nil
|
||||
}
|
||||
func IPv6() (net.IP, error) {
|
||||
as, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, a := range as {
|
||||
ipnet, ok := a.(*net.IPNet)
|
||||
if !ok || ipnet.IP.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
if ipnet.IP.To4() != nil {
|
||||
continue
|
||||
}
|
||||
ip := ipnet.IP.To16()
|
||||
if ip == nil {
|
||||
continue
|
||||
}
|
||||
return ip, nil
|
||||
|
||||
}
|
||||
return nil, errors.New("no ip address")
|
||||
}
|
||||
|
||||
22
pkg/utils/josnpatchutil/jsonpatchutil.go
Normal file
22
pkg/utils/josnpatchutil/jsonpatchutil.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package josnpatchutil
|
||||
|
||||
import (
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func Parse(raw []byte) (jsonpatch.Patch, error) {
|
||||
return jsonpatch.DecodePatch(raw)
|
||||
}
|
||||
|
||||
func GetValue(patch jsonpatch.Operation, value interface{}) error {
|
||||
valueInterface, err := patch.ValueInterface()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mapstructure.Decode(valueInterface, value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -287,9 +287,15 @@ func (c *cachedRepos) addRepo(repo *v1alpha1.HelmRepo, builtin bool) error {
|
||||
},
|
||||
Spec: v1alpha1.HelmApplicationVersionSpec{
|
||||
Metadata: &v1alpha1.Metadata{
|
||||
Name: hvw.GetName(),
|
||||
AppVersion: hvw.GetAppVersion(),
|
||||
Version: hvw.GetVersion(),
|
||||
Name: hvw.GetName(),
|
||||
AppVersion: hvw.GetAppVersion(),
|
||||
Version: hvw.GetVersion(),
|
||||
Description: hvw.GetDescription(),
|
||||
Home: hvw.GetHome(),
|
||||
Icon: hvw.GetIcon(),
|
||||
Maintainers: hvw.GetRawMaintainers(),
|
||||
Sources: hvw.GetRawSources(),
|
||||
Keywords: hvw.GetRawKeywords(),
|
||||
},
|
||||
URLs: chartVersion.URLs,
|
||||
Digest: chartVersion.Digest,
|
||||
|
||||
2
vendor/github.com/json-iterator/go/README.md
generated
vendored
2
vendor/github.com/json-iterator/go/README.md
generated
vendored
@@ -8,8 +8,6 @@
|
||||
|
||||
A high-performance 100% compatible drop-in replacement of "encoding/json"
|
||||
|
||||
You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go)
|
||||
|
||||
# Benchmark
|
||||
|
||||

|
||||
|
||||
2
vendor/github.com/json-iterator/go/go.mod
generated
vendored
2
vendor/github.com/json-iterator/go/go.mod
generated
vendored
@@ -6,6 +6,6 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/google/gofuzz v1.0.0
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742
|
||||
github.com/modern-go/reflect2 v1.0.2
|
||||
github.com/stretchr/testify v1.3.0
|
||||
)
|
||||
|
||||
4
vendor/github.com/json-iterator/go/go.sum
generated
vendored
4
vendor/github.com/json-iterator/go/go.sum
generated
vendored
@@ -5,8 +5,8 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
||||
3
vendor/github.com/json-iterator/go/iter_float.go
generated
vendored
3
vendor/github.com/json-iterator/go/iter_float.go
generated
vendored
@@ -288,6 +288,9 @@ non_decimal_loop:
|
||||
return iter.readFloat64SlowPath()
|
||||
}
|
||||
value = (value << 3) + (value << 1) + uint64(ind)
|
||||
if value > maxFloat64 {
|
||||
return iter.readFloat64SlowPath()
|
||||
}
|
||||
}
|
||||
}
|
||||
return iter.readFloat64SlowPath()
|
||||
|
||||
3
vendor/github.com/json-iterator/go/iter_int.go
generated
vendored
3
vendor/github.com/json-iterator/go/iter_int.go
generated
vendored
@@ -9,6 +9,7 @@ var intDigits []int8
|
||||
|
||||
const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1
|
||||
const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1
|
||||
const maxFloat64 = 1<<53 - 1
|
||||
|
||||
func init() {
|
||||
intDigits = make([]int8, 256)
|
||||
@@ -339,7 +340,7 @@ func (iter *Iterator) readUint64(c byte) (ret uint64) {
|
||||
}
|
||||
|
||||
func (iter *Iterator) assertInteger() {
|
||||
if iter.head < len(iter.buf) && iter.buf[iter.head] == '.' {
|
||||
if iter.head < iter.tail && iter.buf[iter.head] == '.' {
|
||||
iter.ReportError("assertInteger", "can not decode float as int")
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/github.com/json-iterator/go/reflect.go
generated
vendored
2
vendor/github.com/json-iterator/go/reflect.go
generated
vendored
@@ -65,7 +65,7 @@ func (iter *Iterator) ReadVal(obj interface{}) {
|
||||
decoder := iter.cfg.getDecoderFromCache(cacheKey)
|
||||
if decoder == nil {
|
||||
typ := reflect2.TypeOf(obj)
|
||||
if typ.Kind() != reflect.Ptr {
|
||||
if typ == nil || typ.Kind() != reflect.Ptr {
|
||||
iter.ReportError("ReadVal", "can only unmarshal into pointer")
|
||||
return
|
||||
}
|
||||
|
||||
24
vendor/github.com/json-iterator/go/reflect_json_raw_message.go
generated
vendored
24
vendor/github.com/json-iterator/go/reflect_json_raw_message.go
generated
vendored
@@ -33,11 +33,19 @@ type jsonRawMessageCodec struct {
|
||||
}
|
||||
|
||||
func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
*((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes())
|
||||
if iter.ReadNil() {
|
||||
*((*json.RawMessage)(ptr)) = nil
|
||||
} else {
|
||||
*((*json.RawMessage)(ptr)) = iter.SkipAndReturnBytes()
|
||||
}
|
||||
}
|
||||
|
||||
func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
stream.WriteRaw(string(*((*json.RawMessage)(ptr))))
|
||||
if *((*json.RawMessage)(ptr)) == nil {
|
||||
stream.WriteNil()
|
||||
} else {
|
||||
stream.WriteRaw(string(*((*json.RawMessage)(ptr))))
|
||||
}
|
||||
}
|
||||
|
||||
func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
@@ -48,11 +56,19 @@ type jsoniterRawMessageCodec struct {
|
||||
}
|
||||
|
||||
func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
*((*RawMessage)(ptr)) = RawMessage(iter.SkipAndReturnBytes())
|
||||
if iter.ReadNil() {
|
||||
*((*RawMessage)(ptr)) = nil
|
||||
} else {
|
||||
*((*RawMessage)(ptr)) = iter.SkipAndReturnBytes()
|
||||
}
|
||||
}
|
||||
|
||||
func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
stream.WriteRaw(string(*((*RawMessage)(ptr))))
|
||||
if *((*RawMessage)(ptr)) == nil {
|
||||
stream.WriteNil()
|
||||
} else {
|
||||
stream.WriteRaw(string(*((*RawMessage)(ptr))))
|
||||
}
|
||||
}
|
||||
|
||||
func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
|
||||
5
vendor/github.com/json-iterator/go/reflect_struct_decoder.go
generated
vendored
5
vendor/github.com/json-iterator/go/reflect_struct_decoder.go
generated
vendored
@@ -1075,6 +1075,11 @@ type stringModeNumberDecoder struct {
|
||||
}
|
||||
|
||||
func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
if iter.WhatIsNext() == NilValue {
|
||||
decoder.elemDecoder.Decode(ptr, iter)
|
||||
return
|
||||
}
|
||||
|
||||
c := iter.nextToken()
|
||||
if c != '"' {
|
||||
iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c}))
|
||||
|
||||
2
vendor/github.com/modern-go/reflect2/.travis.yml
generated
vendored
2
vendor/github.com/modern-go/reflect2/.travis.yml
generated
vendored
@@ -1,7 +1,7 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.x
|
||||
|
||||
before_install:
|
||||
|
||||
8
vendor/github.com/modern-go/reflect2/Gopkg.lock
generated
vendored
8
vendor/github.com/modern-go/reflect2/Gopkg.lock
generated
vendored
@@ -1,15 +1,9 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/modern-go/concurrent"
|
||||
packages = ["."]
|
||||
revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a"
|
||||
version = "1.0.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "daee8a88b3498b61c5640056665b8b9eea062006f5e596bbb6a3ed9119a11ec7"
|
||||
input-imports = []
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
4
vendor/github.com/modern-go/reflect2/Gopkg.toml
generated
vendored
4
vendor/github.com/modern-go/reflect2/Gopkg.toml
generated
vendored
@@ -26,10 +26,6 @@
|
||||
|
||||
ignored = []
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/modern-go/concurrent"
|
||||
version = "1.0.0"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
3
vendor/github.com/modern-go/reflect2/go.mod
generated
vendored
Normal file
3
vendor/github.com/modern-go/reflect2/go.mod
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module github.com/modern-go/reflect2
|
||||
|
||||
go 1.12
|
||||
23
vendor/github.com/modern-go/reflect2/go_above_118.go
generated
vendored
Normal file
23
vendor/github.com/modern-go/reflect2/go_above_118.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
//+build go1.18
|
||||
|
||||
package reflect2
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// m escapes into the return value, but the caller of mapiterinit
|
||||
// doesn't let the return value escape.
|
||||
//go:noescape
|
||||
//go:linkname mapiterinit reflect.mapiterinit
|
||||
func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer, it *hiter)
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
|
||||
var it hiter
|
||||
mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj), &it)
|
||||
return &UnsafeMapIterator{
|
||||
hiter: &it,
|
||||
pKeyRType: type2.pKeyRType,
|
||||
pElemRType: type2.pElemRType,
|
||||
}
|
||||
}
|
||||
8
vendor/github.com/modern-go/reflect2/go_above_17.go
generated
vendored
8
vendor/github.com/modern-go/reflect2/go_above_17.go
generated
vendored
@@ -1,8 +0,0 @@
|
||||
//+build go1.7
|
||||
|
||||
package reflect2
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:linkname resolveTypeOff reflect.resolveTypeOff
|
||||
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
|
||||
3
vendor/github.com/modern-go/reflect2/go_above_19.go
generated
vendored
3
vendor/github.com/modern-go/reflect2/go_above_19.go
generated
vendored
@@ -6,6 +6,9 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:linkname resolveTypeOff reflect.resolveTypeOff
|
||||
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
|
||||
|
||||
//go:linkname makemap reflect.makemap
|
||||
func makemap(rtype unsafe.Pointer, cap int) (m unsafe.Pointer)
|
||||
|
||||
|
||||
21
vendor/github.com/modern-go/reflect2/go_below_118.go
generated
vendored
Normal file
21
vendor/github.com/modern-go/reflect2/go_below_118.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
//+build !go1.18
|
||||
|
||||
package reflect2
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// m escapes into the return value, but the caller of mapiterinit
|
||||
// doesn't let the return value escape.
|
||||
//go:noescape
|
||||
//go:linkname mapiterinit reflect.mapiterinit
|
||||
func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) (val *hiter)
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
|
||||
return &UnsafeMapIterator{
|
||||
hiter: mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)),
|
||||
pKeyRType: type2.pKeyRType,
|
||||
pElemRType: type2.pElemRType,
|
||||
}
|
||||
}
|
||||
9
vendor/github.com/modern-go/reflect2/go_below_17.go
generated
vendored
9
vendor/github.com/modern-go/reflect2/go_below_17.go
generated
vendored
@@ -1,9 +0,0 @@
|
||||
//+build !go1.7
|
||||
|
||||
package reflect2
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
|
||||
return nil
|
||||
}
|
||||
14
vendor/github.com/modern-go/reflect2/go_below_19.go
generated
vendored
14
vendor/github.com/modern-go/reflect2/go_below_19.go
generated
vendored
@@ -1,14 +0,0 @@
|
||||
//+build !go1.9
|
||||
|
||||
package reflect2
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:linkname makemap reflect.makemap
|
||||
func makemap(rtype unsafe.Pointer) (m unsafe.Pointer)
|
||||
|
||||
func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer {
|
||||
return makemap(rtype)
|
||||
}
|
||||
20
vendor/github.com/modern-go/reflect2/reflect2.go
generated
vendored
20
vendor/github.com/modern-go/reflect2/reflect2.go
generated
vendored
@@ -1,8 +1,9 @@
|
||||
package reflect2
|
||||
|
||||
import (
|
||||
"github.com/modern-go/concurrent"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -130,13 +131,13 @@ var ConfigSafe = Config{UseSafeImplementation: true}.Froze()
|
||||
|
||||
type frozenConfig struct {
|
||||
useSafeImplementation bool
|
||||
cache *concurrent.Map
|
||||
cache *sync.Map
|
||||
}
|
||||
|
||||
func (cfg Config) Froze() *frozenConfig {
|
||||
return &frozenConfig{
|
||||
useSafeImplementation: cfg.UseSafeImplementation,
|
||||
cache: concurrent.NewMap(),
|
||||
cache: new(sync.Map),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,11 +289,12 @@ func NoEscape(p unsafe.Pointer) unsafe.Pointer {
|
||||
}
|
||||
|
||||
func UnsafeCastString(str string) []byte {
|
||||
bytes := make([]byte, 0)
|
||||
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str))
|
||||
sliceHeader := &reflect.SliceHeader{
|
||||
Data: stringHeader.Data,
|
||||
Cap: stringHeader.Len,
|
||||
Len: stringHeader.Len,
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(sliceHeader))
|
||||
sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
|
||||
sliceHeader.Data = stringHeader.Data
|
||||
sliceHeader.Cap = stringHeader.Len
|
||||
sliceHeader.Len = stringHeader.Len
|
||||
runtime.KeepAlive(str)
|
||||
return bytes
|
||||
}
|
||||
|
||||
12
vendor/github.com/modern-go/reflect2/test.sh
generated
vendored
12
vendor/github.com/modern-go/reflect2/test.sh
generated
vendored
@@ -1,12 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
for d in $(go list github.com/modern-go/reflect2-tests/... | grep -v vendor); do
|
||||
go test -coverprofile=profile.out -coverpkg=github.com/modern-go/reflect2 $d
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
rm profile.out
|
||||
fi
|
||||
done
|
||||
51
vendor/github.com/modern-go/reflect2/type_map.go
generated
vendored
51
vendor/github.com/modern-go/reflect2/type_map.go
generated
vendored
@@ -1,17 +1,13 @@
|
||||
// +build !gccgo
|
||||
|
||||
package reflect2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// typelinks1 for 1.5 ~ 1.6
|
||||
//go:linkname typelinks1 reflect.typelinks
|
||||
func typelinks1() [][]unsafe.Pointer
|
||||
|
||||
// typelinks2 for 1.7 ~
|
||||
//go:linkname typelinks2 reflect.typelinks
|
||||
func typelinks2() (sections []unsafe.Pointer, offset [][]int32)
|
||||
@@ -27,49 +23,10 @@ func discoverTypes() {
|
||||
types = make(map[string]reflect.Type)
|
||||
packages = make(map[string]map[string]reflect.Type)
|
||||
|
||||
ver := runtime.Version()
|
||||
if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") {
|
||||
loadGo15Types()
|
||||
} else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") {
|
||||
loadGo15Types()
|
||||
} else {
|
||||
loadGo17Types()
|
||||
}
|
||||
loadGoTypes()
|
||||
}
|
||||
|
||||
func loadGo15Types() {
|
||||
var obj interface{} = reflect.TypeOf(0)
|
||||
typePtrss := typelinks1()
|
||||
for _, typePtrs := range typePtrss {
|
||||
for _, typePtr := range typePtrs {
|
||||
(*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr
|
||||
typ := obj.(reflect.Type)
|
||||
if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
|
||||
loadedType := typ.Elem()
|
||||
pkgTypes := packages[loadedType.PkgPath()]
|
||||
if pkgTypes == nil {
|
||||
pkgTypes = map[string]reflect.Type{}
|
||||
packages[loadedType.PkgPath()] = pkgTypes
|
||||
}
|
||||
types[loadedType.String()] = loadedType
|
||||
pkgTypes[loadedType.Name()] = loadedType
|
||||
}
|
||||
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr &&
|
||||
typ.Elem().Elem().Kind() == reflect.Struct {
|
||||
loadedType := typ.Elem().Elem()
|
||||
pkgTypes := packages[loadedType.PkgPath()]
|
||||
if pkgTypes == nil {
|
||||
pkgTypes = map[string]reflect.Type{}
|
||||
packages[loadedType.PkgPath()] = pkgTypes
|
||||
}
|
||||
types[loadedType.String()] = loadedType
|
||||
pkgTypes[loadedType.Name()] = loadedType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loadGo17Types() {
|
||||
func loadGoTypes() {
|
||||
var obj interface{} = reflect.TypeOf(0)
|
||||
sections, offset := typelinks2()
|
||||
for i, offs := range offset {
|
||||
|
||||
26
vendor/github.com/modern-go/reflect2/unsafe_link.go
generated
vendored
26
vendor/github.com/modern-go/reflect2/unsafe_link.go
generated
vendored
@@ -19,18 +19,12 @@ func typedslicecopy(elemType unsafe.Pointer, dst, src sliceHeader) int
|
||||
|
||||
//go:linkname mapassign reflect.mapassign
|
||||
//go:noescape
|
||||
func mapassign(rtype unsafe.Pointer, m unsafe.Pointer, key, val unsafe.Pointer)
|
||||
func mapassign(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer, val unsafe.Pointer)
|
||||
|
||||
//go:linkname mapaccess reflect.mapaccess
|
||||
//go:noescape
|
||||
func mapaccess(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
|
||||
|
||||
// m escapes into the return value, but the caller of mapiterinit
|
||||
// doesn't let the return value escape.
|
||||
//go:noescape
|
||||
//go:linkname mapiterinit reflect.mapiterinit
|
||||
func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) *hiter
|
||||
|
||||
//go:noescape
|
||||
//go:linkname mapiternext reflect.mapiternext
|
||||
func mapiternext(it *hiter)
|
||||
@@ -42,9 +36,21 @@ func ifaceE2I(rtype unsafe.Pointer, src interface{}, dst unsafe.Pointer)
|
||||
// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate
|
||||
// the layout of this structure.
|
||||
type hiter struct {
|
||||
key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/internal/gc/range.go).
|
||||
value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go).
|
||||
// rest fields are ignored
|
||||
key unsafe.Pointer
|
||||
value unsafe.Pointer
|
||||
t unsafe.Pointer
|
||||
h unsafe.Pointer
|
||||
buckets unsafe.Pointer
|
||||
bptr unsafe.Pointer
|
||||
overflow *[]unsafe.Pointer
|
||||
oldoverflow *[]unsafe.Pointer
|
||||
startBucket uintptr
|
||||
offset uint8
|
||||
wrapped bool
|
||||
B uint8
|
||||
i uint8
|
||||
bucket uintptr
|
||||
checkBucket uintptr
|
||||
}
|
||||
|
||||
// add returns p+x.
|
||||
|
||||
8
vendor/github.com/modern-go/reflect2/unsafe_map.go
generated
vendored
8
vendor/github.com/modern-go/reflect2/unsafe_map.go
generated
vendored
@@ -107,14 +107,6 @@ func (type2 *UnsafeMapType) Iterate(obj interface{}) MapIterator {
|
||||
return type2.UnsafeIterate(objEFace.data)
|
||||
}
|
||||
|
||||
func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
|
||||
return &UnsafeMapIterator{
|
||||
hiter: mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)),
|
||||
pKeyRType: type2.pKeyRType,
|
||||
pElemRType: type2.pElemRType,
|
||||
}
|
||||
}
|
||||
|
||||
type UnsafeMapIterator struct {
|
||||
*hiter
|
||||
pKeyRType unsafe.Pointer
|
||||
|
||||
22
vendor/modules.txt
vendored
22
vendor/modules.txt
vendored
@@ -416,7 +416,7 @@ github.com/google/go-containerregistry/pkg/v1/types
|
||||
github.com/google/go-querystring/query
|
||||
# github.com/google/gofuzz v1.1.0 => github.com/google/gofuzz v1.1.0
|
||||
github.com/google/gofuzz
|
||||
# github.com/google/gops v0.3.23
|
||||
# github.com/google/gops v0.3.23 => github.com/google/gops v0.3.23
|
||||
## explicit
|
||||
github.com/google/gops/agent
|
||||
github.com/google/gops/internal
|
||||
@@ -479,7 +479,7 @@ github.com/jmespath/go-jmespath
|
||||
# github.com/jmoiron/sqlx v1.3.1 => github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/jmoiron/sqlx
|
||||
github.com/jmoiron/sqlx/reflectx
|
||||
# github.com/json-iterator/go v1.1.11 => github.com/json-iterator/go v1.1.10
|
||||
# github.com/json-iterator/go v1.1.12 => github.com/json-iterator/go v1.1.12
|
||||
## explicit
|
||||
github.com/json-iterator/go
|
||||
# github.com/jszwec/csvutil v1.5.0 => github.com/jszwec/csvutil v1.5.0
|
||||
@@ -566,7 +566,7 @@ github.com/moby/term
|
||||
github.com/moby/term/windows
|
||||
# github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd => github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
|
||||
github.com/modern-go/concurrent
|
||||
# github.com/modern-go/reflect2 v1.0.1 => github.com/modern-go/reflect2 v1.0.1
|
||||
# github.com/modern-go/reflect2 v1.0.2 => github.com/modern-go/reflect2 v1.0.2
|
||||
github.com/modern-go/reflect2
|
||||
# github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 => github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00
|
||||
github.com/monochromegane/go-gitignore
|
||||
@@ -818,10 +818,6 @@ github.com/rubenv/sql-migrate/sqlparse
|
||||
github.com/russross/blackfriday
|
||||
# github.com/sergi/go-diff v1.1.0 => github.com/sergi/go-diff v1.0.0
|
||||
github.com/sergi/go-diff/diffmatchpatch
|
||||
# github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7
|
||||
## explicit
|
||||
# github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4
|
||||
## explicit
|
||||
# github.com/sirupsen/logrus v1.8.1 => github.com/sirupsen/logrus v1.4.2
|
||||
github.com/sirupsen/logrus
|
||||
# github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009 => github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009
|
||||
@@ -2234,6 +2230,7 @@ sigs.k8s.io/yaml
|
||||
# github.com/Shopify/logrus-bugsnag => github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d
|
||||
# github.com/Shopify/sarama => github.com/Shopify/sarama v1.19.0
|
||||
# github.com/Shopify/toxiproxy => github.com/Shopify/toxiproxy v2.1.4+incompatible
|
||||
# github.com/StackExchange/wmi => github.com/StackExchange/wmi v1.2.1
|
||||
# github.com/VividCortex/gohistogram => github.com/VividCortex/gohistogram v1.0.0
|
||||
# github.com/afex/hystrix-go => github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
|
||||
# github.com/agnivade/levenshtein => github.com/agnivade/levenshtein v1.0.1
|
||||
@@ -2397,6 +2394,7 @@ sigs.k8s.io/yaml
|
||||
# github.com/go-logfmt/logfmt => github.com/go-logfmt/logfmt v0.5.0
|
||||
# github.com/go-logr/logr => github.com/go-logr/logr v0.4.0
|
||||
# github.com/go-logr/zapr => github.com/go-logr/zapr v0.4.0
|
||||
# github.com/go-ole/go-ole => github.com/go-ole/go-ole v1.2.6-0.20210915003542-8b1f7f90f6b1
|
||||
# github.com/go-openapi/analysis => github.com/go-openapi/analysis v0.19.10
|
||||
# github.com/go-openapi/errors => github.com/go-openapi/errors v0.19.4
|
||||
# github.com/go-openapi/jsonpointer => github.com/go-openapi/jsonpointer v0.19.3
|
||||
@@ -2459,6 +2457,7 @@ sigs.k8s.io/yaml
|
||||
# github.com/google/go-github => github.com/google/go-github v17.0.0+incompatible
|
||||
# github.com/google/go-querystring => github.com/google/go-querystring v1.0.0
|
||||
# github.com/google/gofuzz => github.com/google/gofuzz v1.1.0
|
||||
# github.com/google/gops => github.com/google/gops v0.3.23
|
||||
# github.com/google/martian => github.com/google/martian v2.1.0+incompatible
|
||||
# github.com/google/pprof => github.com/google/pprof v0.0.0-20200417002340-c6e0a841f49a
|
||||
# github.com/google/renameio => github.com/google/renameio v0.1.0
|
||||
@@ -2530,7 +2529,7 @@ sigs.k8s.io/yaml
|
||||
# github.com/jonboulle/clockwork => github.com/jonboulle/clockwork v0.1.0
|
||||
# github.com/jpillora/backoff => github.com/jpillora/backoff v1.0.0
|
||||
# github.com/jsimonetti/rtnetlink => github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4
|
||||
# github.com/json-iterator/go => github.com/json-iterator/go v1.1.10
|
||||
# github.com/json-iterator/go => github.com/json-iterator/go v1.1.12
|
||||
# github.com/jstemmer/go-junit-report => github.com/jstemmer/go-junit-report v0.9.1
|
||||
# github.com/jsternberg/zap-logfmt => github.com/jsternberg/zap-logfmt v1.0.0
|
||||
# github.com/jszwec/csvutil => github.com/jszwec/csvutil v1.5.0
|
||||
@@ -2542,6 +2541,7 @@ sigs.k8s.io/yaml
|
||||
# github.com/karrick/godirwalk => github.com/karrick/godirwalk v1.10.3
|
||||
# github.com/kelseyhightower/envconfig => github.com/kelseyhightower/envconfig v1.4.0
|
||||
# github.com/kevinburke/ssh_config => github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e
|
||||
# github.com/keybase/go-ps => github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19
|
||||
# github.com/kisielk/errcheck => github.com/kisielk/errcheck v1.2.0
|
||||
# github.com/kisielk/gotool => github.com/kisielk/gotool v1.0.0
|
||||
# github.com/kisielk/sqlstruct => github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49
|
||||
@@ -2610,7 +2610,7 @@ sigs.k8s.io/yaml
|
||||
# github.com/moby/spdystream => github.com/moby/spdystream v0.2.0
|
||||
# github.com/moby/term => github.com/moby/term v0.0.0-20201216013528-df9cb8a40635
|
||||
# github.com/modern-go/concurrent => github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
|
||||
# github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.1
|
||||
# github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.2
|
||||
# github.com/monochromegane/go-gitignore => github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00
|
||||
# github.com/montanaflynn/stats => github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe
|
||||
# github.com/morikuni/aec => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c
|
||||
@@ -2706,6 +2706,7 @@ sigs.k8s.io/yaml
|
||||
# github.com/segmentio/kafka-go => github.com/segmentio/kafka-go v0.2.0
|
||||
# github.com/sercand/kuberesolver => github.com/sercand/kuberesolver v2.4.0+incompatible
|
||||
# github.com/sergi/go-diff => github.com/sergi/go-diff v1.0.0
|
||||
# github.com/shirou/gopsutil/v3 => github.com/shirou/gopsutil/v3 v3.21.9
|
||||
# github.com/shopspring/decimal => github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24
|
||||
# github.com/shurcooL/httpfs => github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
|
||||
# github.com/shurcooL/sanitized_anchor_name => github.com/shurcooL/sanitized_anchor_name v1.0.0
|
||||
@@ -2734,6 +2735,8 @@ sigs.k8s.io/yaml
|
||||
# github.com/thanos-io/thanos => github.com/thanos-io/thanos v0.13.1-0.20200910143741-e0b7f7b32e9c
|
||||
# github.com/tidwall/pretty => github.com/tidwall/pretty v1.0.0
|
||||
# github.com/tinylib/msgp => github.com/tinylib/msgp v1.1.0
|
||||
# github.com/tklauser/go-sysconf => github.com/tklauser/go-sysconf v0.3.9
|
||||
# github.com/tklauser/numcpus => github.com/tklauser/numcpus v0.3.0
|
||||
# github.com/tmc/grpc-websocket-proxy => github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5
|
||||
# github.com/tv42/httpunix => github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926
|
||||
# github.com/uber/jaeger-client-go => github.com/uber/jaeger-client-go v2.23.0+incompatible
|
||||
@@ -2864,6 +2867,7 @@ sigs.k8s.io/yaml
|
||||
# kubesphere.io/client-go => ./staging/src/kubesphere.io/client-go
|
||||
# kubesphere.io/monitoring-dashboard => kubesphere.io/monitoring-dashboard v0.2.2
|
||||
# rsc.io/binaryregexp => rsc.io/binaryregexp v0.2.0
|
||||
# rsc.io/goversion => rsc.io/goversion v1.2.0
|
||||
# rsc.io/letsencrypt => rsc.io/letsencrypt v0.0.1
|
||||
# rsc.io/pdf => rsc.io/pdf v0.1.1
|
||||
# rsc.io/quote/v3 => rsc.io/quote/v3 v3.1.0
|
||||
|
||||
Reference in New Issue
Block a user