Compare commits

...

60 Commits

Author SHA1 Message Date
zryfish
c905fdbdb4 Update pin-dependency.sh 2020-05-13 14:37:26 +08:00
KubeSphere CI Bot
31d0e0e966 Merge pull request #1920 from wansir/1919
fix: role binding change
2020-02-23 19:18:35 +08:00
hongming
ed4d046b6d fix: role binding change
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-23 18:59:20 +08:00
zryfish
296c028d42 upgrade kubernetes sigs application controller (#1915) 2020-02-21 22:39:10 +08:00
KubeSphere CI Bot
1ece2e8104 Merge pull request #1908 from wansir/1907
fix: use constants
2020-02-21 22:26:35 +08:00
hongming
d51cd98e12 fix: use constants
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-21 14:38:54 +08:00
KubeSphere CI Bot
24527a7125 Merge pull request #1875 from wansir/bug-fix
fix: default reverse param always false
2020-02-14 15:00:32 +08:00
hongming
81982adcdd fix: default reverse param always false
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-14 13:49:29 +08:00
zryfish
59de78aba1 update vendor directory (#1864) 2020-02-13 15:30:14 +08:00
KubeSphere CI Bot
a285cf70f8 Merge pull request #1857 from huanggze/release-2.1
update builtin metrics
2020-02-13 14:08:32 +08:00
KubeSphere CI Bot
856ea6ef2d Merge pull request #1852 from wansir/1849
fix: delete login logs when account is deleted
2020-02-13 14:07:33 +08:00
KubeSphere CI Bot
bebf592fb7 Merge pull request #1848 from wansir/iam
fix: verify old password if it's defined
2020-02-13 13:52:37 +08:00
KubeSphere CI Bot
eabb28f3b8 Merge pull request #1846 from wansir/op
fix: create context with owner path
2020-02-13 12:36:37 +08:00
zryfish
aca8ee023d bump kiali version (#1860) 2020-02-13 12:36:05 +08:00
huanggze
ecf94db4e9 update builtin metrics
Signed-off-by: huanggze <loganhuang@yunify.com>
2020-02-13 12:21:55 +08:00
KubeSphere CI Bot
af2c4e7a44 Merge pull request #1850 from wansir/workspaces-manager
fix: workspaces-manager cannot be overwrite
2020-02-12 18:31:31 +08:00
hongming
8308b93ac2 fix: delete login logs when account is deleted
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-12 18:10:16 +08:00
hongming
cbc43b60ba fix: workspaces-manager cannot be overwrite
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-12 17:46:43 +08:00
hongming
54eb886e5e fix: verify old password if it's defined
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-12 16:55:38 +08:00
hongming
afb92dfc53 fix: create context with owner path
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-12 15:05:01 +08:00
KubeSphere CI Bot
a003b57351 Merge pull request #1836 from wansir/namespace_controller
fix: remove owner reference when unbind workspace
2020-02-12 14:29:32 +08:00
hongming
3387c9da50 fix: remove owner reference when unbind workspace
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-12 13:44:37 +08:00
KubeSphere CI Bot
c0ffdfd9cc Merge pull request #1839 from soulseen/update_verify
update secret verify
2020-02-12 11:11:36 +08:00
zhuxiaoyang
4fc40e5faf update secret verify
Signed-off-by: zhuxiaoyang <sunzhu@yunify.com>
2020-02-11 17:45:13 +08:00
KubeSphere CI Bot
2238998e78 Merge pull request #1831 from soulseen/release-2.1.1/verify
verify secret
2020-02-11 15:05:32 +08:00
KubeSphere CI Bot
4006c363e1 Merge pull request #1823 from huanggze/release-2.1
fix doc-gen conflict
2020-02-11 15:04:32 +08:00
KubeSphere CI Bot
ed530b826a Merge pull request #1833 from wansir/release-2.1
fix: use constants
2020-02-11 15:01:36 +08:00
hongming
6339e66125 fix: use constants
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-11 13:21:21 +08:00
zhuxiaoyang
2f434b1483 RegistryVerify unit test
Signed-off-by: zhuxiaoyang <sunzhu@yunify.com>
2020-02-11 11:25:22 +08:00
KubeSphere CI Bot
0180c9e679 Merge pull request #1828 from runzexia/release-2.1-travis
push image on branch release 2.1
2020-02-11 11:09:31 +08:00
zhuxiaoyang
3698af5e8e verify secret
Signed-off-by: zhuxiaoyang <sunzhu@yunify.com>
2020-02-10 23:10:21 +08:00
runzexia
77b66dab14 push image on branch release 2.1
Signed-off-by: runzexia <runzexia@yunify.com>
2020-02-10 16:36:31 +08:00
KubeSphere CI Bot
eff9918e6e Merge pull request #1826 from runzexia/post-credential
create & update credential use form
2020-02-10 13:09:31 +08:00
runzexia
291af6707e create & update credential use form
Signed-off-by: runzexia <runzexia@yunify.com>
2020-02-10 11:54:01 +08:00
huanggze
fdabeadf20 fix doc-gen conflict
Signed-off-by: huanggze <loganhuang@yunify.com>
2020-02-07 11:58:09 +08:00
KubeSphere CI Bot
be8e88cd60 Merge pull request #1821 from wansir/release-2.1
fix: cease cluster
2020-02-06 17:44:30 +08:00
KubeSphere CI Bot
e29cc286c1 Merge pull request #1812 from runzexia/pipeline-config-validate
validate pipeline config
2020-02-06 17:43:30 +08:00
hongming
76c8785c2d fix: cease cluster
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-06 17:32:50 +08:00
KubeSphere CI Bot
47e3241090 Merge pull request #1819 from huanggze/release-2.1
update container metrics
2020-02-06 17:27:30 +08:00
KubeSphere CI Bot
736a744451 Merge pull request #1817 from wansir/kubeconfig
fix: in cluster kubeconfig CA data is empty
2020-02-06 17:25:30 +08:00
huanggze
6a623c4c66 update container metrics
Signed-off-by: huanggze <loganhuang@yunify.com>
2020-02-06 10:52:32 +08:00
hongming
2ac4bc5371 fix in cluster kubeconfig CA data is empty
Signed-off-by: hongming <talonwan@yunify.com>
2020-02-05 17:15:44 +08:00
runzexia
751eff2da7 validate pipeline config
Signed-off-by: runzexia <runzexia@yunify.com>
2020-02-05 10:55:30 +08:00
zryfish
88da4f7809 [release-2.1] Cherry pick from master branch (#1781)
* change router underlying resource apiversion
2020-01-16 14:44:21 +08:00
KubeSphere CI Bot
bafbd7c4db Merge pull request #1774 from soulseen/fix/image
Fix/image
2020-01-16 14:08:00 +08:00
zhuxiaoyang
26d62b5f6e update unit test
Signed-off-by: zhuxiaoyang <sunzhu@yunify.com>
2020-01-16 11:27:34 +08:00
zhuxiaoyang
da074e22bd remove schema if requiredss and add Check SSL
Signed-off-by: zhuxiaoyang <sunzhu@yunify.com>
2020-01-16 11:27:17 +08:00
KubeSphere CI Bot
4a5049d7ca Merge pull request #1763 from wansir/kubeconfig
use CSR to generate user client certificate
2020-01-15 16:29:05 +08:00
hongming
b6b6f14fb6 use CSR generate user client certificate
Signed-off-by: hongming <talonwan@yunify.com>
2020-01-15 15:58:35 +08:00
KubeSphere CI Bot
9f06d62e29 Merge pull request #1761 from runzexia/fix-param-parse
fix choice param parse
2020-01-15 15:32:00 +08:00
runzexia
b3690795a6 refmt code
Signed-off-by: runzexia <runzexia@yunify.com>
2020-01-15 11:45:16 +08:00
KubeSphere CI Bot
3ec030974b Merge pull request #1772 from wnxn/release-2.1
Add API for setting default storage class (#1757)
2020-01-15 11:17:00 +08:00
KubeSphere CI Bot
08786877f8 Merge pull request #1767 from huanggze/release-2.1
filter out metrics with empty resource_name when sorting
2020-01-15 11:16:01 +08:00
runzexia
0531e2ce48 add more comments
Signed-off-by: runzexia <runzexia@yunify.com>
2020-01-15 11:11:04 +08:00
Wiley Wang
20d3f8fa4f Add API for setting default storage class (#1757)
Signed-off-by: Xin Wang <wileywang@yunify.com>
(cherry picked from commit 66850ee3ee)
2020-01-15 10:51:37 +08:00
runzexia
4b30fd8c13 fix choice param parse
Signed-off-by: runzexia <runzexia@yunify.com>
2020-01-15 10:36:43 +08:00
huanggze
a3a0371203 filter out metrics with empty resource_name when sorting
Signed-off-by: huanggze <loganhuang@yunify.com>
2020-01-14 23:24:53 +08:00
zryfish
7a97a696b6 Update .travis.yml 2020-01-14 20:30:30 +08:00
KubeSphere CI Bot
89f1158a67 Merge pull request #1750 from wansir/fix
refactor resources API
2020-01-10 11:39:54 +08:00
hongming
05e949103e refactor resources API
Signed-off-by: hongming <talonwan@yunify.com>
2020-01-10 10:28:14 +08:00
157 changed files with 4857 additions and 4207 deletions

View File

@@ -9,7 +9,7 @@ git:
depth: false
go:
- "1.12.x"
- "1.13.x"
env:
- GO111MODULE=on
cache:
@@ -29,8 +29,13 @@ install:
- go get golang.org/x/lint/golint
deploy:
skip_cleanup: true
provider: script
script: bash hack/docker_build.sh
on:
branch: master
- skip_cleanup: true
provider: script
script: bash hack/docker_build.sh
on:
branch: master
- skip_cleanup: true
provider: script
script: bash hack/docker_build.sh
on:
branch: release-2.1

View File

@@ -37,12 +37,12 @@ import (
istioclientset "github.com/knative/pkg/client/clientset/versioned"
istioinformers "github.com/knative/pkg/client/informers/externalversions"
applicationclientset "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
applicationinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
s2iclientset "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
s2iinformers "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
kubesphereclientset "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
kubesphereinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
applicationclientset "sigs.k8s.io/application/pkg/client/clientset/versioned"
applicationinformers "sigs.k8s.io/application/pkg/client/informers/externalversions"
)
const defaultResync = 600 * time.Second

18
go.mod
View File

@@ -15,7 +15,6 @@ require (
github.com/Microsoft/go-winio v0.4.12 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/PuerkitoBio/goquery v1.5.0
github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30 // indirect
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf
github.com/aws/aws-sdk-go v1.22.2
github.com/beevik/etree v1.1.0
@@ -45,7 +44,6 @@ require (
github.com/fatih/structs v1.1.0
github.com/go-ldap/ldap v3.0.3+incompatible
github.com/go-logr/logr v0.1.0
github.com/go-logr/zapr v0.1.1 // indirect
github.com/go-openapi/jsonpointer v0.19.0 // indirect
github.com/go-openapi/jsonreference v0.19.0 // indirect
github.com/go-openapi/spec v0.19.0
@@ -74,11 +72,10 @@ require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/json-iterator/go v1.1.6
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/kiali/kiali v0.15.1-0.20190407071308-6b5b818211c3
github.com/kiali/kiali v0.15.1-0.20200213040359-608aece2aa66
github.com/klauspost/cpuid v1.2.1 // indirect
github.com/knative/pkg v0.0.0-20190314204845-cd278f2d3394
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/kubernetes-sigs/application v0.0.0-20190518133311-b9d9eb0b5cf7
github.com/kubesphere/s2ioperator v0.0.13
github.com/kubesphere/sonargo v0.0.2
github.com/leodido/go-urn v1.1.0 // indirect
@@ -92,13 +89,14 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
github.com/onsi/ginkgo v1.8.0
github.com/onsi/gomega v1.5.0
github.com/onsi/ginkgo v1.10.1
github.com/onsi/gomega v1.7.0
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/openshift/api v3.9.0+incompatible // indirect
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.8.1
github.com/projectcalico/go-json v0.0.0-20161128004156-6219dc7339ba // indirect
github.com/projectcalico/go-yaml v0.0.0-20161201183616-955bc3e451ef // indirect
github.com/projectcalico/go-yaml-wrapper v0.0.0-20161127220527-598e54215bee // indirect
@@ -131,7 +129,7 @@ require (
gopkg.in/src-d/go-git.v4 v4.11.0
gopkg.in/yaml.v2 v2.2.2
gotest.tools v2.2.0+incompatible // indirect
k8s.io/api v0.0.0-20181213150558-05914d821849
k8s.io/api v0.0.0-20190831074750-7364b6bdad65
k8s.io/apiextensions-apiserver v0.0.0-20181213153335-0fe22c71c476
k8s.io/apimachinery v0.0.0-20190831074630-461753078381
k8s.io/apiserver v0.0.0-20190507070644-e9c02aff496d
@@ -148,7 +146,6 @@ require (
sigs.k8s.io/application v0.0.0-20190404151855-67ae7f915d4e
sigs.k8s.io/controller-runtime v0.1.10
sigs.k8s.io/controller-tools v0.1.12
sigs.k8s.io/testing_frameworks v0.1.1 // indirect
sigs.k8s.io/yaml v1.1.0 // indirect
)
@@ -294,7 +291,7 @@ replace (
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-20161005175911-668c8856d999
github.com/kiali/kiali => github.com/kubesphere/kiali v0.15.1-0.20190407071308-6b5b818211c3
github.com/kiali/kiali => github.com/kubesphere/kiali v0.15.1-0.20200213040359-608aece2aa66
github.com/klauspost/cpuid => github.com/klauspost/cpuid v1.2.1
github.com/knative/pkg => github.com/knative/pkg v0.0.0-20190314204845-cd278f2d3394
github.com/koding/multiconfig => github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7
@@ -303,7 +300,6 @@ replace (
github.com/kr/pretty => github.com/kr/pretty v0.1.0
github.com/kr/pty => github.com/kr/pty v1.1.1
github.com/kr/text => github.com/kr/text v0.1.0
github.com/kubernetes-sigs/application => github.com/kubesphere/application v0.0.0-20190518133311-b9d9eb0b5cf7
github.com/kubesphere/s2ioperator => github.com/kubesphere/s2ioperator v0.0.13
github.com/kubesphere/sonargo => github.com/kubesphere/sonargo v0.0.2
github.com/kylelemons/godebug => github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
@@ -430,7 +426,7 @@ replace (
openpitrix.io/logger v0.1.0 => github.com/openpitrix/logger v0.1.0
openpitrix.io/openpitrix => openpitrix.io/openpitrix v0.4.1-0.20190920134345-4d2be6e4965c
rsc.io/goversion => rsc.io/goversion v1.0.0
sigs.k8s.io/application => sigs.k8s.io/application v0.0.0-20190404151855-67ae7f915d4e
sigs.k8s.io/application => github.com/kubesphere/application v0.0.0-20200221140547-8beafe2fa7ef
sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.1.10
sigs.k8s.io/controller-tools => sigs.k8s.io/controller-tools v0.1.12
sigs.k8s.io/testing_frameworks => sigs.k8s.io/testing_frameworks v0.1.1

8
go.sum
View File

@@ -268,10 +268,14 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kubernetes-sigs/application v0.8.1 h1:tnIN+iijr0kDJxvOhnqjoXV+3hWydRNy8OHisMyO71U=
github.com/kubernetes-sigs/application v0.8.1/go.mod h1:KqAScqo78PXUrmoFOH8z6P4xQDBdzyJH1FMqrhgJJLE=
github.com/kubesphere/application v0.0.0-20190518133311-b9d9eb0b5cf7 h1:9dongD6mbssQJGb9pV4sE7IHyua6I/lCOu4h6rEfj20=
github.com/kubesphere/application v0.0.0-20190518133311-b9d9eb0b5cf7/go.mod h1:xCs7b2bgA24oBSuZYf+5btESJC3xPs//ZTSK1ql+W6I=
github.com/kubesphere/kiali v0.15.1-0.20190407071308-6b5b818211c3 h1:5IASnVaVqZFzzIc/0FZuAnjWO1gVCUxJe1OFUS42/fU=
github.com/kubesphere/kiali v0.15.1-0.20190407071308-6b5b818211c3/go.mod h1:Y1EqeixoXkKkU8I+yvOfhdh21+8+etFE6wYOVT2XFdI=
github.com/kubesphere/application v0.0.0-20200221140547-8beafe2fa7ef h1:0s/3VfJ9xP9cqLB7dKj1eXCfC+Nr8fy/5xUJhD2lojU=
github.com/kubesphere/application v0.0.0-20200221140547-8beafe2fa7ef/go.mod h1:Sn/bPGEhZxJeByRvkBo3I+n343KJ+5PBbhdmCdoJZX8=
github.com/kubesphere/kiali v0.15.1-0.20200213040359-608aece2aa66 h1:xrYcJkIEsE6RDmBprHn1SSMOoYcew/SAxJPm2+rHg1s=
github.com/kubesphere/kiali v0.15.1-0.20200213040359-608aece2aa66/go.mod h1:Y1EqeixoXkKkU8I+yvOfhdh21+8+etFE6wYOVT2XFdI=
github.com/kubesphere/s2ioperator v0.0.13 h1:K6RdjaFluhn/GterbnIykORrueAZcwR/Qj3MsVI4qQs=
github.com/kubesphere/s2ioperator v0.0.13/go.mod h1:dv9L+zRYDlHvnKPp0j6VHRtlGB1BU+lloltW9SAWqVU=
github.com/kubesphere/sonargo v0.0.2 h1:hsSRE3sv3mkPcUAeSABdp7rtfcNW2zzeHXzFa01CTkU=

View File

@@ -13,6 +13,10 @@ elif [[ $TRAVIS_EVENT_TYPE == "cron" ]]; then
TAG=dev-$(date +%Y%m%d)
fi
if [[ $TRAVIS_BRANCH == "release-2.1" ]]; then
TAG=release-2.1
fi
docker build -f build/ks-apigateway/Dockerfile -t $REPO/ks-apigateway:$TAG .
docker build -f build/ks-apiserver/Dockerfile -t $REPO/ks-apiserver:$TAG .

View File

@@ -48,7 +48,7 @@ mkdir -p "${_tmp}"
# Add the require directive
echo "Running: go get ${dep}@${sha}"
go get -m -d "${dep}@${sha}"
go get -d "${dep}@${sha}"
# Find the resolved version
rev=$(go mod edit -json | jq -r ".Require[] | select(.Path == \"${dep}\") | .Version")

View File

@@ -20,7 +20,7 @@ import (
"github.com/knative/pkg/apis/istio/v1alpha3"
"kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
"github.com/kubernetes-sigs/application/pkg/apis/app/v1beta1"
appv1beta1 "sigs.k8s.io/application/pkg/apis/app/v1beta1"
)
func init() {
@@ -31,5 +31,5 @@ func init() {
AddToSchemes = append(AddToSchemes, v1alpha3.SchemeBuilder.AddToScheme)
// Register application scheme
AddToSchemes = append(AddToSchemes, v1beta1.SchemeBuilder.AddToScheme)
AddToSchemes = append(AddToSchemes, appv1beta1.SchemeBuilder.AddToScheme)
}

View File

@@ -405,5 +405,8 @@ func addWebService(c *restful.Container) error {
Produces(restful.MIME_JSON)
c.Add(ws)
metrics.CompatibleMetrics()
return nil
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/emicklei/go-restful-openapi"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/components"
"kubesphere.io/kubesphere/pkg/apiserver/git"
@@ -257,7 +258,14 @@ func addWebService(c *restful.Container) error {
Returns(http.StatusOK, ok, status.WorkLoadStatus{}).
To(workloadstatuses.GetNamespacedAbnormalWorkloads))
c.Add(webservice)
webservice.Route(webservice.PATCH("/storageclasses/{storageclass}").
To(resources.PatchStorageClass).
Doc("patch storage class").
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ClusterResourcesTag}).
Returns(http.StatusOK, ok, storagev1.StorageClass{}).
Writes(storagev1.StorageClass{}).
Param(webservice.PathParameter("storageclass", "the name of storage class")))
c.Add(webservice)
return nil
}

View File

@@ -38,9 +38,9 @@ func GetDevOpsProjectMembersHandler(request *restful.Request, resp *restful.Resp
return
}
orderBy := request.QueryParameter(params.OrderByParam)
reverse := params.ParseReverse(request)
limit, offset := params.ParsePaging(request.QueryParameter(params.PagingParam))
conditions, err := params.ParseConditions(request.QueryParameter(params.ConditionsParam))
reverse := params.GetBoolValueWithDefault(request, params.ReverseParam, false)
limit, offset := params.ParsePaging(request)
conditions, err := params.ParseConditions(request)
project, err := devops.GetProjectMembers(projectId, conditions, orderBy, reverse, limit, offset)

View File

@@ -39,6 +39,12 @@ func CreateDevOpsProjectPipelineHandler(request *restful.Request, resp *restful.
errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp)
return
}
err = devops.ValidatePipelineConfig(pipeline)
if err != nil {
klog.Errorf("%+v", err)
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp)
return
}
pipelineName, err := devops.CreateProjectPipeline(projectId, pipeline)
if err != nil {
@@ -96,6 +102,12 @@ func UpdateDevOpsProjectPipelineHandler(request *restful.Request, resp *restful.
errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp)
return
}
err = devops.ValidatePipelineConfig(pipeline)
if err != nil {
klog.Errorf("%+v", err)
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp)
return
}
pipelineName, err := devops.UpdateProjectPipeline(projectId, pipelineId, pipeline)
if err != nil {

View File

@@ -21,6 +21,7 @@ import (
"github.com/emicklei/go-restful"
"k8s.io/api/rbac/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/server/params"
"net/http"
"sort"
@@ -50,10 +51,10 @@ func ListRoleUsers(req *restful.Request, resp *restful.Response) {
}
func ListClusterRoles(req *restful.Request, resp *restful.Response) {
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
conditions, err := params.ParseConditions(req)
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
@@ -73,10 +74,10 @@ func ListClusterRoles(req *restful.Request, resp *restful.Response) {
func ListRoles(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, resources.CreateTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
@@ -161,10 +162,10 @@ func ListClusterRoleRules(req *restful.Request, resp *restful.Response) {
func ListClusterRoleUsers(req *restful.Request, resp *restful.Response) {
clusterRoleName := req.PathParameter("clusterrole")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
conditions, err := params.ParseConditions(req)
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))

View File

@@ -20,6 +20,7 @@ package iam
import (
"fmt"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/server/params"
"net/http"
"net/mail"
@@ -149,14 +150,21 @@ func UpdateUser(req *restful.Request, resp *restful.Response) {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
if !isUserManager {
_, err = iam.Login(usernameInHeader, user.CurrentPassword, "")
}
if err != nil {
err = fmt.Errorf("incorrect current password")
klog.Info(err)
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
// user manager can modify password without verify old password
// if the old password is defined must be verified
if !isUserManager || user.CurrentPassword != "" {
if _, err = iam.Login(usernameInHeader, user.CurrentPassword, ""); err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) {
err = fmt.Errorf("incorrect current password")
klog.V(4).Info(err)
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
} else {
klog.Errorln(err)
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
}
return
}
}
}
@@ -281,15 +289,16 @@ func Precheck(req *restful.Request, resp *restful.Response) {
func ListUsers(req *restful.Request, resp *restful.Response) {
if check := req.QueryParameter("check"); check != "" {
// TODO use dry-run instead
if check := params.GetBoolValueWithDefault(req, "check", false); check {
Precheck(req, resp)
return
}
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
reverse := params.ParseReverse(req)
limit, offset := params.ParsePaging(req)
conditions, err := params.ParseConditions(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, resources.CreateTime)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
if err != nil {
klog.Info(err)

View File

@@ -32,10 +32,10 @@ import (
func ListWorkspaceRoles(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
conditions, err := params.ParseConditions(req)
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
@@ -145,10 +145,10 @@ func RemoveUser(req *restful.Request, resp *restful.Response) {
func ListWorkspaceUsers(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
conditions, err := params.ParseConditions(req)
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))

View File

@@ -36,22 +36,18 @@ import (
)
func ListApplications(req *restful.Request, resp *restful.Response) {
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
limit, offset := params.ParsePaging(req)
namespaceName := req.PathParameter("namespace")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
reverse := params.ParseReverse(req)
if orderBy == "" {
orderBy = "create_time"
reverse = true
}
conditions, err := params.ParseConditions(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
// filter namespaced applications by runtime_id
if namespaceName != "" {
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
@@ -60,6 +56,7 @@ func ListApplications(req *restful.Request, resp *restful.Response) {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
var runtimeId string
if ns, ok := namespace.(*v1.Namespace); ok {
@@ -70,7 +67,7 @@ func ListApplications(req *restful.Request, resp *restful.Response) {
resp.WriteAsJson(models.PageableResponse{Items: []interface{}{}, TotalCount: 0})
return
} else {
conditions.Match["runtime_id"] = runtimeId
conditions.Match[openpitrix.RuntimeId] = runtimeId
}
}

View File

@@ -143,23 +143,19 @@ func GetAppVersionFiles(req *restful.Request, resp *restful.Response) {
}
func ListAppVersionAudits(req *restful.Request, resp *restful.Response) {
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
appId := req.PathParameter("app")
versionId := req.PathParameter("version")
if orderBy == "" {
orderBy = "status_time"
reverse = true
}
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
conditions.Match["app"] = appId
conditions.Match[openpitrix.AppId] = appId
if versionId != "" {
conditions.Match["version"] = versionId
conditions.Match[openpitrix.VersionId] = versionId
}
result, err := openpitrix.ListAppVersionAudits(conditions, orderBy, reverse, limit, offset)
@@ -179,14 +175,11 @@ func ListAppVersionAudits(req *restful.Request, resp *restful.Response) {
}
func ListReviews(req *restful.Request, resp *restful.Response) {
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if orderBy == "" {
orderBy = "status_time"
reverse = true
}
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
@@ -209,21 +202,17 @@ func ListReviews(req *restful.Request, resp *restful.Response) {
}
func ListAppVersions(req *restful.Request, resp *restful.Response) {
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
appId := req.PathParameter("app")
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
if orderBy == "" {
orderBy = "create_time"
reverse = true
}
statistics := params.GetBoolValueWithDefault(req, "statistics", false)
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
conditions.Match["app"] = appId
conditions.Match[openpitrix.AppId] = appId
result, err := openpitrix.ListAppVersions(conditions, orderBy, reverse, limit, offset)
@@ -241,7 +230,7 @@ func ListAppVersions(req *restful.Request, resp *restful.Response) {
if statistics {
for _, item := range result.Items {
if version, ok := item.(*openpitrix.AppVersion); ok {
statisticsResult, err := openpitrix.ListApplications(&params.Conditions{Match: map[string]string{"app_id": version.AppId, "version_id": version.VersionId}}, 0, 0, "", false)
statisticsResult, err := openpitrix.ListApplications(&params.Conditions{Match: map[string]string{openpitrix.AppId: version.AppId, openpitrix.VersionId: version.VersionId}}, 0, 0, "", false)
if err != nil {
klog.Errorln(err)
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
@@ -256,15 +245,11 @@ func ListAppVersions(req *restful.Request, resp *restful.Response) {
}
func ListApps(req *restful.Request, resp *restful.Response) {
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
if orderBy == "" {
orderBy = "create_time"
reverse = true
}
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
@@ -288,7 +273,7 @@ func ListApps(req *restful.Request, resp *restful.Response) {
for _, item := range result.Items {
if app, ok := item.(*openpitrix.App); ok {
status := "active|used|enabled|stopped|pending|creating|upgrading|updating|rollbacking|stopping|starting|recovering|resizing|scaling|deleting"
statisticsResult, err := openpitrix.ListApplications(&params.Conditions{Match: map[string]string{"app_id": app.AppId, "status": status}}, 0, 0, "", false)
statisticsResult, err := openpitrix.ListApplications(&params.Conditions{Match: map[string]string{openpitrix.AppId: app.AppId, openpitrix.Status: status}}, 0, 0, "", false)
if err != nil {
klog.Errorln(err)
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
@@ -394,7 +379,7 @@ func CreateApp(req *restful.Request, resp *restful.Response) {
createAppRequest.Username = req.HeaderParameter(constants.UserNameHeader)
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
validate := params.GetBoolValueWithDefault(req, "validate", false)
var result interface{}
@@ -437,7 +422,7 @@ func CreateAppVersion(req *restful.Request, resp *restful.Response) {
createAppVersionRequest.AppId = req.PathParameter("app")
createAppVersionRequest.Username = req.HeaderParameter(constants.UserNameHeader)
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
validate := params.GetBoolValueWithDefault(req, "validate", false)
var result interface{}

View File

@@ -28,7 +28,6 @@ import (
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client"
"net/http"
"strconv"
)
func CreateCategory(req *restful.Request, resp *restful.Response) {
@@ -125,15 +124,11 @@ func DescribeCategory(req *restful.Request, resp *restful.Response) {
resp.WriteEntity(result)
}
func ListCategories(req *restful.Request, resp *restful.Response) {
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if orderBy == "" {
orderBy = "create_time"
reverse = true
}
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
statistics := params.GetBoolValueWithDefault(req, "statistics", false)
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
@@ -156,7 +151,7 @@ func ListCategories(req *restful.Request, resp *restful.Response) {
if statistics {
for _, item := range result.Items {
if category, ok := item.(*openpitrix.Category); ok {
statisticsResult, err := openpitrix.ListApps(&params.Conditions{Match: map[string]string{"category_id": category.CategoryID, "status": openpitrix.StatusActive, "repo": openpitrix.BuiltinRepoId}}, "", false, 0, 0)
statisticsResult, err := openpitrix.ListApps(&params.Conditions{Match: map[string]string{openpitrix.CategoryId: category.CategoryID, openpitrix.Status: openpitrix.StatusActive, openpitrix.RepoId: openpitrix.BuiltinRepoId}}, "", false, 0, 0)
if err != nil {
klog.Errorln(err)
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))

View File

@@ -165,14 +165,10 @@ func DescribeRepo(req *restful.Request, resp *restful.Response) {
resp.WriteEntity(result)
}
func ListRepos(req *restful.Request, resp *restful.Response) {
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if orderBy == "" {
orderBy = "create_time"
reverse = true
}
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
@@ -197,8 +193,8 @@ func ListRepos(req *restful.Request, resp *restful.Response) {
func ListRepoEvents(req *restful.Request, resp *restful.Response) {
repoId := req.PathParameter("repo")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
limit, offset := params.ParsePaging(req)
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))

View File

@@ -21,6 +21,7 @@ package registries
import (
"github.com/emicklei/go-restful"
"net/http"
"strings"
"kubesphere.io/kubesphere/pkg/models/registries"
"kubesphere.io/kubesphere/pkg/server/errors"
@@ -68,6 +69,25 @@ func RegistryImageBlob(request *restful.Request, response *restful.Response) {
return
}
// default use ssl
checkSSl := func(serverAddress string) bool {
if strings.HasPrefix(serverAddress, "http://") {
return false
} else {
return true
}
}
if strings.HasPrefix(imageName, "http") {
dockerurl, err := registries.ParseDockerURL(imageName)
if err != nil {
log.Errorf("%+v", err)
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), response)
return
}
imageName = dockerurl.StringWithoutScheme()
}
// parse image
image, err := registries.ParseImage(imageName)
if err != nil {
@@ -76,8 +96,10 @@ func RegistryImageBlob(request *restful.Request, response *restful.Response) {
return
}
useSSL := checkSSl(entry.ServerAddress)
// Create the registry client.
r, err := registries.CreateRegistryClient(entry.Username, entry.Password, image.Domain)
r, err := registries.CreateRegistryClient(entry.Username, entry.Password, image.Domain, useSSL)
if err != nil {
log.Errorf("%+v", err)
response.WriteAsJson(&registries.ImageDetails{Status: registries.StatusFailed, Message: err.Error()})

View File

@@ -33,15 +33,10 @@ func ListNamespacedResources(req *restful.Request, resp *restful.Response) {
func ListResources(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
resourceName := req.PathParameter("resources")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if orderBy == "" {
orderBy = resources.CreateTime
reverse = true
}
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, resources.CreateTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))

View File

@@ -20,8 +20,10 @@ package resources
import (
"github.com/emicklei/go-restful"
"k8s.io/api/core/v1"
"k8s.io/klog"
"net/http"
storagev1 "k8s.io/api/storage/v1"
"kubesphere.io/kubesphere/pkg/models/storage"
"kubesphere.io/kubesphere/pkg/server/errors"
)
@@ -69,3 +71,26 @@ func GetPvcListBySc(request *restful.Request, response *restful.Response) {
response.WriteAsJson(result)
}
func PatchStorageClass(request *restful.Request, response *restful.Response) {
scObj := &storagev1.StorageClass{}
err := request.ReadEntity(scObj)
if err != nil {
klog.Errorf("read entity error: %s", err.Error())
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
klog.V(5).Infof("succeed to read entity %v", scObj)
scName := request.PathParameter("storageclass")
if scObj.Annotations[storage.IsDefaultStorageClassAnnotation] == "true" {
// Set default storage class
sc, err := storage.SetDefaultStorageClass(scName)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
response.WriteEntity(sc)
return
}
response.WriteEntity(errors.None)
}

View File

@@ -58,15 +58,10 @@ func ListWorkspaceRules(req *restful.Request, resp *restful.Response) {
func ListWorkspaces(req *restful.Request, resp *restful.Response) {
username := req.HeaderParameter(constants.UserNameHeader)
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if orderBy == "" {
orderBy = resources.CreateTime
reverse = true
}
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, resources.CreateTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
conditions, err := params.ParseConditions(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
@@ -114,10 +109,10 @@ func ListNamespaces(req *restful.Request, resp *restful.Response) {
username = req.HeaderParameter(constants.UserNameHeader)
}
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
conditions, err := params.ParseConditions(req)
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, resources.CreateTime)
limit, offset := params.ParsePaging(req)
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
@@ -223,9 +218,9 @@ func ListDevopsProjects(req *restful.Request, resp *restful.Response) {
username = req.HeaderParameter(constants.UserNameHeader)
}
orderBy := req.QueryParameter(params.OrderByParam)
reverse := params.ParseReverse(req)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
limit, offset := params.ParsePaging(req)
conditions, err := params.ParseConditions(req)
if err != nil {
klog.Errorf("%+v", err)

View File

@@ -17,7 +17,7 @@ limitations under the License.
package controller
import (
"sigs.k8s.io/application/pkg/controller/application"
application "sigs.k8s.io/application/controllers"
)
func init() {

View File

@@ -4,9 +4,6 @@ import (
"fmt"
"time"
applicationclient "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
applicationinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions/app/v1beta1"
applicationlister "github.com/kubernetes-sigs/application/pkg/client/listers/app/v1beta1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -27,6 +24,9 @@ import (
servicemeshinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh/v1alpha2"
servicemeshlisters "kubesphere.io/kubesphere/pkg/client/listers/servicemesh/v1alpha2"
"kubesphere.io/kubesphere/pkg/controller/virtualservice/util"
applicationclient "sigs.k8s.io/application/pkg/client/clientset/versioned"
applicationinformers "sigs.k8s.io/application/pkg/client/informers/externalversions/app/v1beta1"
applicationlister "sigs.k8s.io/application/pkg/client/listers/app/v1beta1"
)
const (

View File

@@ -20,7 +20,6 @@ package clusterrolebinding
import (
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
@@ -29,6 +28,7 @@ import (
"k8s.io/apimachinery/pkg/types"
log "k8s.io/klog"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
"reflect"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -99,8 +99,8 @@ func (r *ReconcileClusterRoleBinding) Reconcile(request reconcile.Request) (reco
workspaceName := instance.Labels[constants.WorkspaceLabelKey]
if workspaceName != "" && k8sutil.IsControlledBy(instance.OwnerReferences, "Workspace", workspaceName) {
if instance.Name == getWorkspaceAdminRoleBindingName(workspaceName) ||
instance.Name == getWorkspaceViewerRoleBindingName(workspaceName) {
if instance.Name == iam.GetWorkspaceAdminRoleBindingName(workspaceName) ||
instance.Name == iam.GetWorkspaceViewerRoleBindingName(workspaceName) {
nsList := &corev1.NamespaceList{}
options := client.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: workspaceName})}
@@ -121,100 +121,60 @@ func (r *ReconcileClusterRoleBinding) Reconcile(request reconcile.Request) (reco
return reconcile.Result{}, nil
}
func (r *ReconcileClusterRoleBinding) updateRoleBindings(clusterRoleBinding *rbac.ClusterRoleBinding, namespace *corev1.Namespace) error {
workspaceName := namespace.Labels[constants.WorkspaceLabelKey]
if clusterRoleBinding.Name == getWorkspaceAdminRoleBindingName(workspaceName) {
adminBinding := &rbac.RoleBinding{}
adminBinding.Name = "admin"
adminBinding.Namespace = namespace.Name
adminBinding.RoleRef = rbac.RoleRef{Name: "admin", APIGroup: "rbac.authorization.k8s.io", Kind: "Role"}
adminBinding.Subjects = clusterRoleBinding.Subjects
found := &rbac.RoleBinding{}
err := r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: adminBinding.Name}, found)
func (r *ReconcileClusterRoleBinding) createRoleBindingsIfNotExist(roleBinding *rbac.RoleBinding) error {
found := &rbac.RoleBinding{}
if err := r.Get(context.TODO(), types.NamespacedName{Namespace: roleBinding.Namespace, Name: roleBinding.Name}, found); err != nil {
if errors.IsNotFound(err) {
err = r.Create(context.TODO(), adminBinding)
err := r.Create(context.TODO(), roleBinding)
if err != nil {
log.Error(err)
log.Errorln(err)
}
return err
} else if err != nil {
log.Error(err)
return err
}
if !reflect.DeepEqual(found.RoleRef, adminBinding.RoleRef) {
err = r.Delete(context.TODO(), found)
if err != nil {
log.Error(err)
return err
}
return fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, adminBinding.Name)
}
if !reflect.DeepEqual(found.Subjects, adminBinding.Subjects) {
found.Subjects = adminBinding.Subjects
err = r.Update(context.TODO(), found)
if err != nil {
log.Error(err)
return err
}
}
log.Errorln(err)
return err
}
if clusterRoleBinding.Name == getWorkspaceViewerRoleBindingName(workspaceName) {
found := &rbac.RoleBinding{}
viewerBinding := &rbac.RoleBinding{}
viewerBinding.Name = "viewer"
viewerBinding.Namespace = namespace.Name
viewerBinding.RoleRef = rbac.RoleRef{Name: "viewer", APIGroup: "rbac.authorization.k8s.io", Kind: "Role"}
viewerBinding.Subjects = clusterRoleBinding.Subjects
err := r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: viewerBinding.Name}, found)
if errors.IsNotFound(err) {
err = r.Create(context.TODO(), viewerBinding)
if err != nil {
log.Error(err)
}
if !reflect.DeepEqual(found.Subjects, roleBinding.Subjects) {
found.Subjects = roleBinding.Subjects
if err := r.Update(context.TODO(), found); err != nil {
log.Errorln(err)
return err
} else if err != nil {
log.Error(err)
return err
}
if !reflect.DeepEqual(found.RoleRef, viewerBinding.RoleRef) {
err = r.Delete(context.TODO(), found)
if err != nil {
log.Error(err)
return err
}
return fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, viewerBinding.Name)
}
if !reflect.DeepEqual(found.Subjects, viewerBinding.Subjects) {
found.Subjects = viewerBinding.Subjects
err = r.Update(context.TODO(), found)
if err != nil {
log.Error(err)
return err
}
}
}
return nil
}
func getWorkspaceAdminRoleBindingName(workspaceName string) string {
return fmt.Sprintf("workspace:%s:admin", workspaceName)
}
func (r *ReconcileClusterRoleBinding) updateRoleBindings(clusterRoleBinding *rbac.ClusterRoleBinding, namespace *corev1.Namespace) error {
func getWorkspaceViewerRoleBindingName(workspaceName string) string {
return fmt.Sprintf("workspace:%s:viewer", workspaceName)
workspaceName := namespace.Labels[constants.WorkspaceLabelKey]
if clusterRoleBinding.Name == iam.GetWorkspaceAdminRoleBindingName(workspaceName) {
adminBinding := &rbac.RoleBinding{}
adminBinding.Name = iam.NamespaceAdminRoleBindName
adminBinding.Namespace = namespace.Name
adminBinding.RoleRef = rbac.RoleRef{Name: iam.NamespaceAdminRoleName, APIGroup: "rbac.authorization.k8s.io", Kind: iam.RoleKind}
adminBinding.Subjects = clusterRoleBinding.Subjects
if err := r.createRoleBindingsIfNotExist(adminBinding); err != nil {
log.Errorln(err)
return err
}
}
if clusterRoleBinding.Name == iam.GetWorkspaceViewerRoleBindingName(workspaceName) {
viewerBinding := &rbac.RoleBinding{}
viewerBinding.Name = iam.NamespaceViewerRoleBindName
viewerBinding.Namespace = namespace.Name
viewerBinding.RoleRef = rbac.RoleRef{Name: iam.NamespaceViewerRoleName, APIGroup: "rbac.authorization.k8s.io", Kind: iam.RoleKind}
viewerBinding.Subjects = clusterRoleBinding.Subjects
if err := r.createRoleBindingsIfNotExist(viewerBinding); err != nil {
log.Errorln(err)
return err
}
}
return nil
}

View File

@@ -32,9 +32,9 @@ import (
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/iam"
cs "kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"openpitrix.io/openpitrix/pkg/pb"
"reflect"
@@ -54,12 +54,12 @@ const (
)
var (
admin = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "admin", Annotations: map[string]string{constants.DescriptionAnnotationKey: adminDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}}
operator = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "operator", Annotations: map[string]string{constants.DescriptionAnnotationKey: operatorDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}},
admin = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: iam.NamespaceAdminRoleName, Annotations: map[string]string{constants.DescriptionAnnotationKey: adminDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}}
operator = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: iam.NamespaceOperatorRoleName, Annotations: map[string]string{constants.DescriptionAnnotationKey: operatorDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}},
{Verbs: []string{"*"}, APIGroups: []string{"apps", "extensions", "batch", "logging.kubesphere.io", "monitoring.kubesphere.io", "iam.kubesphere.io", "autoscaling", "alerting.kubesphere.io", "openpitrix.io", "app.k8s.io", "servicemesh.kubesphere.io", "operations.kubesphere.io", "devops.kubesphere.io"}, Resources: []string{"*"}},
{Verbs: []string{"*"}, APIGroups: []string{"", "resources.kubesphere.io"}, Resources: []string{"jobs", "cronjobs", "daemonsets", "deployments", "horizontalpodautoscalers", "ingresses", "endpoints", "configmaps", "events", "persistentvolumeclaims", "pods", "podtemplates", "pods", "secrets", "services"}},
}}
viewer = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: "viewer", Annotations: map[string]string{constants.DescriptionAnnotationKey: viewerDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}}
viewer = rbac.Role{ObjectMeta: metav1.ObjectMeta{Name: iam.NamespaceViewerRoleName, Annotations: map[string]string{constants.DescriptionAnnotationKey: viewerDescription, constants.CreatorAnnotationKey: constants.System}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}}
defaultRoles = []rbac.Role{admin, operator, viewer}
)
@@ -170,9 +170,15 @@ func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (reconcile.Res
if !controlledByWorkspace {
err = r.deleteRoleBindings(instance)
if err = r.unbindWorkspace(instance); err != nil {
return reconcile.Result{}, err
}
return reconcile.Result{}, err
if err = r.deleteRoleBindings(instance); err != nil {
return reconcile.Result{}, err
}
return reconcile.Result{}, nil
}
if err = r.checkAndBindWorkspace(instance); err != nil {
@@ -220,6 +226,7 @@ func (r *ReconcileNamespace) checkAndCreateRoles(namespace *corev1.Namespace) er
klog.Error(err)
return err
}
found = role
} else {
klog.Error(err)
return err
@@ -236,119 +243,84 @@ func (r *ReconcileNamespace) checkAndCreateRoles(namespace *corev1.Namespace) er
return nil
}
func (r *ReconcileNamespace) createRoleBindingsIfNotExist(roleBinding *rbac.RoleBinding) error {
found := &rbac.RoleBinding{}
if err := r.Get(context.TODO(), types.NamespacedName{Namespace: roleBinding.Namespace, Name: roleBinding.Name}, found); err != nil {
if errors.IsNotFound(err) {
err := r.Create(context.TODO(), roleBinding)
if err != nil {
klog.Errorln(err)
}
return err
}
klog.Errorln(err)
return err
}
if !reflect.DeepEqual(found.Subjects, roleBinding.Subjects) {
found.Subjects = roleBinding.Subjects
if err := r.Update(context.TODO(), found); err != nil {
klog.Errorln(err)
return err
}
}
return nil
}
func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namespace) error {
workspaceName := namespace.Labels[constants.WorkspaceLabelKey]
creatorName := namespace.Annotations[constants.CreatorAnnotationKey]
creator := rbac.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: creatorName}
if creatorName != "" {
creatorRoleBinding := &rbac.RoleBinding{}
creatorRoleBinding.Name = fmt.Sprintf("%s-%s", admin.Name, creatorName)
creatorRoleBinding.Namespace = namespace.Name
creatorRoleBinding.RoleRef = rbac.RoleRef{Name: admin.Name, APIGroup: "rbac.authorization.k8s.io", Kind: "Role"}
creatorRoleBinding.Subjects = []rbac.Subject{{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: creatorName}}
if err := r.createRoleBindingsIfNotExist(creatorRoleBinding); err != nil {
klog.Errorln(err)
return err
}
}
workspaceAdminBinding := &rbac.ClusterRoleBinding{}
err := r.Get(context.TODO(), types.NamespacedName{Name: fmt.Sprintf("workspace:%s:admin", workspaceName)}, workspaceAdminBinding)
if err != nil {
if err := r.Get(context.TODO(), types.NamespacedName{Name: iam.GetWorkspaceAdminRoleBindingName(workspaceName)}, workspaceAdminBinding); err != nil {
klog.Errorln(err)
return err
}
adminBinding := &rbac.RoleBinding{}
adminBinding.Name = admin.Name
adminBinding.Name = iam.NamespaceAdminRoleBindName
adminBinding.Namespace = namespace.Name
adminBinding.RoleRef = rbac.RoleRef{Name: admin.Name, APIGroup: "rbac.authorization.k8s.io", Kind: "Role"}
adminBinding.RoleRef = rbac.RoleRef{Name: admin.Name, APIGroup: "rbac.authorization.k8s.io", Kind: iam.RoleKind}
adminBinding.Subjects = workspaceAdminBinding.Subjects
if creator.Name != "" {
if adminBinding.Subjects == nil {
adminBinding.Subjects = make([]rbac.Subject, 0)
}
if !k8sutil.ContainsUser(adminBinding.Subjects, creatorName) {
adminBinding.Subjects = append(adminBinding.Subjects, creator)
}
}
found := &rbac.RoleBinding{}
err = r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: adminBinding.Name}, found)
if errors.IsNotFound(err) {
err = r.Create(context.TODO(), adminBinding)
if err != nil {
klog.Errorf("creating role binding namespace: %s,role binding: %s, error: %s", namespace.Name, adminBinding.Name, err)
return err
}
found = adminBinding
} else if err != nil {
klog.Errorf("get role binding namespace: %s,role binding: %s, error: %s", namespace.Name, adminBinding.Name, err)
if err := r.createRoleBindingsIfNotExist(adminBinding); err != nil {
klog.Errorln(err)
return err
}
if !reflect.DeepEqual(found.RoleRef, adminBinding.RoleRef) {
err = r.Delete(context.TODO(), found)
if err != nil {
klog.Errorf("deleting role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err)
return err
}
err = fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, adminBinding.Name)
klog.Errorf("conflict role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err)
return err
}
if !reflect.DeepEqual(found.Subjects, adminBinding.Subjects) {
found.Subjects = adminBinding.Subjects
err = r.Update(context.TODO(), found)
if err != nil {
klog.Errorf("updating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, adminBinding.Name, err)
return err
}
}
workspaceViewerBinding := &rbac.ClusterRoleBinding{}
err = r.Get(context.TODO(), types.NamespacedName{Name: fmt.Sprintf("workspace:%s:viewer", workspaceName)}, workspaceViewerBinding)
if err != nil {
if err := r.Get(context.TODO(), types.NamespacedName{Name: iam.GetWorkspaceViewerRoleBindingName(workspaceName)}, workspaceViewerBinding); err != nil {
klog.Errorln(err)
return err
}
viewerBinding := &rbac.RoleBinding{}
viewerBinding.Name = viewer.Name
viewerBinding.Name = iam.NamespaceViewerRoleBindName
viewerBinding.Namespace = namespace.Name
viewerBinding.RoleRef = rbac.RoleRef{Name: viewer.Name, APIGroup: "rbac.authorization.k8s.io", Kind: "Role"}
viewerBinding.RoleRef = rbac.RoleRef{Name: viewer.Name, APIGroup: "rbac.authorization.k8s.io", Kind: iam.RoleKind}
viewerBinding.Subjects = workspaceViewerBinding.Subjects
err = r.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: viewerBinding.Name}, found)
if errors.IsNotFound(err) {
err = r.Create(context.TODO(), viewerBinding)
if err != nil {
klog.Errorf("creating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err)
return err
}
found = viewerBinding
} else if err != nil {
if err := r.createRoleBindingsIfNotExist(viewerBinding); err != nil {
klog.Errorln(err)
return err
}
if !reflect.DeepEqual(found.RoleRef, viewerBinding.RoleRef) {
err = r.Delete(context.TODO(), found)
if err != nil {
klog.Errorf("deleting conflict role binding namespace: %s, role binding: %s, %s", namespace.Name, viewerBinding.Name, err)
return err
}
err = fmt.Errorf("conflict role binding %s.%s, waiting for recreate", namespace.Name, viewerBinding.Name)
klog.Errorf("conflict role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err)
return err
}
if !reflect.DeepEqual(found.Subjects, viewerBinding.Subjects) {
found.Subjects = viewerBinding.Subjects
err = r.Update(context.TODO(), found)
if err != nil {
klog.Errorf("updating role binding namespace: %s, role binding: %s, error: %s", namespace.Name, viewerBinding.Name, err)
return err
}
}
return nil
}
@@ -451,6 +423,21 @@ func (r *ReconcileNamespace) deleteRuntime(namespace *corev1.Namespace) error {
return nil
}
func (r *ReconcileNamespace) unbindWorkspace(instance *corev1.Namespace) error {
ownerReferences := make([]metav1.OwnerReference, 0)
for _, ref := range instance.OwnerReferences {
if ref.Kind != v1alpha1.ResourceKindWorkspace {
ownerReferences = append(ownerReferences, ref)
}
}
if len(ownerReferences) != len(instance.OwnerReferences) {
instance.OwnerReferences = ownerReferences
return r.Update(context.TODO(), instance)
}
return nil
}
// Create openpitrix runtime
func (r *ReconcileNamespace) checkAndBindWorkspace(namespace *corev1.Namespace) error {

View File

@@ -530,7 +530,7 @@ func (j *Jenkins) CreateSshCredential(id, username, passphrase, privateKey, desc
requestStruct := NewCreateSshCredentialRequest(id, username, passphrase, privateKey, description)
param := map[string]string{"json": makeJson(requestStruct)}
responseString := ""
response, err := j.Requester.Post("/credentials/store/system/domain/_/createCredentials",
response, err := j.Requester.PostForm("/credentials/store/system/domain/_/createCredentials",
nil, &responseString, param)
if err != nil {
return nil, err
@@ -545,7 +545,7 @@ func (j *Jenkins) CreateUsernamePasswordCredential(id, username, password, descr
requestStruct := NewCreateUsernamePasswordRequest(id, username, password, description)
param := map[string]string{"json": makeJson(requestStruct)}
responseString := ""
response, err := j.Requester.Post("/credentials/store/system/domain/_/createCredentials",
response, err := j.Requester.PostForm("/credentials/store/system/domain/_/createCredentials",
nil, &responseString, param)
if err != nil {
return nil, err
@@ -570,7 +570,7 @@ func (j *Jenkins) CreateSshCredentialInFolder(domain, id, username, passphrase,
for _, folder := range folders {
prePath = prePath + fmt.Sprintf("/job/%s", folder)
}
response, err := j.Requester.Post(prePath+
response, err := j.Requester.PostForm(prePath+
fmt.Sprintf("/credentials/store/folder/domain/%s/createCredentials", domain),
nil, &responseString, param)
if err != nil {
@@ -596,7 +596,7 @@ func (j *Jenkins) CreateUsernamePasswordCredentialInFolder(domain, id, username,
for _, folder := range folders {
prePath = prePath + fmt.Sprintf("/job/%s", folder)
}
response, err := j.Requester.Post(prePath+
response, err := j.Requester.PostForm(prePath+
fmt.Sprintf("/credentials/store/folder/domain/%s/createCredentials", domain),
nil, &responseString, param)
if err != nil {
@@ -622,7 +622,7 @@ func (j *Jenkins) CreateSecretTextCredentialInFolder(domain, id, secret, descrip
for _, folder := range folders {
prePath = prePath + fmt.Sprintf("/job/%s", folder)
}
response, err := j.Requester.Post(prePath+
response, err := j.Requester.PostForm(prePath+
fmt.Sprintf("/credentials/store/folder/domain/%s/createCredentials", domain),
nil, &responseString, param)
if err != nil {
@@ -648,7 +648,7 @@ func (j *Jenkins) CreateKubeconfigCredentialInFolder(domain, id, content, descri
for _, folder := range folders {
prePath = prePath + fmt.Sprintf("/job/%s", folder)
}
response, err := j.Requester.Post(prePath+
response, err := j.Requester.PostForm(prePath+
fmt.Sprintf("/credentials/store/folder/domain/%s/createCredentials", domain),
nil, &responseString, param)
if err != nil {
@@ -673,7 +673,7 @@ func (j *Jenkins) UpdateSshCredentialInFolder(domain, id, username, passphrase,
for _, folder := range folders {
prePath = prePath + fmt.Sprintf("/job/%s", folder)
}
response, err := j.Requester.Post(prePath+
response, err := j.Requester.PostForm(prePath+
fmt.Sprintf("/credentials/store/folder/domain/%s/credential/%s/updateSubmit", domain, id),
nil, nil, param)
if err != nil {
@@ -698,7 +698,7 @@ func (j *Jenkins) UpdateUsernamePasswordCredentialInFolder(domain, id, username,
for _, folder := range folders {
prePath = prePath + fmt.Sprintf("/job/%s", folder)
}
response, err := j.Requester.Post(prePath+
response, err := j.Requester.PostForm(prePath+
fmt.Sprintf("/credentials/store/folder/domain/%s/credential/%s/updateSubmit", domain, id),
nil, nil, param)
if err != nil {
@@ -723,7 +723,7 @@ func (j *Jenkins) UpdateSecretTextCredentialInFolder(domain, id, secret, descrip
for _, folder := range folders {
prePath = prePath + fmt.Sprintf("/job/%s", folder)
}
response, err := j.Requester.Post(prePath+
response, err := j.Requester.PostForm(prePath+
fmt.Sprintf("/credentials/store/folder/domain/%s/credential/%s/updateSubmit", domain, id),
nil, nil, param)
if err != nil {
@@ -748,7 +748,7 @@ func (j *Jenkins) UpdateKubeconfigCredentialInFolder(domain, id, content, descri
for _, folder := range folders {
prePath = prePath + fmt.Sprintf("/job/%s", folder)
}
response, err := j.Requester.Post(prePath+
response, err := j.Requester.PostForm(prePath+
fmt.Sprintf("/credentials/store/folder/domain/%s/credential/%s/updateSubmit", domain, id),
nil, nil, param)
if err != nil {

View File

@@ -18,11 +18,11 @@
package informers
import (
applicationinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
s2iinformers "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
k8sinformers "k8s.io/client-go/informers"
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/simple/client"
applicationinformers "sigs.k8s.io/application/pkg/client/informers/externalversions"
"sync"
"time"
)

View File

@@ -15,14 +15,15 @@ package devops
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/beevik/etree"
"github.com/kubesphere/sonargo/sonar"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/gojenkins"
"kubesphere.io/kubesphere/pkg/simple/client"
"strconv"
"strings"
"time"
)
const (
@@ -375,16 +376,50 @@ func (s *Parameters) fromEtree(properties *etree.Element) *Parameters {
*s = append(*s, &Parameter{
Name: param.SelectElement("name").Text(),
Description: param.SelectElement("description").Text(),
DefaultValue: param.SelectElement("name").Text(),
DefaultValue: param.SelectElement("defaultValue").Text(),
Type: ParameterTypeMap["hudson.model.PasswordParameterDefinition"],
})
case "hudson.model.ChoiceParameterDefinition":
/*
In Jenkins, different configuration methods will lead to different serialization results.
We need to be compatible with serialization results.
case1: Configured by KubeSphere console / Jenkins console
<hudson.model.ChoiceParameterDefinition>
<name>1</name>
<description>x</description>
<choices class="java.util.Arrays$ArrayList">
<a class="string-array">
<string>1</string>
<string>2</string>
<string>3</string>
</a>
</choices>
</hudson.model.ChoiceParameterDefinition>
case2: Configured by pipeline syntax, sample: parameters { choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '') }
<hudson.model.ChoiceParameterDefinition>
<name>1</name>
<description>x</description>
<choices class="java.util.Arrays$ArrayList">
<string>1</string>
<string>2</string>
<string>3</string>
</choices>
</hudson.model.ChoiceParameterDefinition>
*/
choiceParameter := &Parameter{
Name: param.SelectElement("name").Text(),
Description: param.SelectElement("description").Text(),
Type: ParameterTypeMap["hudson.model.ChoiceParameterDefinition"],
}
choices := param.SelectElement("choices").SelectElement("a").SelectElements("string")
choicesSection := param.SelectElement("choices")
a := choicesSection.SelectElement("a")
var choices []*etree.Element
if a != nil {
choices = a.SelectElements("string")
} else {
choices = choicesSection.SelectElements("string")
}
for _, choice := range choices {
choiceParameter.DefaultValue += fmt.Sprintf("%s\n", choice.Text())
}

View File

@@ -309,3 +309,39 @@ func GetMultiBranchPipelineSonar(projectId, pipelineId, branchId string) ([]*Son
}
return sonarStatus, nil
}
func ValidatePipelineConfig(pipeline *ProjectPipeline) error {
switch pipeline.Type {
case NoScmPipelineType:
if pipeline.Pipeline == nil {
err := fmt.Errorf("request should contains Pipeline struct")
return err
}
if pipeline.Pipeline.Name == "" {
err := fmt.Errorf("pipeline name suport not be nil")
return err
}
if pipeline.Pipeline.Parameters != nil {
params := []*Parameter(*pipeline.Pipeline.Parameters)
for _, param := range params {
if param.Name == "" {
err := fmt.Errorf("param name should not be nil")
return err
}
}
}
case MultiBranchPipelineType:
if pipeline.MultiBranchPipeline == nil {
err := fmt.Errorf("request should contains MultiBranchPipeline struct")
return err
}
if pipeline.MultiBranchPipeline.Name == "" {
err := fmt.Errorf("pipeline name suport not be nil")
return err
}
default:
err := fmt.Errorf("unsupport job type")
return err
}
return nil
}

View File

@@ -631,3 +631,266 @@ func Test_MultiBranchPipelineMultibranchTrigger(t *testing.T) {
}
}
func Test_ParsePipelineConfigChoiceParameters(t *testing.T) {
case1 := `<flow-definition plugin="workflow-job@2.32">
<actions>
<org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobAction plugin="pipeline-model-definition@1.3.9"/>
<org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobPropertyTrackerAction plugin="pipeline-model-definition@1.3.9">
<jobProperties/>
<triggers/>
<parameters>
<string>BIOGRAPHY</string>
<string>PERSON</string>
<string>PASSWORD</string>
<string>TOGGLE</string>
</parameters>
<options/>
</org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobPropertyTrackerAction>
</actions>
<description/>
<keepDependencies>false</keepDependencies>
<properties>
<hudson.plugins.jira.JiraProjectProperty plugin="jira@3.0.8"/>
<jenkins.model.BuildDiscarderProperty>
<strategy class="hudson.tasks.LogRotator">
<daysToKeep>7</daysToKeep>
<numToKeep>10</numToKeep>
<artifactDaysToKeep>-1</artifactDaysToKeep>
<artifactNumToKeep>-1</artifactNumToKeep>
</strategy>
</jenkins.model.BuildDiscarderProperty>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.StringParameterDefinition>
<name>PERSON</name>
<description>Who should I say hello to?</description>
<defaultValue>Mr Jenkins</defaultValue>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.TextParameterDefinition>
<name>BIOGRAPHY</name>
<description>Enter some information about the person</description>
<defaultValue/>
<trim>false</trim>
</hudson.model.TextParameterDefinition>
<hudson.model.BooleanParameterDefinition>
<name>TOGGLE</name>
<description>Toggle this value</description>
<defaultValue>true</defaultValue>
</hudson.model.BooleanParameterDefinition>
<hudson.model.PasswordParameterDefinition>
<name>PASSWORD</name>
<description>Enter a password</description>
<defaultValue>
{AQAAABAAAAAQHD/HoXKklrRKtlQ5ylr1lgN1dj7im57I8SGfkLIe17s=}
</defaultValue>
</hudson.model.PasswordParameterDefinition>
<hudson.model.ChoiceParameterDefinition>
<name>1</name>
<description>x</description>
<choices class="java.util.Arrays$ArrayList">
<a class="string-array">
<string>1</string>
<string>2</string>
<string>3</string>
</a>
</choices>
</hudson.model.ChoiceParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps@2.73">
<script>
pipeline { agent any parameters { string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?') text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person') booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value') password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password') } stages { stage('Example') { steps { echo "Hello ${params.PERSON}" echo "Biography: ${params.BIOGRAPHY}" echo "Toggle: ${params.TOGGLE}" echo "Choice: ${params.CHOICE}" echo "Password: ${params.PASSWORD}" } } } }
</script>
<sandbox>true</sandbox>
</definition>
<triggers/>
<disabled>false</disabled>
</flow-definition>`
case2 := `
<flow-definition plugin="workflow-job@2.32">
<actions>
<org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobAction plugin="pipeline-model-definition@1.3.9"/>
<org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobPropertyTrackerAction plugin="pipeline-model-definition@1.3.9">
<jobProperties/>
<triggers/>
<parameters>
<string>BIOGRAPHY</string>
<string>PERSON</string>
<string>PASSWORD</string>
<string>TOGGLE</string>
</parameters>
<options/>
</org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobPropertyTrackerAction>
</actions>
<description/>
<keepDependencies>false</keepDependencies>
<properties>
<hudson.plugins.jira.JiraProjectProperty plugin="jira@3.0.8"/>
<jenkins.model.BuildDiscarderProperty>
<strategy class="hudson.tasks.LogRotator">
<daysToKeep>7</daysToKeep>
<numToKeep>10</numToKeep>
<artifactDaysToKeep>-1</artifactDaysToKeep>
<artifactNumToKeep>-1</artifactNumToKeep>
</strategy>
</jenkins.model.BuildDiscarderProperty>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.StringParameterDefinition>
<name>PERSON</name>
<description>Who should I say hello to?</description>
<defaultValue>Mr Jenkins</defaultValue>
<trim>false</trim>
</hudson.model.StringParameterDefinition>
<hudson.model.TextParameterDefinition>
<name>BIOGRAPHY</name>
<description>Enter some information about the person</description>
<defaultValue/>
<trim>false</trim>
</hudson.model.TextParameterDefinition>
<hudson.model.BooleanParameterDefinition>
<name>TOGGLE</name>
<description>Toggle this value</description>
<defaultValue>true</defaultValue>
</hudson.model.BooleanParameterDefinition>
<hudson.model.PasswordParameterDefinition>
<name>PASSWORD</name>
<description>Enter a password</description>
<defaultValue>
{AQAAABAAAAAQHD/HoXKklrRKtlQ5ylr1lgN1dj7im57I8SGfkLIe17s=}
</defaultValue>
</hudson.model.PasswordParameterDefinition>
<hudson.model.ChoiceParameterDefinition>
<name>1</name>
<description>x</description>
<choices class="java.util.Arrays$ArrayList">
<string>1</string>
<string>2</string>
<string>3</string>
</choices>
</hudson.model.ChoiceParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps@2.73">
<script>
pipeline { agent any parameters { string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?') text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person') booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value') password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password') } stages { stage('Example') { steps { echo "Hello ${params.PERSON}" echo "Biography: ${params.BIOGRAPHY}" echo "Toggle: ${params.TOGGLE}" echo "Choice: ${params.CHOICE}" echo "Password: ${params.PASSWORD}" } } } }
</script>
<sandbox>true</sandbox>
</definition>
<triggers/>
<disabled>false</disabled>
</flow-definition>`
case1Pipeline, err := parsePipelineConfigXml(case1)
if err != nil {
t.Fatal(err)
}
case2Pipeline, err := parsePipelineConfigXml(case2)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(case1Pipeline, case2Pipeline) {
t.Fatalf("case1 [%+v] case2 [%+v] should equal ", case1Pipeline, case2Pipeline)
}
}
func Test_ValidatePipelineConfig(t *testing.T) {
rightInput := []*ProjectPipeline{
{
Type: "pipeline",
Pipeline: &NoScmPipeline{
Name: "test",
Parameters: nil,
Jenkinsfile: "echo 1",
},
}, {
Type: "multi-branch-pipeline",
MultiBranchPipeline: &MultiBranchPipeline{
Name: "multibranch-test",
Description: "xx",
},
}, {
Type: "pipeline",
Pipeline: &NoScmPipeline{
Name: "test2",
Description: "",
Discarder: nil,
Parameters: &Parameters{
&Parameter{
Name: "xx",
Type: "yy",
}, &Parameter{
Name: "tt",
DefaultValue: "",
Type: "",
Description: "ccc",
},
},
DisableConcurrent: false,
TimerTrigger: nil,
RemoteTrigger: nil,
Jenkinsfile: "",
},
},
}
errorInput := []*ProjectPipeline{
{
Type: "xx",
Pipeline: &NoScmPipeline{
Name: "",
Parameters: nil,
Jenkinsfile: "echo 1",
},
},
{
Type: "pipeline",
Pipeline: &NoScmPipeline{
Name: "",
Parameters: nil,
Jenkinsfile: "echo 1",
},
}, {
Type: "multi-branch-pipeline",
MultiBranchPipeline: &MultiBranchPipeline{
Name: "",
Description: "xx",
},
}, {
Type: "pipeline",
Pipeline: &NoScmPipeline{
Name: "test2",
Description: "",
Discarder: nil,
Parameters: &Parameters{
&Parameter{
Name: "",
Type: "yy",
}, &Parameter{
Name: "tt",
Description: "ccc",
},
},
Jenkinsfile: "",
},
},
}
for _, input := range rightInput {
err := ValidatePipelineConfig(input)
if err != nil {
t.Fatal(err)
}
}
for _, input := range errorInput {
err := ValidatePipelineConfig(input)
if err == nil {
t.Fatalf("%+v, is an error configuration", input)
}
}
}

View File

@@ -42,10 +42,22 @@ import (
const (
ClusterRoleKind = "ClusterRole"
NamespaceAdminRoleBindName = "admin"
NamespaceViewerRoleBindName = "viewer"
RoleKind = "Role"
NamespaceAdminRoleName = "admin"
NamespaceOperatorRoleName = "operator"
NamespaceViewerRoleName = "viewer"
NamespaceAdminRoleBindName = NamespaceAdminRoleName
NamespaceViewerRoleBindName = NamespaceViewerRoleName
)
func GetWorkspaceAdminRoleBindingName(workspaceName string) string {
return fmt.Sprintf("workspace:%s:admin", workspaceName)
}
func GetWorkspaceViewerRoleBindingName(workspaceName string) string {
return fmt.Sprintf("workspace:%s:viewer", workspaceName)
}
func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
var rules []models.SimpleRule
@@ -489,23 +501,21 @@ func GetUserWorkspaceSimpleRules(workspace, username string) ([]models.SimpleRul
return GetWorkspaceRoleSimpleRules(workspace, constants.WorkspaceAdmin), nil
}
// workspaces-manager
if RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{
Verbs: []string{"*"},
APIGroups: []string{"*"},
Resources: []string{"workspaces", "workspaces/*"},
}) {
return GetWorkspaceRoleSimpleRules(workspace, constants.WorkspacesManager), nil
}
workspaceRole, err := GetUserWorkspaceRole(workspace, username)
if err != nil {
if apierrors.IsNotFound(err) {
// workspaces-manager
if RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{
Verbs: []string{"*"},
APIGroups: []string{"*"},
Resources: []string{"workspaces", "workspaces/*"},
}) {
return GetWorkspaceRoleSimpleRules(workspace, constants.WorkspacesManager), nil
}
return []models.SimpleRule{}, nil
}
klog.Error(err)
return nil, err
}

View File

@@ -504,6 +504,19 @@ func loginLog(uid, ip string) {
redisClient.LTrim(fmt.Sprintf("kubesphere:users:%s:login-log", uid), -10, -1)
}
}
func deleteLoginLogs(uid string) error {
redisClient, err := clientset.ClientSets().Redis()
if err != nil {
klog.Errorln(err)
return err
}
err = redisClient.Del(fmt.Sprintf("kubesphere:users:%s:login-log", uid)).Err()
if err != nil {
klog.Errorln(err)
return err
}
return nil
}
func LoginLog(username string) ([]string, error) {
redisClient, err := clientset.ClientSets().Redis()
@@ -790,6 +803,11 @@ func DeleteUser(username string) error {
if err := deleteUserInDevOps(username); err != nil {
klog.Errorln("delete user in devops failed", username, err)
}
if err := deleteLoginLogs(username); err != nil {
klog.Errorln(err)
}
return nil
}

View File

@@ -0,0 +1,64 @@
/*
*
* Copyright 2020 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 pkiutil
import (
"crypto"
cryptorand "crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"github.com/pkg/errors"
certutil "k8s.io/client-go/util/cert"
)
// NewCSRAndKey generates a new key and CSR and that could be signed to create the given certificate
func NewCSRAndKey(config *certutil.Config) (*x509.CertificateRequest, *rsa.PrivateKey, error) {
key, err := certutil.NewPrivateKey()
if err != nil {
return nil, nil, errors.Wrap(err, "unable to create private key")
}
csr, err := NewCSR(*config, key)
if err != nil {
return nil, nil, errors.Wrap(err, "unable to generate CSR")
}
return csr, key, nil
}
// NewCSR creates a new CSR
func NewCSR(cfg certutil.Config, key crypto.Signer) (*x509.CertificateRequest, error) {
template := &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: cfg.CommonName,
Organization: cfg.Organization,
},
DNSNames: cfg.AltNames.DNSNames,
IPAddresses: cfg.AltNames.IPs,
}
csrBytes, err := x509.CreateCertificateRequest(cryptorand.Reader, template, key)
if err != nil {
return nil, errors.Wrap(err, "failed to create a CSR")
}
return x509.ParseCertificateRequest(csrBytes)
}

View File

@@ -21,294 +21,237 @@ package kubeconfig
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/pem"
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/simple/client"
"math/big"
rd "math/rand"
"time"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
certutil "k8s.io/client-go/util/cert"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/constants"
pkiutil "kubesphere.io/kubesphere/pkg/models/kubeconfig/internal"
"kubesphere.io/kubesphere/pkg/simple/client"
"time"
)
const (
caPath = "/etc/kubernetes/pki/ca.crt"
keyPath = "/etc/kubernetes/pki/ca.key"
clusterName = "kubernetes"
kubectlConfigKey = "config"
defaultNamespace = "default"
inClusterCAFilePath = "/run/secrets/kubernetes.io/serviceaccount/ca.crt"
kubeconfigNameFormat = "kubeconfig-%s"
defaultClusterName = "local"
defaultNamespace = "default"
fileName = "config"
configMapKind = "ConfigMap"
configMapAPIVersion = "v1"
)
type clusterInfo struct {
CertificateAuthorityData string `yaml:"certificate-authority-data"`
Server string `yaml:"server"`
}
type cluster struct {
Cluster clusterInfo `yaml:"cluster"`
Name string `yaml:"name"`
}
type contextInfo struct {
Cluster string `yaml:"cluster"`
User string `yaml:"user"`
NameSpace string `yaml:"namespace"`
}
type contextObject struct {
Context contextInfo `yaml:"context"`
Name string `yaml:"name"`
}
type userInfo struct {
CaData string `yaml:"client-certificate-data"`
KeyData string `yaml:"client-key-data"`
}
type user struct {
Name string `yaml:"name"`
User userInfo `yaml:"user"`
}
type kubeConfig struct {
ApiVersion string `yaml:"apiVersion"`
Clusters []cluster `yaml:"clusters"`
Contexts []contextObject `yaml:"contexts"`
CurrentContext string `yaml:"current-context"`
Kind string `yaml:"kind"`
Preferences map[string]string `yaml:"preferences"`
Users []user `yaml:"users"`
}
type CertInformation struct {
Country []string
Organization []string
OrganizationalUnit []string
EmailAddress []string
Province []string
Locality []string
CommonName string
CrtName, KeyName string
IsCA bool
Names []pkix.AttributeTypeAndValue
}
func createCRT(RootCa *x509.Certificate, RootKey *rsa.PrivateKey, info CertInformation) ([]byte, []byte, error) {
var cert, key bytes.Buffer
Crt := newCertificate(info)
Key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
klog.Error(err)
return nil, nil, err
}
var buf []byte
buf, err = x509.CreateCertificate(rand.Reader, Crt, RootCa, &Key.PublicKey, RootKey)
if err != nil {
klog.Error(err)
return nil, nil, err
}
pem.Encode(&cert, &pem.Block{Type: "CERTIFICATE", Bytes: buf})
if err != nil {
klog.Error(err)
return nil, nil, err
}
buf = x509.MarshalPKCS1PrivateKey(Key)
pem.Encode(&key, &pem.Block{Type: "PRIVATE KEY", Bytes: buf})
return cert.Bytes(), key.Bytes(), nil
}
func Parse(crtPath, keyPath string) (rootcertificate *x509.Certificate, rootPrivateKey *rsa.PrivateKey, err error) {
rootcertificate, err = parseCrt(crtPath)
if err != nil {
klog.Error(err)
return nil, nil, err
}
rootPrivateKey, err = parseKey(keyPath)
return rootcertificate, rootPrivateKey, nil
}
func parseCrt(path string) (*x509.Certificate, error) {
buf, err := ioutil.ReadFile(path)
if err != nil {
klog.Error(err)
return nil, err
}
p := &pem.Block{}
p, buf = pem.Decode(buf)
return x509.ParseCertificate(p.Bytes)
}
func parseKey(path string) (*rsa.PrivateKey, error) {
buf, err := ioutil.ReadFile(path)
if err != nil {
klog.Error(err)
return nil, err
}
p, buf := pem.Decode(buf)
return x509.ParsePKCS1PrivateKey(p.Bytes)
}
func newCertificate(info CertInformation) *x509.Certificate {
rd.Seed(time.Now().UnixNano())
return &x509.Certificate{
SerialNumber: big.NewInt(rd.Int63()),
Subject: pkix.Name{
Country: info.Country,
Organization: info.Organization,
OrganizationalUnit: info.OrganizationalUnit,
Province: info.Province,
CommonName: info.CommonName,
Locality: info.Locality,
ExtraNames: info.Names,
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(20, 0, 0),
BasicConstraintsValid: true,
IsCA: info.IsCA,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
EmailAddresses: info.EmailAddress,
}
}
func generateCaAndKey(user, caPath, keyPath string) (string, string, error) {
crtInfo := CertInformation{CommonName: user, IsCA: false}
crt, pri, err := Parse(caPath, keyPath)
if err != nil {
klog.Error(err)
return "", "", err
}
cert, key, err := createCRT(crt, pri, crtInfo)
if err != nil {
klog.Error(err)
return "", "", err
}
base64Cert := base64.StdEncoding.EncodeToString(cert)
base64Key := base64.StdEncoding.EncodeToString(key)
return base64Cert, base64Key, nil
}
func createKubeConfig(username string) (string, error) {
tmpKubeConfig := kubeConfig{ApiVersion: "v1", Kind: "Config"}
serverCa, err := ioutil.ReadFile(caPath)
if err != nil {
klog.Errorln(err)
return "", err
}
base64ServerCa := base64.StdEncoding.EncodeToString(serverCa)
tmpClusterInfo := clusterInfo{CertificateAuthorityData: base64ServerCa, Server: client.ClientSets().K8s().Master()}
tmpCluster := cluster{Cluster: tmpClusterInfo, Name: clusterName}
tmpKubeConfig.Clusters = append(tmpKubeConfig.Clusters, tmpCluster)
contextName := username + "@" + clusterName
tmpContext := contextObject{Context: contextInfo{User: username, Cluster: clusterName, NameSpace: defaultNamespace}, Name: contextName}
tmpKubeConfig.Contexts = append(tmpKubeConfig.Contexts, tmpContext)
cert, key, err := generateCaAndKey(username, caPath, keyPath)
if err != nil {
return "", err
}
tmpUser := user{User: userInfo{CaData: cert, KeyData: key}, Name: username}
tmpKubeConfig.Users = append(tmpKubeConfig.Users, tmpUser)
tmpKubeConfig.CurrentContext = contextName
config, err := yaml.Marshal(tmpKubeConfig)
if err != nil {
return "", err
}
return string(config), nil
}
func CreateKubeConfig(username string) error {
k8sClient := client.ClientSets().K8s().Kubernetes()
configName := fmt.Sprintf("kubeconfig-%s", username)
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
configName := fmt.Sprintf(kubeconfigNameFormat, username)
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metav1.GetOptions{})
if errors.IsNotFound(err) {
config, err := createKubeConfig(username)
kubeconfig, err := createKubeConfig(username)
if err != nil {
klog.Errorln(err)
return err
}
data := map[string]string{"config": config}
configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: configName}, Data: data}
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
data := map[string]string{fileName: string(kubeconfig)}
cm := &corev1.ConfigMap{TypeMeta: metav1.TypeMeta{Kind: configMapKind, APIVersion: configMapAPIVersion}, ObjectMeta: metav1.ObjectMeta{Name: configName}, Data: data}
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(cm)
if err != nil && !errors.IsAlreadyExists(err) {
klog.Errorf("create username %s's kubeConfig failed, reason: %v", username, err)
klog.Errorln(err)
return err
}
}
return nil
}
func createKubeConfig(username string) ([]byte, error) {
k8sClient := client.ClientSets().K8s().Kubernetes()
kubeconfig := client.ClientSets().K8s().Config()
var err error
var ca []byte
if len(kubeconfig.CAData) > 0 {
ca = kubeconfig.CAData
} else {
ca, err = ioutil.ReadFile(inClusterCAFilePath)
if err != nil {
klog.Errorln(err)
return nil, err
}
}
csrConfig := &certutil.Config{
CommonName: username,
Organization: nil,
AltNames: certutil.AltNames{},
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
}
x509csr, x509key, err := pkiutil.NewCSRAndKey(csrConfig)
if err != nil {
klog.Errorln(err)
return nil, err
}
var csrBuffer, keyBuffer bytes.Buffer
pem.Encode(&keyBuffer, &pem.Block{Type: "PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(x509key)})
csrBytes, _ := x509.CreateCertificateRequest(rand.Reader, x509csr, x509key)
pem.Encode(&csrBuffer, &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes})
csr := csrBuffer.Bytes()
key := keyBuffer.Bytes()
csrName := fmt.Sprintf("%s-csr-%d", username, time.Now().Unix())
k8sCSR := &certificatesv1beta1.CertificateSigningRequest{
TypeMeta: metav1.TypeMeta{
Kind: "CertificateSigningRequest",
APIVersion: "certificates.k8s.io/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: csrName,
},
Spec: certificatesv1beta1.CertificateSigningRequestSpec{
Request: csr,
Usages: []certificatesv1beta1.KeyUsage{certificatesv1beta1.UsageServerAuth, certificatesv1beta1.UsageKeyEncipherment, certificatesv1beta1.UsageClientAuth, certificatesv1beta1.UsageDigitalSignature},
Username: username,
Groups: []string{"system:authenticated"},
},
}
// create csr
k8sCSR, err = k8sClient.CertificatesV1beta1().CertificateSigningRequests().Create(k8sCSR)
if err != nil {
klog.Errorln(err)
return nil, err
}
// release csr, if it fails need to delete it manually
defer func() {
err := k8sClient.CertificatesV1beta1().CertificateSigningRequests().Delete(csrName, &metav1.DeleteOptions{})
if err != nil {
klog.Errorln(err)
}
}()
k8sCSR.Status = certificatesv1beta1.CertificateSigningRequestStatus{
Conditions: []certificatesv1beta1.CertificateSigningRequestCondition{{
Type: "Approved",
Reason: "KubeSphereApprove",
Message: "This CSR was approved by KubeSphere certificate approve.",
LastUpdateTime: metav1.Time{
Time: time.Now(),
},
}},
}
// approve csr
k8sCSR, err = k8sClient.CertificatesV1beta1().CertificateSigningRequests().UpdateApproval(k8sCSR)
if err != nil {
klog.Errorln(err)
return nil, err
}
// get client cert
var cert []byte
maxRetries := 3
for i := 0; i < maxRetries; i++ {
k8sCSR, err = k8sClient.CertificatesV1beta1().CertificateSigningRequests().Get(csrName, metav1.GetOptions{})
if k8sCSR != nil && k8sCSR.Status.Certificate != nil {
cert = k8sCSR.Status.Certificate
break
}
// sleep 0/200/400 millisecond
time.Sleep(200 * time.Millisecond * time.Duration(i))
}
if cert == nil {
return nil, fmt.Errorf("create client certificate failed: %v", err)
}
currentContext := fmt.Sprintf("%s@%s", username, defaultClusterName)
config := clientcmdapi.Config{
Kind: configMapKind,
APIVersion: configMapAPIVersion,
Preferences: clientcmdapi.Preferences{},
Clusters: map[string]*clientcmdapi.Cluster{defaultClusterName: {
Server: kubeconfig.Host,
InsecureSkipTLSVerify: false,
CertificateAuthorityData: ca,
}},
AuthInfos: map[string]*clientcmdapi.AuthInfo{username: {
ClientCertificateData: cert,
ClientKeyData: key,
}},
Contexts: map[string]*clientcmdapi.Context{currentContext: {
Cluster: defaultClusterName,
AuthInfo: username,
Namespace: defaultNamespace,
}},
CurrentContext: currentContext,
}
return clientcmd.Write(config)
}
func GetKubeConfig(username string) (string, error) {
k8sClient := client.ClientSets().K8s().Kubernetes()
configName := fmt.Sprintf("kubeconfig-%s", username)
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
configName := fmt.Sprintf(kubeconfigNameFormat, username)
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metav1.GetOptions{})
if err != nil {
klog.Errorf("cannot get username %s's kubeConfig, reason: %v", username, err)
klog.Errorln(err)
return "", err
}
str := configMap.Data[kubectlConfigKey]
var kubeConfig kubeConfig
err = yaml.Unmarshal([]byte(str), &kubeConfig)
data := []byte(configMap.Data[fileName])
kubeconfig, err := clientcmd.Load(data)
if err != nil {
klog.Error(err)
klog.Errorln(err)
return "", err
}
masterURL := client.ClientSets().K8s().Master()
for i, cluster := range kubeConfig.Clusters {
cluster.Cluster.Server = masterURL
kubeConfig.Clusters[i] = cluster
if cluster := kubeconfig.Clusters[defaultClusterName]; cluster != nil {
cluster.Server = masterURL
}
data, err := yaml.Marshal(kubeConfig)
data, err = clientcmd.Write(*kubeconfig)
if err != nil {
klog.Error(err)
klog.Errorln(err)
return "", err
}
return string(data), nil
}
func DelKubeConfig(username string) error {
k8sClient := client.ClientSets().K8s().Kubernetes()
configName := fmt.Sprintf("kubeconfig-%s", username)
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
if errors.IsNotFound(err) {
return nil
}
configName := fmt.Sprintf(kubeconfigNameFormat, username)
deletePolicy := metaV1.DeletePropagationBackground
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(configName, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
deletePolicy := metav1.DeletePropagationBackground
err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(configName, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
if err != nil {
klog.Errorf("delete username %s's kubeConfig failed, reason: %v", username, err)
klog.Errorln(err)
return err
}
return nil

View File

@@ -313,7 +313,7 @@ func GetPodMetrics(params RequestParams) *Response {
// add label resouce_name
for _, item := range response.Data.Result {
item.Metric["resource_name"] = item.Metric["pod_name"]
item.Metric["resource_name"] = item.Metric[labelNamePod]
}
ch <- APIResponse{
@@ -364,7 +364,7 @@ func GetContainerMetrics(params RequestParams) *Response {
// add label resouce_name
for _, item := range response.Data.Result {
item.Metric["resource_name"] = item.Metric["container_name"]
item.Metric["resource_name"] = item.Metric[labelNameContainer]
}
ch <- APIResponse{
@@ -616,9 +616,9 @@ func makePromqlForContainer(metricName string, params RequestParams) string {
var containerSelector string
if params.ContainerName != "" {
containerSelector = fmt.Sprintf(`pod_name="%s", namespace="%s", container_name="%s"`, params.PodName, params.NamespaceName, params.ContainerName)
containerSelector = fmt.Sprintf(`%s="%s", namespace="%s", %s="%s"`, labelNamePod, params.PodName, params.NamespaceName, labelNameContainer, params.ContainerName)
} else {
containerSelector = fmt.Sprintf(`pod_name="%s", namespace="%s", container_name=~"%s"`, params.PodName, params.NamespaceName, params.ResourcesFilter)
containerSelector = fmt.Sprintf(`%s="%s", namespace="%s", %s=~"%s"`, labelNamePod, params.PodName, params.NamespaceName, labelNameContainer, params.ResourcesFilter)
}
return strings.Replace(exp, "$1", containerSelector, -1)

View File

@@ -13,6 +13,16 @@ limitations under the License.
package metrics
import (
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/simple/client"
)
var (
labelNamePod = "pod_name"
labelNameContainer = "container_name"
)
const (
// TODO: expose the following metrics in prometheus format
MetricClusterWorkspaceCount = "cluster_workspace_count"
@@ -293,7 +303,7 @@ var metricsPromqlMap = map[string]string{
"cluster_disk_inode_total": `sum(node:node_inodes_total:)`,
"cluster_disk_inode_usage": `sum(node:node_inodes_total:) - sum(node:node_inodes_free:)`,
"cluster_disk_inode_utilisation": `cluster:disk_inode_utilization:ratio`,
"cluster_namespace_count": `count(kube_namespace_annotations)`,
"cluster_namespace_count": `count(kube_namespace_labels)`,
"cluster_pod_count": `cluster:pod:sum`,
"cluster_pod_quota": `sum(max(kube_node_status_capacity_pods) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_utilisation": `cluster:pod_utilization:ratio`,
@@ -311,7 +321,7 @@ var metricsPromqlMap = map[string]string{
"cluster_hpa_count": `sum(kube_hpa_labels)`,
"cluster_job_count": `sum(kube_job_labels)`,
"cluster_statefulset_count": `sum(kube_statefulset_labels)`,
"cluster_replicaset_count": `count(kube_replicaset_created)`,
"cluster_replicaset_count": `count(kube_replicaset_labels)`,
"cluster_service_count": `sum(kube_service_info)`,
"cluster_secret_count": `sum(kube_secret_info)`,
"cluster_pv_count": `sum(kube_persistentvolume_labels)`,
@@ -374,7 +384,7 @@ var metricsPromqlMap = map[string]string{
"workspace_hpa_count": `sum by (label_kubesphere_io_workspace) (kube_hpa_labels{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels{$1}))`,
"workspace_job_count": `sum by (label_kubesphere_io_workspace) (kube_job_labels{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels{$1}))`,
"workspace_statefulset_count": `sum by (label_kubesphere_io_workspace) (kube_statefulset_labels{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels{$1}))`,
"workspace_replicaset_count": `count by (label_kubesphere_io_workspace) (kube_replicaset_created{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels{$1}))`,
"workspace_replicaset_count": `count by (label_kubesphere_io_workspace) (kube_replicaset_labels{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels{$1}))`,
"workspace_service_count": `sum by (label_kubesphere_io_workspace) (kube_service_info{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels{$1}))`,
"workspace_secret_count": `sum by (label_kubesphere_io_workspace) (kube_secret_info{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels{$1}))`,
"workspace_pod_abnormal_ratio": `count by (label_kubesphere_io_workspace) ((kube_pod_info{node!=""} unless on (pod, namespace) (kube_pod_status_phase{job="kube-state-metrics", phase="Succeeded"}>0) unless on (pod, namespace) ((kube_pod_status_ready{job="kube-state-metrics", condition="true"}>0) and on (pod, namespace) (kube_pod_status_phase{job="kube-state-metrics", phase="Running"}>0)) unless on (pod, namespace) (kube_pod_container_status_waiting_reason{job="kube-state-metrics", reason="ContainerCreating"}>0)) * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1}) / sum by (label_kubesphere_io_workspace) (kube_pod_status_phase{phase!="Succeeded", namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels{$1}))`,
@@ -401,7 +411,7 @@ var metricsPromqlMap = map[string]string{
"namespace_hpa_count": `sum by (namespace) (kube_hpa_labels{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`,
"namespace_job_count": `sum by (namespace) (kube_job_labels{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`,
"namespace_statefulset_count": `sum by (namespace) (kube_statefulset_labels{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`,
"namespace_replicaset_count": `count by (namespace) (kube_replicaset_created{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`,
"namespace_replicaset_count": `count by (namespace) (kube_replicaset_labels{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`,
"namespace_service_count": `sum by (namespace) (kube_service_info{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`,
"namespace_secret_count": `sum by (namespace) (kube_secret_info{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`,
"namespace_configmap_count": `sum by (namespace) (kube_configmap_info{namespace!=""} * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`,
@@ -435,14 +445,14 @@ var metricsPromqlMap = map[string]string{
// pod
"pod_cpu_usage": `round(label_join(sum by (namespace, pod_name) (irate(container_cpu_usage_seconds_total{job="kubelet", pod_name!="", image!=""}[5m])), "pod", "", "pod_name") * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}, 0.001)`,
"pod_memory_usage": `label_join(sum by (namespace, pod_name) (container_memory_usage_bytes{job="kubelet", pod_name!="", image!=""}), "pod", "", "pod_name") * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`,
"pod_memory_usage_wo_cache": `label_join(sum by (namespace, pod_name) (container_memory_usage_bytes{job="kubelet", pod_name!="", image!=""} - container_memory_cache{job="kubelet", pod_name!="", image!=""}), "pod", "", "pod_name") * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`,
"pod_memory_usage_wo_cache": `label_join(sum by (namespace, pod_name) (container_memory_working_set_bytes{job="kubelet", pod_name!="", image!=""}), "pod", "", "pod_name") * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`,
"pod_net_bytes_transmitted": `label_join(sum by (namespace, pod_name) (irate(container_network_transmit_bytes_total{pod_name!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m])), "pod", "", "pod_name") * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`,
"pod_net_bytes_received": `label_join(sum by (namespace, pod_name) (irate(container_network_receive_bytes_total{pod_name!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m])), "pod", "", "pod_name") * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`,
// container
"container_cpu_usage": `round(sum by (namespace, pod_name, container_name) (irate(container_cpu_usage_seconds_total{job="kubelet", container_name!="POD", container_name!="", image!="", $1}[5m])), 0.001)`,
"container_memory_usage": `sum by (namespace, pod_name, container_name) (container_memory_usage_bytes{job="kubelet", container_name!="POD", container_name!="", image!="", $1})`,
"container_memory_usage_wo_cache": `sum by (namespace, pod_name, container_name) (container_memory_usage_bytes{job="kubelet", container_name!="POD", container_name!="", image!="", $1} - container_memory_cache{job="kubelet", container_name!="POD", container_name!="", image!="", $1})`,
"container_memory_usage_wo_cache": `sum by (namespace, pod_name, container_name) (container_memory_working_set_bytes{job="kubelet", container_name!="POD", container_name!="", image!="", $1})`,
// pvc
"pvc_inodes_available": `max by (namespace, persistentvolumeclaim) (kubelet_volume_stats_inodes_free) * on (namespace, persistentvolumeclaim) group_left (storageclass) kube_persistentvolumeclaim_info{$1}`,
@@ -506,3 +516,36 @@ var metricsPromqlMap = map[string]string{
"prometheus_up_sum": `prometheus:up:sum`,
"prometheus_tsdb_head_samples_appended_rate": `prometheus:prometheus_tsdb_head_samples_appended:sum_rate`,
}
// As of Kubernetes v1.16, any Prometheus queries that match `pod_name` and
// `container_name` labels must be updated to use `pod` and `container` instead.
func CompatibleMetrics() {
if client.ClientSets() == nil {
return
}
version, err := client.ClientSets().K8s().Discovery().ServerVersion()
if err != nil {
klog.Errorf("fail to fetch k8s version: %v.", err)
return
}
if version.Minor >= "16" {
labelNamePod = "pod"
labelNameContainer = "container"
m := metricsPromqlMap
m["workspace_net_bytes_transmitted"] = `sum by (label_kubesphere_io_workspace) (sum by (namespace) (irate(container_network_transmit_bytes_total{namespace!="", pod!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m])) * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`
m["workspace_net_bytes_received"] = `sum by (label_kubesphere_io_workspace) (sum by (namespace) (irate(container_network_receive_bytes_total{namespace!="", pod!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m])) * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`
m["namespace_net_bytes_transmitted"] = `sum by (namespace) (irate(container_network_transmit_bytes_total{namespace!="", pod!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m]) * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`
m["namespace_net_bytes_received"] = `sum by (namespace) (irate(container_network_receive_bytes_total{namespace!="", pod!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m]) * on (namespace) group_left(label_kubesphere_io_workspace) kube_namespace_labels{$1})`
m["pod_cpu_usage"] = `round(sum by (namespace, pod) (irate(container_cpu_usage_seconds_total{job="kubelet", pod!="", image!=""}[5m])) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}, 0.001)`
m["pod_memory_usage"] = `sum by (namespace, pod) (container_memory_usage_bytes{job="kubelet", pod!="", image!=""}) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`
m["pod_memory_usage_wo_cache"] = `sum by (namespace, pod) (container_memory_working_set_bytes{job="kubelet", pod!="", image!=""}) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`
m["pod_net_bytes_transmitted"] = `sum by (namespace, pod) (irate(container_network_transmit_bytes_total{pod!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m])) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`
m["pod_net_bytes_received"] = `sum by (namespace, pod) (irate(container_network_receive_bytes_total{pod!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m])) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`
m["container_cpu_usage"] = `round(sum by (namespace, pod, container) (irate(container_cpu_usage_seconds_total{job="kubelet", container!="POD", container!="", image!="", $1}[5m])), 0.001)`
m["container_memory_usage"] = `sum by (namespace, pod, container) (container_memory_usage_bytes{job="kubelet", container!="POD", container!="", image!="", $1})`
m["container_memory_usage_wo_cache"] = `sum by (namespace, pod, container) (container_memory_working_set_bytes{job="kubelet", container!="POD", container!="", image!="", $1})`
}
}

View File

@@ -126,7 +126,7 @@ func (rawMetrics *Response) SortBy(sortMetricName string, sortType string) (*Res
// record the ordering of resource_name to indexMap
// example: {"metric":{ResultItemMetricResourceName: "Deployment:xxx"},"value":[1541142931.731,"3"]}
resourceName, exist := r.Metric[ResultItemMetricResourceName]
if exist {
if exist && resourceName != "" {
if _, exist := indexMap[resourceName]; !exist {
indexMap[resourceName] = i
i = i + 1
@@ -138,7 +138,7 @@ func (rawMetrics *Response) SortBy(sortMetricName string, sortType string) (*Res
// iterator all metric to find max metricItems length
for _, r := range metricItem.Data.Result {
k, ok := r.Metric[ResultItemMetricResourceName]
if ok {
if ok && k != "" {
currentResourceMap[k] = 1
}
}
@@ -167,7 +167,7 @@ func (rawMetrics *Response) SortBy(sortMetricName string, sortType string) (*Res
for j := 0; j < len(re.Data.Result); j++ {
r := re.Data.Result[j]
k, exist := r.Metric[ResultItemMetricResourceName]
if exist {
if exist && k != "" {
index, exist := indexMap[k]
if exist {
sortedMetric[index] = r

View File

@@ -0,0 +1,315 @@
package metrics
import (
"kubesphere.io/kubesphere/pkg/api/monitoring/v1alpha2"
"reflect"
"testing"
)
func TestSortBy(t *testing.T) {
tests := []struct {
description string
rawMetrics *Response
sortMetrics string
sortType string
expected *Response
}{
{
description: "sort a set of node metrics for node1, node2 and a node with blank name (this should be considered as abnormal).",
rawMetrics: &Response{
Results: []APIResponse{
{
MetricName: "node_cpu_usage",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "0.221"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "0.177"},
},
{
Metric: map[string]string{"resource_name": ""},
Value: []interface{}{1578987135.334, ""},
},
},
},
},
},
{
MetricName: "node_memory_total",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "8201043968"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "8201039872"},
},
{
Metric: map[string]string{"resource_name": ""},
Value: []interface{}{1578987135.334, ""},
},
},
},
},
},
{
MetricName: "node_pod_running_count",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "19"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "6"},
},
{
Metric: map[string]string{"resource_name": ""},
Value: []interface{}{1578987135.334, ""},
},
},
},
},
},
},
},
sortMetrics: "node_cpu_usage",
sortType: "desc",
expected: &Response{
Results: []APIResponse{
{
MetricName: "node_cpu_usage",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "0.221"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "0.177"},
},
},
},
},
},
{
MetricName: "node_memory_total",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "8201043968"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "8201039872"},
},
},
},
},
},
{
MetricName: "node_pod_running_count",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "19"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "6"},
},
},
},
},
},
},
},
},
{
description: "sort a set of node metrics for node1, node2 and node3.",
rawMetrics: &Response{
Results: []APIResponse{
{
MetricName: "node_cpu_usage",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "0.221"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "0.177"},
},
{
Metric: map[string]string{"resource_name": "node3"},
Value: []interface{}{1578987135.334, "0.194"},
},
},
},
},
},
{
MetricName: "node_memory_total",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "8201043968"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "8201039872"},
},
{
Metric: map[string]string{"resource_name": "node3"},
Value: []interface{}{1578987135.334, "8201056256"},
},
},
},
},
},
{
MetricName: "node_pod_running_count",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "19"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "6"},
},
{
Metric: map[string]string{"resource_name": "node3"},
Value: []interface{}{1578987135.334, "14"},
},
},
},
},
},
},
},
sortMetrics: "node_cpu_usage",
sortType: "desc",
expected: &Response{
Results: []APIResponse{
{
MetricName: "node_cpu_usage",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "0.221"},
},
{
Metric: map[string]string{"resource_name": "node3"},
Value: []interface{}{1578987135.334, "0.194"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "0.177"},
},
},
},
},
},
{
MetricName: "node_memory_total",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "8201043968"},
},
{
Metric: map[string]string{"resource_name": "node3"},
Value: []interface{}{1578987135.334, "8201056256"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "8201039872"},
},
},
},
},
},
{
MetricName: "node_pod_running_count",
APIResponse: v1alpha2.APIResponse{
Status: "success",
Data: v1alpha2.QueryResult{
ResultType: "vector",
Result: []v1alpha2.QueryValue{
{
Metric: map[string]string{"resource_name": "node1"},
Value: []interface{}{1578987135.334, "19"},
},
{
Metric: map[string]string{"resource_name": "node3"},
Value: []interface{}{1578987135.334, "14"},
},
{
Metric: map[string]string{"resource_name": "node2"},
Value: []interface{}{1578987135.334, "6"},
},
},
},
},
},
},
},
},
}
for _, test := range tests {
res, _ := test.rawMetrics.SortBy(test.sortMetrics, test.sortType)
if !reflect.DeepEqual(res, test.expected) {
t.Errorf("got unexpected results: %v", res)
}
}
}

View File

@@ -65,25 +65,25 @@ func ListApplications(conditions *params.Conditions, limit, offset int, orderBy
describeClustersRequest := &pb.DescribeClustersRequest{
Limit: uint32(limit),
Offset: uint32(offset)}
if keyword := conditions.Match["keyword"]; keyword != "" {
if keyword := conditions.Match[Keyword]; keyword != "" {
describeClustersRequest.SearchWord = &wrappers.StringValue{Value: keyword}
}
if runtimeId := conditions.Match["runtime_id"]; runtimeId != "" {
if runtimeId := conditions.Match[RuntimeId]; runtimeId != "" {
describeClustersRequest.RuntimeId = []string{runtimeId}
}
if appId := conditions.Match["app_id"]; appId != "" {
if appId := conditions.Match[AppId]; appId != "" {
describeClustersRequest.AppId = []string{appId}
}
if versionId := conditions.Match["version_id"]; versionId != "" {
if versionId := conditions.Match[VersionId]; versionId != "" {
describeClustersRequest.VersionId = []string{versionId}
}
if status := conditions.Match["status"]; status != "" {
if status := conditions.Match[Status]; status != "" {
describeClustersRequest.Status = strings.Split(status, "|")
}
if orderBy != "" {
describeClustersRequest.SortKey = &wrappers.StringValue{Value: orderBy}
}
describeClustersRequest.Reverse = &wrappers.BoolValue{Value: !reverse}
describeClustersRequest.Reverse = &wrappers.BoolValue{Value: reverse}
resp, err := client.Cluster().DescribeClusters(openpitrix.SystemContext(), describeClustersRequest)
if err != nil {
klog.Errorln(err)
@@ -405,7 +405,8 @@ func DeleteApplication(clusterId string) error {
return err
}
_, err = client.Cluster().DeleteClusters(openpitrix.SystemContext(), &pb.DeleteClustersRequest{ClusterId: []string{clusterId}, Force: &wrappers.BoolValue{Value: true}})
_, err = client.Cluster().CeaseClusters(openpitrix.SystemContext(),
&pb.CeaseClustersRequest{ClusterId: []string{clusterId}, Force: &wrappers.BoolValue{Value: true}})
if err != nil {
klog.Errorln(err)

View File

@@ -45,19 +45,19 @@ func ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit
}
describeAppsRequest := &pb.DescribeAppsRequest{}
if keyword := conditions.Match["keyword"]; keyword != "" {
if keyword := conditions.Match[Keyword]; keyword != "" {
describeAppsRequest.SearchWord = &wrappers.StringValue{Value: keyword}
}
if appId := conditions.Match["app_id"]; appId != "" {
if appId := conditions.Match[AppId]; appId != "" {
describeAppsRequest.AppId = strings.Split(appId, "|")
}
if isv := conditions.Match["isv"]; isv != "" {
if isv := conditions.Match[ISV]; isv != "" {
describeAppsRequest.Isv = strings.Split(isv, "|")
}
if categoryId := conditions.Match["category_id"]; categoryId != "" {
if categoryId := conditions.Match[CategoryId]; categoryId != "" {
describeAppsRequest.CategoryId = strings.Split(categoryId, "|")
}
if repoId := conditions.Match["repo"]; repoId != "" {
if repoId := conditions.Match[RepoId]; repoId != "" {
// hard code, app template in built-in repo has no repo_id attribute
if repoId == BuiltinRepoId {
describeAppsRequest.RepoId = []string{"\u0000"}
@@ -65,7 +65,7 @@ func ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit
describeAppsRequest.RepoId = strings.Split(repoId, "|")
}
}
if status := conditions.Match["status"]; status != "" {
if status := conditions.Match[Status]; status != "" {
describeAppsRequest.Status = strings.Split(status, "|")
}
if orderBy != "" {
@@ -451,7 +451,7 @@ func DoAppAction(appId string, request *ActionRequest) error {
// TODO openpitrix need to implement app suspend interface
resp, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
AppId: []string{appId},
Status: []string{"active"},
Status: []string{StatusActive},
Limit: 200,
Offset: 0,
})
@@ -572,22 +572,22 @@ func ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse
describeAppVersionAudits := &pb.DescribeAppVersionAuditsRequest{}
if keyword := conditions.Match["keyword"]; keyword != "" {
if keyword := conditions.Match[Keyword]; keyword != "" {
describeAppVersionAudits.SearchWord = &wrappers.StringValue{Value: keyword}
}
if appId := conditions.Match["app"]; appId != "" {
if appId := conditions.Match[AppId]; appId != "" {
describeAppVersionAudits.AppId = []string{appId}
}
if versionId := conditions.Match["version"]; versionId != "" {
if versionId := conditions.Match[VersionId]; versionId != "" {
describeAppVersionAudits.VersionId = []string{versionId}
}
if status := conditions.Match["status"]; status != "" {
if status := conditions.Match[Status]; status != "" {
describeAppVersionAudits.Status = strings.Split(status, "|")
}
if orderBy != "" {
describeAppVersionAudits.SortKey = &wrappers.StringValue{Value: orderBy}
}
describeAppVersionAudits.Reverse = &wrappers.BoolValue{Value: !reverse}
describeAppVersionAudits.Reverse = &wrappers.BoolValue{Value: reverse}
describeAppVersionAudits.Limit = uint32(limit)
describeAppVersionAudits.Offset = uint32(offset)
resp, err := client.App().DescribeAppVersionAudits(openpitrix.SystemContext(), describeAppVersionAudits)
@@ -617,16 +617,16 @@ func ListAppVersionReviews(conditions *params.Conditions, orderBy string, revers
describeAppVersionReviews := &pb.DescribeAppVersionReviewsRequest{}
if keyword := conditions.Match["keyword"]; keyword != "" {
if keyword := conditions.Match[Keyword]; keyword != "" {
describeAppVersionReviews.SearchWord = &wrappers.StringValue{Value: keyword}
}
if status := conditions.Match["status"]; status != "" {
if status := conditions.Match[Status]; status != "" {
describeAppVersionReviews.Status = strings.Split(status, "|")
}
if orderBy != "" {
describeAppVersionReviews.SortKey = &wrappers.StringValue{Value: orderBy}
}
describeAppVersionReviews.Reverse = &wrappers.BoolValue{Value: !reverse}
describeAppVersionReviews.Reverse = &wrappers.BoolValue{Value: reverse}
describeAppVersionReviews.Limit = uint32(limit)
describeAppVersionReviews.Offset = uint32(offset)
// TODO icon is needed
@@ -657,19 +657,19 @@ func ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool
describeAppVersionsRequest := &pb.DescribeAppVersionsRequest{}
if keyword := conditions.Match["keyword"]; keyword != "" {
if keyword := conditions.Match[Keyword]; keyword != "" {
describeAppVersionsRequest.SearchWord = &wrappers.StringValue{Value: keyword}
}
if appId := conditions.Match["app"]; appId != "" {
if appId := conditions.Match[AppId]; appId != "" {
describeAppVersionsRequest.AppId = []string{appId}
}
if status := conditions.Match["status"]; status != "" {
if status := conditions.Match[Status]; status != "" {
describeAppVersionsRequest.Status = strings.Split(status, "|")
}
if orderBy != "" {
describeAppVersionsRequest.SortKey = &wrappers.StringValue{Value: orderBy}
}
describeAppVersionsRequest.Reverse = &wrappers.BoolValue{Value: !reverse}
describeAppVersionsRequest.Reverse = &wrappers.BoolValue{Value: reverse}
describeAppVersionsRequest.Limit = uint32(limit)
describeAppVersionsRequest.Offset = uint32(offset)
resp, err := client.App().DescribeAppVersions(openpitrix.SystemContext(), describeAppVersionsRequest)

View File

@@ -138,13 +138,13 @@ func ListCategories(conditions *params.Conditions, orderBy string, reverse bool,
req := &pb.DescribeCategoriesRequest{}
if keyword := conditions.Match["keyword"]; keyword != "" {
if keyword := conditions.Match[Keyword]; keyword != "" {
req.SearchWord = &wrappers.StringValue{Value: keyword}
}
if orderBy != "" {
req.SortKey = &wrappers.StringValue{Value: orderBy}
}
req.Reverse = &wrappers.BoolValue{Value: !reverse}
req.Reverse = &wrappers.BoolValue{Value: reverse}
req.Limit = uint32(limit)
req.Offset = uint32(offset)
resp, err := client.Category().DescribeCategories(openpitrix.SystemContext(), req)

View File

@@ -169,28 +169,28 @@ func ListRepos(conditions *params.Conditions, orderBy string, reverse bool, limi
req := &pb.DescribeReposRequest{}
if keyword := conditions.Match["keyword"]; keyword != "" {
if keyword := conditions.Match[Keyword]; keyword != "" {
req.SearchWord = &wrappers.StringValue{Value: keyword}
}
if status := conditions.Match["status"]; status != "" {
if status := conditions.Match[Status]; status != "" {
req.Status = strings.Split(status, "|")
}
if typeStr := conditions.Match["type"]; typeStr != "" {
if typeStr := conditions.Match[Type]; typeStr != "" {
req.Type = strings.Split(typeStr, "|")
}
if visibility := conditions.Match["visibility"]; visibility != "" {
if visibility := conditions.Match[Visibility]; visibility != "" {
req.Visibility = strings.Split(visibility, "|")
}
if status := conditions.Match["status"]; status != "" {
if status := conditions.Match[Status]; status != "" {
req.Status = strings.Split(status, "|")
}
if workspace := conditions.Match["workspace"]; workspace != "" {
if workspace := conditions.Match[WorkspaceLabel]; workspace != "" {
req.Label = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", workspace)}
}
if orderBy != "" {
req.SortKey = &wrappers.StringValue{Value: orderBy}
}
req.Reverse = &wrappers.BoolValue{Value: !reverse}
req.Reverse = &wrappers.BoolValue{Value: reverse}
req.Limit = uint32(limit)
req.Offset = uint32(offset)
resp, err := client.Repo().DescribeRepos(openpitrix.SystemContext(), req)
@@ -270,10 +270,10 @@ func ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset
describeRepoEventsRequest := &pb.DescribeRepoEventsRequest{
RepoId: []string{repoId},
}
if eventId := conditions.Match["repo_event_id"]; eventId != "" {
if eventId := conditions.Match[RepoEventId]; eventId != "" {
describeRepoEventsRequest.RepoEventId = strings.Split(eventId, "|")
}
if status := conditions.Match["status"]; status != "" {
if status := conditions.Match[Status]; status != "" {
describeRepoEventsRequest.Status = strings.Split(status, "|")
}
describeRepoEventsRequest.Limit = uint32(limit)

View File

@@ -835,3 +835,20 @@ type ModifyClusterAttributesRequest struct {
// cluster name
Name *string `json:"name,omitempty"`
}
const (
CreateTime = "create_time"
StatusTime = "status_time"
RuntimeId = "runtime_id"
VersionId = "version_id"
RepoId = "repo_id"
CategoryId = "category_id"
RepoEventId = "repo_event_id"
Status = "status"
Type = "type"
Visibility = "visibility"
AppId = "app_id"
Keyword = "keyword"
ISV = "isv"
WorkspaceLabel = "workspace"
)

View File

@@ -2,9 +2,11 @@ package registries
import (
"fmt"
"github.com/docker/distribution/reference"
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest"
log "k8s.io/klog"
"net/url"
"strings"
)
// Image holds information about an image.
@@ -30,9 +32,28 @@ func (i *Image) Reference() string {
return i.Tag
}
type DockerURL struct {
*url.URL
}
func (u *DockerURL) StringWithoutScheme() string {
u.Scheme = ""
s := u.String()
return strings.Trim(s, "//")
}
func ParseDockerURL(rawurl string) (*DockerURL, error) {
url, err := url.Parse(rawurl)
if err != nil {
log.Errorf("%+v", err)
return nil, err
}
return &DockerURL{URL: url}, nil
}
// ParseImage returns an Image struct with all the values filled in for a given image.
// example : localhost:5000/nginx:latest, nginx:perl etc.
func ParseImage(image string) (Image, error) {
func ParseImage(image string) (i Image, err error) {
// Parse the image name and tag.
named, err := reference.ParseNormalizedNamed(image)
if err != nil {
@@ -41,7 +62,7 @@ func ParseImage(image string) (Image, error) {
// Add the latest lag if they did not provide one.
named = reference.TagNameOnly(named)
i := Image{
i = Image{
named: named,
Domain: reference.Domain(named),
Path: reference.Path(named),

View File

@@ -0,0 +1,73 @@
package registries
import (
"testing"
)
func TestParseImage(t *testing.T) {
type testImage struct {
inputImageName string
ExImage Image
}
testImages := []testImage{
{inputImageName: "dockerhub.qingcloud.com/kubesphere/test:v1", ExImage: Image{Domain: "dockerhub.qingcloud.com", Tag: "v1", Path: "kubesphere/test"}},
{inputImageName: "harbor.devops.kubesphere.local:30280/library/tomcat:latest", ExImage: Image{Domain: "harbor.devops.kubesphere.local:30280", Tag: "latest", Path: "library/tomcat"}},
{inputImageName: "zhuxiaoyang/nginx:v1", ExImage: Image{Domain: "docker.io", Tag: "v1", Path: "zhuxiaoyang/nginx"}},
{inputImageName: "nginx", ExImage: Image{Domain: "docker.io", Tag: "latest", Path: "library/nginx"}},
{inputImageName: "nginx:latest", ExImage: Image{Domain: "docker.io", Tag: "latest", Path: "library/nginx"}},
{inputImageName: "kubesphere/ks-account:v2.1.0", ExImage: Image{Domain: "docker.io", Tag: "v2.1.0", Path: "kubesphere/ks-account"}},
{inputImageName: "http://docker.io/nginx:latest", ExImage: Image{}},
{inputImageName: "https://harbor.devops.kubesphere.local:30280/library/tomcat:latest", ExImage: Image{}},
{inputImageName: "docker.io/nginx:latest:latest", ExImage: Image{}},
{inputImageName: "nginx:8000:latest", ExImage: Image{}},
}
for _, image := range testImages {
res, err := ParseImage(image.inputImageName)
if err != nil {
if res != image.ExImage {
t.Fatalf("Get err %s", err)
}
}
if res.Domain != image.ExImage.Domain {
t.Fatalf("Doamin got %v, expected %v", res.Domain, image.ExImage.Domain)
}
if res.Tag != image.ExImage.Tag {
t.Fatalf("Tag got %v, expected %v", res.Tag, image.ExImage.Tag)
}
if res.Path != image.ExImage.Path {
t.Fatalf("Path got %v, expected %v", res.Path, image.ExImage.Path)
}
}
}
func TestStringWithoutScheme(t *testing.T) {
type testRawUrl struct {
Rawurl string
ExUrl string
}
testRawurls := []testRawUrl{
{"http://dockerhub.qingcloud.com/kubesphere/nginx:v1", "dockerhub.qingcloud.com/kubesphere/nginx:v1"},
{"https://dockerhub.qingcloud.com/kubesphere/nginx:v1", "dockerhub.qingcloud.com/kubesphere/nginx:v1"},
{"http://harbor.devops.kubesphere.local:30280/library/tomcat:latest", "harbor.devops.kubesphere.local:30280/library/tomcat:latest"},
{"https://harbor.devops.kubesphere.local:30280/library/tomcat:latest", "harbor.devops.kubesphere.local:30280/library/tomcat:latest"},
}
for _, rawurl := range testRawurls {
dockerurl, err := ParseDockerURL(rawurl.Rawurl)
if err != nil {
t.Fatalf("Get err %s", err)
}
imageName := dockerurl.StringWithoutScheme()
if imageName != rawurl.ExUrl {
t.Fatalf("imagename got %v, expected %v", imageName, rawurl.ExUrl)
}
}
}

View File

@@ -5,6 +5,7 @@ import (
"time"
)
// TODO: deprecated, use github.com/docker/docker/api/types.AuthConfig instead
type AuthInfo struct {
Username string `json:"username" description:"username"`
Password string `json:"password" description:"password"`

View File

@@ -7,7 +7,7 @@ import (
func TestDigestFromDockerHub(t *testing.T) {
testImage := Image{Domain: "docker.io", Path: "library/alpine", Tag: "latest"}
r, err := CreateRegistryClient("", "", "docker.io")
r, err := CreateRegistryClient("", "", "docker.io", true)
if err != nil {
t.Fatalf("Could not get client: %s", err)
}

View File

@@ -25,9 +25,11 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
corev1 "k8s.io/api/core/v1"
"k8s.io/klog"
log "k8s.io/klog"
"kubesphere.io/kubesphere/pkg/informers"
"net/http"
"net/url"
"strings"
)
const (
@@ -58,7 +60,7 @@ func RegistryVerify(authInfo AuthInfo) error {
cli, err := client.NewClientWithOpts(client.WithAPIVersionNegotiation())
if err != nil {
klog.Error(err)
log.Error(err)
}
config := types.AuthConfig{
@@ -68,6 +70,22 @@ func RegistryVerify(authInfo AuthInfo) error {
ServerAddress: authInfo.ServerHost,
}
if !strings.HasPrefix(authInfo.ServerHost, "https://") && !strings.HasPrefix(authInfo.ServerHost, "http://") {
authInfo.ServerHost = "https://" + authInfo.ServerHost
}
u, err := url.Parse(authInfo.ServerHost)
if err != nil {
return err
}
if u.Host != DefaultDockerHub {
_, err := http.Get(authInfo.ServerHost + "/v2/")
if err != nil {
return err
}
}
// TODO: deprecated, use native Docker Registry v2 authentication.
resp, err := cli.RegistryLogin(ctx, config)
cli.Close()

View File

@@ -0,0 +1,33 @@
package registries
import (
"testing"
)
func TestRegistryVerify(t *testing.T) {
type testRegistry struct {
Auth AuthInfo
Result bool
}
// some registry can not login with guest.
registries := []testRegistry{
{Auth: AuthInfo{Username: "guest", Password: "guest", ServerHost: "docker.io"}, Result: true},
{Auth: AuthInfo{Username: "guest", Password: "guest", ServerHost: "https://docker.io"}, Result: true},
{Auth: AuthInfo{Username: "guest", Password: "guest", ServerHost: "dockerhub.qingcloud.com"}, Result: true},
{Auth: AuthInfo{Username: "guest", Password: "guest", ServerHost: "https://dockerhub.qingcloud.com"}, Result: true},
{Auth: AuthInfo{Username: "guest", Password: "guest", ServerHost: "http://dockerhub.qingcloud.com"}, Result: false},
{Auth: AuthInfo{Username: "guest", Password: "guest", ServerHost: "registry.cn-hangzhou.aliyuncs.com"}, Result: false},
}
for _, registry := range registries {
err := RegistryVerify(registry.Auth)
if registry.Result == true && err != nil {
t.Fatalf("Get err %s", err)
}
if registry.Result == false && err == nil {
t.Fatalf("Input Wrong data but without any error.")
}
}
}

View File

@@ -64,7 +64,7 @@ type authService struct {
Scope []string
}
func CreateRegistryClient(username, password, domain string) (*Registry, error) {
func CreateRegistryClient(username, password, domain string, useSSL bool) (*Registry, error) {
authDomain := domain
auth, err := GetAuthConfig(username, password, authDomain)
if err != nil {
@@ -75,6 +75,7 @@ func CreateRegistryClient(username, password, domain string) (*Registry, error)
// Create the registry client.
return New(auth, RegistryOpt{
Domain: domain,
UseSSL: useSSL,
})
}

View File

@@ -4,6 +4,8 @@ import (
"testing"
)
const DockerHub = "docker.io"
func TestCreateRegistryClient(t *testing.T) {
type imageInfo struct {
Username string
@@ -11,17 +13,19 @@ func TestCreateRegistryClient(t *testing.T) {
Domain string
ExDomain string
ExUrl string
UseSSL bool
}
testImages := []imageInfo{
{Domain: "kubesphere.io", ExDomain: "kubesphere.io", ExUrl: "http://kubesphere.io"},
{Domain: "127.0.0.1:5000", ExDomain: "127.0.0.1:5000", ExUrl: "http://127.0.0.1:5000"},
{Username: "Username", Password: "Password", Domain: "docker.io", ExDomain: "registry-1.docker.io", ExUrl: "https://registry-1.docker.io"},
{Domain: "harbor.devops.kubesphere.local:30280", ExDomain: "harbor.devops.kubesphere.local:30280", ExUrl: "http://harbor.devops.kubesphere.local:30280"},
{Domain: "kubesphere.io", ExDomain: "kubesphere.io", ExUrl: "https://kubesphere.io", UseSSL: true},
{Domain: "127.0.0.1:5000", ExDomain: "127.0.0.1:5000", ExUrl: "http://127.0.0.1:5000", UseSSL: false},
{Username: "Username", Password: "Password", Domain: DockerHub, ExDomain: "registry-1.docker.io", ExUrl: "https://registry-1.docker.io", UseSSL: true},
{Domain: "harbor.devops.kubesphere.local:30280", ExDomain: "harbor.devops.kubesphere.local:30280", ExUrl: "http://harbor.devops.kubesphere.local:30280", UseSSL: false},
{Domain: "dockerhub.qingcloud.com/zxytest/s2i-jj:jj", ExDomain: "dockerhub.qingcloud.com", ExUrl: "https://dockerhub.qingcloud.com/zxytest/s2i-jj:jj", UseSSL: true},
}
for _, testImage := range testImages {
reg, err := CreateRegistryClient(testImage.Username, testImage.Password, testImage.Domain)
reg, err := CreateRegistryClient(testImage.Username, testImage.Password, testImage.Domain, testImage.UseSSL)
if err != nil {
t.Fatalf("Get err %s", err)
}
@@ -36,8 +40,8 @@ func TestCreateRegistryClient(t *testing.T) {
}
testImage := Image{Domain: "docker.io", Path: "library/alpine", Tag: "latest"}
r, err := CreateRegistryClient("", "", "docker.io")
testImage := Image{Domain: DockerHub, Path: "library/alpine", Tag: "latest"}
r, err := CreateRegistryClient("", "", DockerHub, true)
if err != nil {
t.Fatalf("Could not get client: %s", err)
}

View File

@@ -32,7 +32,7 @@ func (asm authServiceMock) equalTo(v *authService) bool {
func TestToken(t *testing.T) {
testImage := Image{Domain: "docker.io", Path: "library/alpine", Tag: "latest"}
r, err := CreateRegistryClient("", "", "docker.io")
r, err := CreateRegistryClient("", "", "docker.io", true)
if err != nil {
t.Fatalf("Could not get registry client: %s", err)
}

View File

@@ -19,14 +19,11 @@
package resources
import (
"github.com/kubernetes-sigs/application/pkg/apis/app/v1beta1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sigs.k8s.io/application/pkg/apis/app/v1beta1"
"sort"
"strings"
)
type appSearcher struct {
@@ -37,67 +34,27 @@ func (*appSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*appSearcher) match(match map[string]string, item *v1beta1.Application) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*appSearcher) match(kv map[string]string, item *v1beta1.Application) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*appSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.Application) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*appSearcher) fuzzy(kv map[string]string, item *v1beta1.Application) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*appSearcher) compare(a, b *v1beta1.Application, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *appSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,16 +18,13 @@
package resources
import (
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
)
type clusterRoleSearcher struct {
@@ -38,26 +35,17 @@ func (*clusterRoleSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
for k, v := range match {
func (*clusterRoleSearcher) match(kv map[string]string, item *rbac.ClusterRole) bool {
for k, v := range kv {
switch k {
case OwnerKind:
fallthrough
case OwnerName:
kind := match[OwnerKind]
name := match[OwnerName]
kind := kv[OwnerKind]
name := kv[OwnerName]
if !k8sutil.IsControlledBy(item.OwnerReferences, kind, name) {
return false
}
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
case UserFacing:
if v == "true" {
if !isUserFacingClusterRole(item) {
@@ -65,8 +53,7 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
}
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -75,40 +62,17 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
}
// Fuzzy searchInNamespace
func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*clusterRoleSearcher) fuzzy(kv map[string]string, item *rbac.ClusterRole) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*clusterRoleSearcher) compare(a, b *rbac.ClusterRole, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *clusterRoleSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,15 +18,11 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type configMapSearcher struct {
@@ -37,67 +33,27 @@ func (*configMapSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*configMapSearcher) match(kv map[string]string, item *v1.ConfigMap) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*configMapSearcher) fuzzy(kv map[string]string, item *v1.ConfigMap) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*configMapSearcher) compare(a, b *v1.ConfigMap, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *configMapSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,10 +18,8 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
@@ -45,25 +43,15 @@ func cronJobStatus(item *v1beta1.CronJob) string {
}
// Exactly Match
func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bool {
for k, v := range match {
func (*cronJobSearcher) match(kv map[string]string, item *v1beta1.CronJob) bool {
for k, v := range kv {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Status:
if cronJobStatus(item) != v {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -71,34 +59,12 @@ func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bo
return true
}
func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.CronJob) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*cronJobSearcher) fuzzy(kv map[string]string, item *v1beta1.CronJob) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
@@ -111,13 +77,12 @@ func (*cronJobSearcher) compare(a, b *v1beta1.CronJob, orderBy string) bool {
if b.Status.LastScheduleTime == nil {
return false
}
if a.Status.LastScheduleTime.Equal(b.Status.LastScheduleTime) {
return strings.Compare(a.Name, b.Name) <= 0
}
return a.Status.LastScheduleTime.Before(b.Status.LastScheduleTime)
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
default:
fallthrough
case Name:
return strings.Compare(a.Name, b.Name) <= 0
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
}

View File

@@ -18,15 +18,11 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type daemonSetSearcher struct {
@@ -47,25 +43,15 @@ func daemonSetStatus(item *v1.DaemonSet) string {
}
// Exactly Match
func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool {
for k, v := range match {
func (*daemonSetSearcher) match(kv map[string]string, item *v1.DaemonSet) bool {
for k, v := range kv {
switch k {
case Status:
if daemonSetStatus(item) != v {
return false
}
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -73,46 +59,17 @@ func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) boo
return true
}
func (*daemonSetSearcher) fuzzy(fuzzy map[string]string, item *v1.DaemonSet) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*daemonSetSearcher) fuzzy(kv map[string]string, item *v1.DaemonSet) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*daemonSetSearcher) compare(a, b *v1.DaemonSet, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *daemonSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,10 +18,8 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"time"
@@ -52,25 +50,15 @@ func deploymentStatus(item *v1.Deployment) string {
}
// Exactly Match
func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool {
for k, v := range match {
func (*deploymentSearcher) match(kv map[string]string, item *v1.Deployment) bool {
for k, v := range kv {
switch k {
case Status:
if deploymentStatus(item) != v {
return false
}
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -78,47 +66,27 @@ func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) b
return true
}
func (*deploymentSearcher) fuzzy(fuzzy map[string]string, item *v1.Deployment) bool {
func (*deploymentSearcher) fuzzy(kv map[string]string, item *v1.Deployment) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (s *deploymentSearcher) compare(a, b *v1.Deployment, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case UpdateTime:
return s.lastUpdateTime(a).Before(s.lastUpdateTime(b))
case Name:
fallthrough
aLastUpdateTime := s.lastUpdateTime(a)
bLastUpdateTime := s.lastUpdateTime(b)
if aLastUpdateTime.Equal(bLastUpdateTime) {
return strings.Compare(a.Name, b.Name) <= 0
}
return aLastUpdateTime.Before(bLastUpdateTime)
default:
return strings.Compare(a.Name, b.Name) <= 0
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
}

View File

@@ -19,14 +19,10 @@ package resources
import (
autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2"
"kubesphere.io/kubesphere/pkg/constants"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/apimachinery/pkg/labels"
)
type hpaSearcher struct {
@@ -41,28 +37,19 @@ func hpaTargetMatch(item *autoscalingv2beta2.HorizontalPodAutoscaler, kind, name
}
// exactly Match
func (*hpaSearcher) match(match map[string]string, item *autoscalingv2beta2.HorizontalPodAutoscaler) bool {
for k, v := range match {
func (*hpaSearcher) match(kv map[string]string, item *autoscalingv2beta2.HorizontalPodAutoscaler) bool {
for k, v := range kv {
switch k {
case TargetKind:
fallthrough
case TargetName:
kind := match[TargetKind]
name := match[TargetName]
kind := kv[TargetKind]
name := kv[TargetName]
if !hpaTargetMatch(item, kind, name) {
return false
}
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
if item.Labels[k] != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -71,44 +58,17 @@ func (*hpaSearcher) match(match map[string]string, item *autoscalingv2beta2.Hori
}
// Fuzzy searchInNamespace
func (*hpaSearcher) fuzzy(fuzzy map[string]string, item *autoscalingv2beta2.HorizontalPodAutoscaler) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*hpaSearcher) fuzzy(kv map[string]string, item *autoscalingv2beta2.HorizontalPodAutoscaler) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
return false
}
}
}
return true
}
func (*hpaSearcher) compare(a, b *autoscalingv2beta2.HorizontalPodAutoscaler, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *hpaSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,14 +18,10 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
extensions "k8s.io/api/extensions/v1beta1"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/labels"
)
@@ -38,67 +34,27 @@ func (*ingressSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*ingressSearcher) match(kv map[string]string, item *extensions.Ingress) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*ingressSearcher) fuzzy(kv map[string]string, item *extensions.Ingress) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*ingressSearcher) compare(a, b *extensions.Ingress, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *ingressSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,11 +18,9 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"time"
@@ -51,8 +49,8 @@ func jobStatus(item *batchv1.Job) string {
}
// Exactly Match
func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
for k, v := range match {
func (*jobSearcher) match(kv map[string]string, item *batchv1.Job) bool {
for k, v := range kv {
switch k {
case Status:
if jobStatus(item) != v {
@@ -66,18 +64,8 @@ func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
if v == "false" && k8sutil.IsControlledBy(item.OwnerReferences, s2iRunKind, "") {
return false
}
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -85,34 +73,12 @@ func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
return true
}
func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchv1.Job) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*jobSearcher) fuzzy(kv map[string]string, item *batchv1.Job) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
@@ -131,14 +97,15 @@ func jobUpdateTime(item *batchv1.Job) time.Time {
func (*jobSearcher) compare(a, b *batchv1.Job, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case UpdateTime:
return jobUpdateTime(a).Before(jobUpdateTime(b))
case Name:
fallthrough
aUpdateTime := jobUpdateTime(a)
bUpdateTime := jobUpdateTime(b)
if aUpdateTime.Equal(bUpdateTime) {
return strings.Compare(a.Name, b.Name) <= 0
}
return aUpdateTime.Before(bUpdateTime)
default:
return strings.Compare(a.Name, b.Name) <= 0
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
}

View File

@@ -18,15 +18,11 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type namespaceSearcher struct {
@@ -37,67 +33,27 @@ func (*namespaceSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*namespaceSearcher) match(kv map[string]string, item *v1.Namespace) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*namespaceSearcher) fuzzy(kv map[string]string, item *v1.Namespace) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *namespaceSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -19,15 +19,11 @@ package resources
import (
"fmt"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type nodeSearcher struct {
@@ -53,10 +49,14 @@ func getNodeStatus(node *v1.Node) string {
const NodeConfigOK v1.NodeConditionType = "ConfigOK"
const NodeKubeletReady v1.NodeConditionType = "KubeletReady"
var expectedConditions = map[v1.NodeConditionType]v1.ConditionStatus{v1.NodeOutOfDisk: v1.ConditionFalse,
v1.NodeMemoryPressure: v1.ConditionFalse, v1.NodeDiskPressure: v1.ConditionFalse, v1.NodePIDPressure: v1.ConditionFalse,
v1.NodeNetworkUnavailable: v1.ConditionFalse, NodeConfigOK: v1.ConditionTrue, NodeKubeletReady: v1.ConditionTrue,
v1.NodeReady: v1.ConditionTrue,
var expectedConditions = map[v1.NodeConditionType]v1.ConditionStatus{
v1.NodeMemoryPressure: v1.ConditionFalse,
v1.NodeDiskPressure: v1.ConditionFalse,
v1.NodePIDPressure: v1.ConditionFalse,
v1.NodeNetworkUnavailable: v1.ConditionFalse,
NodeConfigOK: v1.ConditionTrue,
NodeKubeletReady: v1.ConditionTrue,
v1.NodeReady: v1.ConditionTrue,
}
func isUnhealthStatus(condition v1.NodeCondition) bool {
@@ -68,14 +68,9 @@ func isUnhealthStatus(condition v1.NodeCondition) bool {
}
// exactly Match
func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
for k, v := range match {
func (*nodeSearcher) match(kv map[string]string, item *v1.Node) bool {
for k, v := range kv {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Role:
labelKey := fmt.Sprintf("node-role.kubernetes.io/%s", v)
if _, ok := item.Labels[labelKey]; !ok {
@@ -85,13 +80,8 @@ func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
if getNodeStatus(item) != v {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -100,44 +90,17 @@ func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
}
// Fuzzy searchInNamespace
func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*nodeSearcher) fuzzy(kv map[string]string, item *v1.Node) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*nodeSearcher) compare(a, b *v1.Node, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *nodeSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,7 +18,6 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
@@ -49,14 +48,9 @@ func pvcStatus(item *v1.PersistentVolumeClaim) string {
}
// exactly Match
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
for k, v := range match {
func (*persistentVolumeClaimSearcher) match(kv map[string]string, item *v1.PersistentVolumeClaim) bool {
for k, v := range kv {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Status:
statuses := strings.Split(v, "|")
if !sliceutil.HasString(statuses, pvcStatus(item)) {
@@ -66,13 +60,8 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
if item.Spec.StorageClassName == nil || *item.Spec.StorageClassName != v {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -81,44 +70,17 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
}
// Fuzzy searchInNamespace
func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*persistentVolumeClaimSearcher) fuzzy(kv map[string]string, item *v1.PersistentVolumeClaim) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*persistentVolumeClaimSearcher) compare(a, b *v1.PersistentVolumeClaim, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -19,10 +19,8 @@ package resources
import (
appsv1 "k8s.io/api/apps/v1"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
@@ -147,14 +145,14 @@ func podBelongToService(item *v1.Pod, serviceName string) bool {
}
// exactly Match
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
for k, v := range match {
func (*podSearcher) match(kv map[string]string, item *v1.Pod) bool {
for k, v := range kv {
switch k {
case OwnerKind:
fallthrough
case OwnerName:
kind := match[OwnerKind]
name := match[OwnerName]
kind := kv[OwnerKind]
name := kv[OwnerName]
if !podBelongTo(item, kind, name) {
return false
}
@@ -170,18 +168,8 @@ func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
if !podBelongToService(item, v) {
return false
}
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -190,30 +178,10 @@ func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
}
// Fuzzy searchInNamespace
func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*podSearcher) fuzzy(kv map[string]string, item *v1.Pod) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
@@ -228,13 +196,12 @@ func (*podSearcher) compare(a, b *v1.Pod, orderBy string) bool {
if b.Status.StartTime == nil {
return true
}
if a.Status.StartTime.Equal(b.Status.StartTime) {
return strings.Compare(a.Name, b.Name) <= 0
}
return a.Status.StartTime.Before(b.Status.StartTime)
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
}

View File

@@ -19,7 +19,9 @@ package resources
import (
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
@@ -160,13 +162,26 @@ func ListResources(namespace, resource string, conditions *params.Conditions, or
return nil, err
}
for i, item := range result {
if i >= offset && (limit == -1 || len(items) < limit) {
items = append(items, injector.addExtraAnnotations(item))
}
totalCount := len(result)
// query all
if limit < 0 || offset < 0 {
result = result[:totalCount]
// out of range
} else if offset > totalCount {
result = result[:0]
// last page
} else if limit+offset > totalCount {
result = result[offset:totalCount]
} else {
result = result[offset : offset+limit]
}
return &models.PageableResponse{TotalCount: len(result), Items: items}, nil
for _, item := range result {
items = append(items, injector.addExtraAnnotations(item))
}
return &models.PageableResponse{TotalCount: totalCount, Items: items}, nil
}
func searchFuzzy(m map[string]string, key, value string) bool {
@@ -181,3 +196,64 @@ func searchFuzzy(m map[string]string, key, value string) bool {
return false
}
func match(key, value string, item metav1.ObjectMeta) bool {
switch key {
case Name:
names := strings.Split(value, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, value) && !searchFuzzy(item.Labels, "", value) && !searchFuzzy(item.Annotations, "", value) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[key]; !ok || val != value {
return false
}
}
return true
}
func fuzzy(key, value string, item metav1.ObjectMeta) bool {
switch key {
case Name:
if !strings.Contains(item.Name, value) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], value) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", value) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", value) {
return false
}
return false
case app:
if !strings.Contains(item.Labels[chart], value) && !strings.Contains(item.Labels[release], value) {
return false
}
default:
if !searchFuzzy(item.Labels, key, value) {
return false
}
}
return true
}
func compare(a, b metav1.ObjectMeta, by string) bool {
switch by {
case CreateTime:
if a.CreationTimestamp.Equal(&b.CreationTimestamp) {
return strings.Compare(a.Name, b.Name) <= 0
}
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
}

View File

@@ -18,15 +18,12 @@
package resources
import (
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
)
type roleSearcher struct {
@@ -37,18 +34,9 @@ func (*roleSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
for k, v := range match {
func (*roleSearcher) match(kv map[string]string, item *rbac.Role) bool {
for k, v := range kv {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
case UserFacing:
if v == "true" {
if !isUserFacingRole(item) {
@@ -56,8 +44,7 @@ func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
}
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -66,40 +53,17 @@ func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
}
// Fuzzy searchInNamespace
func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*roleSearcher) fuzzy(kv map[string]string, item *rbac.Role) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*roleSearcher) compare(a, b *rbac.Role, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *roleSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -21,12 +21,9 @@ package resources
import (
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
)
type s2iBuilderSearcher struct {
@@ -37,67 +34,27 @@ func (*s2iBuilderSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*s2iBuilderSearcher) match(match map[string]string, item *v1alpha1.S2iBuilder) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*s2iBuilderSearcher) match(kv map[string]string, item *v1alpha1.S2iBuilder) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*s2iBuilderSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuilder) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*s2iBuilderSearcher) fuzzy(kv map[string]string, item *v1alpha1.S2iBuilder) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*s2iBuilderSearcher) compare(a, b *v1alpha1.S2iBuilder, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *s2iBuilderSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -19,14 +19,10 @@ package resources
import (
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"kubesphere.io/kubesphere/pkg/constants"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/apimachinery/pkg/labels"
)
type s2iBuilderTemplateSearcher struct {
@@ -37,63 +33,27 @@ func (*s2iBuilderTemplateSearcher) get(namespace, name string) (interface{}, err
}
// exactly Match
func (*s2iBuilderTemplateSearcher) match(match map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*s2iBuilderTemplateSearcher) match(kv map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*s2iBuilderTemplateSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*s2iBuilderTemplateSearcher) fuzzy(kv map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*s2iBuilderTemplateSearcher) compare(a, b *v1alpha1.S2iBuilderTemplate, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *s2iBuilderTemplateSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -19,13 +19,9 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
"k8s.io/apimachinery/pkg/labels"
@@ -40,25 +36,15 @@ func (*s2iRunSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*s2iRunSearcher) match(match map[string]string, item *v1alpha1.S2iRun) bool {
for k, v := range match {
func (*s2iRunSearcher) match(kv map[string]string, item *v1alpha1.S2iRun) bool {
for k, v := range kv {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Status:
if string(item.Status.RunState) != v {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -67,44 +53,17 @@ func (*s2iRunSearcher) match(match map[string]string, item *v1alpha1.S2iRun) boo
}
// Fuzzy searchInNamespace
func (*s2iRunSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iRun) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*s2iRunSearcher) fuzzy(kv map[string]string, item *v1alpha1.S2iRun) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*s2iRunSearcher) compare(a, b *v1alpha1.S2iRun, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *s2iRunSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,15 +18,11 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type secretSearcher struct {
@@ -37,25 +33,15 @@ func (*secretSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
for k, v := range match {
func (*secretSearcher) match(kv map[string]string, item *v1.Secret) bool {
for k, v := range kv {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case "type":
if string(item.Type) != v {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -64,44 +50,17 @@ func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
}
// Fuzzy searchInNamespace
func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*secretSearcher) fuzzy(kv map[string]string, item *v1.Secret) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*secretSearcher) compare(a, b *v1.Secret, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *secretSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,15 +18,11 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type serviceSearcher struct {
@@ -37,67 +33,27 @@ func (*serviceSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*serviceSearcher) match(kv map[string]string, item *v1.Service) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*serviceSearcher) fuzzy(kv map[string]string, item *v1.Service) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*serviceSearcher) compare(a, b *v1.Service, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *serviceSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,15 +18,11 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type statefulSetSearcher struct {
@@ -50,25 +46,15 @@ func statefulSetStatus(item *v1.StatefulSet) string {
}
// Exactly Match
func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool {
for k, v := range match {
func (*statefulSetSearcher) match(kv map[string]string, item *v1.StatefulSet) bool {
for k, v := range kv {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
case Status:
if statefulSetStatus(item) != v {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
if !match(k, v, item.ObjectMeta) {
return false
}
}
@@ -76,46 +62,17 @@ func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet)
return true
}
func (*statefulSetSearcher) fuzzy(fuzzy map[string]string, item *v1.StatefulSet) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*statefulSetSearcher) fuzzy(kv map[string]string, item *v1.StatefulSet) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*statefulSetSearcher) compare(a, b *v1.StatefulSet, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *statefulSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,15 +18,11 @@
package resources
import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"sort"
)
type storageClassesSearcher struct {
@@ -37,63 +33,27 @@ func (*storageClassesSearcher) get(namespace, name string) (interface{}, error)
}
// exactly Match
func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*storageClassesSearcher) match(kv map[string]string, item *v1.StorageClass) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*storageClassesSearcher) fuzzy(kv map[string]string, item *v1.StorageClass) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*storageClassesSearcher) compare(a, b *v1.StorageClass, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *storageClassesSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -18,15 +18,11 @@
package resources
import (
"k8s.io/apimachinery/pkg/labels"
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/apimachinery/pkg/labels"
)
type workspaceSearcher struct {
@@ -37,67 +33,27 @@ func (*workspaceSearcher) get(namespace, name string) (interface{}, error) {
}
// exactly Match
func (*workspaceSearcher) match(match map[string]string, item *tenantv1alpha1.Workspace) bool {
for k, v := range match {
switch k {
case Name:
names := strings.Split(v, "|")
if !sliceutil.HasString(names, item.Name) {
return false
}
case Keyword:
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
return false
}
default:
// label not exist or value not equal
if val, ok := item.Labels[k]; !ok || val != v {
return false
}
func (*workspaceSearcher) match(kv map[string]string, item *tenantv1alpha1.Workspace) bool {
for k, v := range kv {
if !match(k, v, item.ObjectMeta) {
return false
}
}
return true
}
// Fuzzy searchInNamespace
func (*workspaceSearcher) fuzzy(fuzzy map[string]string, item *tenantv1alpha1.Workspace) bool {
for k, v := range fuzzy {
switch k {
case Name:
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false
}
case Label:
if !searchFuzzy(item.Labels, "", v) {
return false
}
case annotation:
if !searchFuzzy(item.Annotations, "", v) {
return false
}
func (*workspaceSearcher) fuzzy(kv map[string]string, item *tenantv1alpha1.Workspace) bool {
for k, v := range kv {
if !fuzzy(k, v, item.ObjectMeta) {
return false
case app:
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
return false
}
default:
if !searchFuzzy(item.Labels, k, v) {
return false
}
}
}
return true
}
func (*workspaceSearcher) compare(a, b *tenantv1alpha1.Workspace, orderBy string) bool {
switch orderBy {
case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case Name:
fallthrough
default:
return strings.Compare(a.Name, b.Name) <= 0
}
return compare(a.ObjectMeta, b.ObjectMeta, orderBy)
}
func (s *workspaceSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {

View File

@@ -21,6 +21,7 @@ package routers
import (
"fmt"
"io/ioutil"
v1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog"
@@ -31,8 +32,7 @@ import (
"kubesphere.io/kubesphere/pkg/informers"
corev1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
"strings"
@@ -41,24 +41,24 @@ import (
)
// choose router node ip by labels, currently select master node
var RouterNodeIPLabelSelector = map[string]string{
var routerNodeIPLabelSelector = map[string]string{
"node-role.kubernetes.io/master": "",
}
const (
SERVICEMESH_ENABLED = "servicemesh.kubesphere.io/enabled"
SIDECAR_INJECT = "sidecar.istio.io/inject"
servicemeshEnabled = "servicemesh.kubesphere.io/enabled"
sidecarInject = "sidecar.istio.io/inject"
)
var routerTemplates map[string]runtime.Object
// Load yamls
func init() {
yamls, err := LoadYamls()
yamls, err := loadYamls()
routerTemplates = make(map[string]runtime.Object, 2)
if err != nil {
klog.Error(err)
klog.Warning("error happened during loading external yamls", err)
return
}
@@ -74,7 +74,7 @@ func init() {
switch obj.(type) {
case *corev1.Service:
routerTemplates["SERVICE"] = obj
case *extensionsv1beta1.Deployment:
case *v1.Deployment:
routerTemplates["DEPLOYMENT"] = obj
}
}
@@ -86,7 +86,7 @@ func init() {
func getMasterNodeIp() string {
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
selector := labels.SelectorFromSet(RouterNodeIPLabelSelector)
selector := labels.SelectorFromSet(routerNodeIPLabelSelector)
masters, err := nodeLister.List(selector)
sort.Slice(masters, func(i, j int) bool {
@@ -174,13 +174,13 @@ func getRouterService(namespace string) (*corev1.Service, error) {
}
// Load all resource yamls
func LoadYamls() ([]string, error) {
func loadYamls() ([]string, error) {
var yamls []string
files, err := ioutil.ReadDir(constants.IngressControllerFolder)
if err != nil {
klog.Error(err)
klog.Warning(err)
return nil, err
}
@@ -205,7 +205,7 @@ func LoadYamls() ([]string, error) {
func CreateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
injectSidecar := false
if enabled, ok := annotations[SERVICEMESH_ENABLED]; ok {
if enabled, ok := annotations[servicemeshEnabled]; ok {
if enabled == "true" {
injectSidecar = true
}
@@ -307,7 +307,7 @@ func deleteRouterService(namespace string) (*corev1.Service, error) {
// delete controller service
serviceName := constants.IngressControllerPrefix + namespace
deleteOptions := meta_v1.DeleteOptions{}
deleteOptions := metav1.DeleteOptions{}
err = k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Delete(serviceName, &deleteOptions)
if err != nil {
@@ -328,13 +328,13 @@ func createOrUpdateRouterWorkload(namespace string, publishService bool, service
deployName := constants.IngressControllerPrefix + namespace
k8sClient := client.ClientSets().K8s().Kubernetes()
deployment, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Get(deployName, meta_v1.GetOptions{})
deployment, err := k8sClient.AppsV1().Deployments(constants.IngressControllerNamespace).Get(deployName, metav1.GetOptions{})
createDeployment := true
if err != nil {
if errors.IsNotFound(err) {
deployment = obj.(*extensionsv1beta1.Deployment)
deployment = obj.(*v1.Deployment)
deployment.Name = constants.IngressControllerPrefix + namespace
@@ -376,9 +376,9 @@ func createOrUpdateRouterWorkload(namespace string, publishService bool, service
deployment.Spec.Template.Annotations = make(map[string]string, 0)
}
if servicemeshEnabled {
deployment.Spec.Template.Annotations[SIDECAR_INJECT] = "true"
deployment.Spec.Template.Annotations[sidecarInject] = "true"
} else {
deployment.Spec.Template.Annotations[SIDECAR_INJECT] = "false"
deployment.Spec.Template.Annotations[sidecarInject] = "false"
}
if publishService {
@@ -388,9 +388,9 @@ func createOrUpdateRouterWorkload(namespace string, publishService bool, service
}
if createDeployment {
deployment, err = k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Create(deployment)
deployment, err = k8sClient.AppsV1().Deployments(constants.IngressControllerNamespace).Create(deployment)
} else {
deployment, err = k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Update(deployment)
deployment, err = k8sClient.AppsV1().Deployments(constants.IngressControllerNamespace).Update(deployment)
}
if err != nil {
@@ -404,10 +404,10 @@ func createOrUpdateRouterWorkload(namespace string, publishService bool, service
func deleteRouterWorkload(namespace string) error {
k8sClient := client.ClientSets().K8s().Kubernetes()
deleteOptions := meta_v1.DeleteOptions{}
deleteOptions := metav1.DeleteOptions{}
// delete controller deployment
deploymentName := constants.IngressControllerPrefix + namespace
err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Delete(deploymentName, &deleteOptions)
err := k8sClient.AppsV1().Deployments(constants.IngressControllerNamespace).Delete(deploymentName, &deleteOptions)
if err != nil {
klog.Error(err)
}
@@ -448,7 +448,7 @@ func UpdateRouter(namespace string, routerType corev1.ServiceType, annotations m
return router, err
}
enableServicemesh := annotations[SERVICEMESH_ENABLED] == "true"
enableServicemesh := annotations[servicemeshEnabled] == "true"
err = createOrUpdateRouterWorkload(namespace, routerType == corev1.ServiceTypeLoadBalancer, enableServicemesh)
if err != nil {

View File

@@ -18,6 +18,7 @@
package storage
import (
"kubesphere.io/kubesphere/pkg/simple/client"
"strconv"
"k8s.io/api/core/v1"
@@ -27,16 +28,17 @@ import (
"kubesphere.io/kubesphere/pkg/informers"
)
const (
IsDefaultStorageClassAnnotation = "storageclass.kubernetes.io/is-default-class"
betaIsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class"
)
type ScMetrics struct {
Capacity string `json:"capacity,omitempty"`
Usage string `json:"usage,omitempty"`
PvcNumber string `json:"pvcNumber"`
}
func init() {
}
func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
persistentVolumeClaimLister := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
all, err := persistentVolumeClaimLister.List(labels.Everything())
@@ -102,3 +104,36 @@ func GetScList() ([]*storageV1.StorageClass, error) {
return scList, nil
}
func SetDefaultStorageClass(defaultScName string) (*storageV1.StorageClass, error) {
scLister := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister()
// 1. verify storage class name
sc, err := scLister.Get(defaultScName)
if sc == nil || err != nil {
return sc, err
}
// 2. unset all default sc and then set default sc
scList, err := scLister.List(labels.Everything())
if err != nil {
return nil, err
}
k8sClient := client.ClientSets().K8s().Kubernetes()
var defaultSc *storageV1.StorageClass
for _, sc := range scList {
_, hasDefault := sc.Annotations[IsDefaultStorageClassAnnotation]
_, hasBeta := sc.Annotations[betaIsDefaultStorageClassAnnotation]
if sc.Name == defaultScName || hasDefault || hasBeta {
delete(sc.Annotations, IsDefaultStorageClassAnnotation)
delete(sc.Annotations, betaIsDefaultStorageClassAnnotation)
if sc.Name == defaultScName {
sc.Annotations[IsDefaultStorageClassAnnotation] = "true"
defaultSc = sc
}
_, err := k8sClient.StorageV1().StorageClasses().Update(sc)
if err != nil {
return nil, err
}
}
}
return defaultSc, nil
}

View File

@@ -123,9 +123,7 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
// order & reverse
sort.Slice(result, func(i, j int) bool {
if reverse {
tmp := i
i = j
j = tmp
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
})

View File

@@ -156,16 +156,26 @@ func DeleteWorkspaceRoleBinding(workspace, username string, role string) error {
}
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
for i, v := range workspaceRoleBinding.Subjects {
if v.Kind == v1.UserKind && v.Name == username {
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects[:i], workspaceRoleBinding.Subjects[i+1:]...)
i--
subjects := make([]v1.Subject, 0)
for _, subject := range workspaceRoleBinding.Subjects {
if subject.Kind != v1.UserKind || subject.Name != username {
subjects = append(subjects, subject)
}
}
workspaceRoleBinding, err = clientset.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
if len(subjects) != len(workspaceRoleBinding.Subjects) {
workspaceRoleBinding.Subjects = subjects
return err
_, err = clientset.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
if err != nil {
klog.Errorln(err)
return err
}
}
return nil
}
func GetDevOpsProjectsCount(workspaceName string) (int, error) {

View File

@@ -30,22 +30,26 @@ const (
OrderByParam = "orderBy"
ConditionsParam = "conditions"
ReverseParam = "reverse"
NameParam = "name"
defaultLimit = 10
defaultOffset = 0
)
func ParsePaging(paging string) (limit, offset int) {
limit = 10
offset = 0
func ParsePaging(req *restful.Request) (limit, offset int) {
paging := req.QueryParameter(PagingParam)
if groups := regexp.MustCompile(`^limit=(-?\d+),page=(\d+)$`).FindStringSubmatch(paging); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
offset = (page - 1) * limit
} else {
limit = defaultLimit
offset = defaultOffset
}
return
}
func ParseConditions(conditionsStr string) (*Conditions, error) {
func ParseConditions(req *restful.Request) (*Conditions, error) {
conditionsStr := req.QueryParameter(ConditionsParam)
conditions := &Conditions{Match: make(map[string]string, 0), Fuzzy: make(map[string]string, 0)}
@@ -76,16 +80,23 @@ func ParseConditions(conditionsStr string) (*Conditions, error) {
return conditions, nil
}
func ParseReverse(req *restful.Request) bool {
reverse := req.QueryParameter(ReverseParam)
b, err := strconv.ParseBool(reverse)
if err != nil {
return false
}
return b
}
type Conditions struct {
Match map[string]string
Fuzzy map[string]string
}
func GetBoolValueWithDefault(req *restful.Request, name string, dv bool) bool {
reverse := req.QueryParameter(name)
if v, err := strconv.ParseBool(reverse); err == nil {
return v
}
return dv
}
func GetStringValueWithDefault(req *restful.Request, name string, dv string) string {
v := req.QueryParameter(name)
if v == "" {
v = dv
}
return v
}

View File

@@ -1,13 +1,13 @@
package k8s
import (
applicationclientset "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
s2i "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
applicationclientset "sigs.k8s.io/application/pkg/client/clientset/versioned"
"strings"
)

View File

@@ -212,16 +212,15 @@ func (c *OpenPitrixClient) Attachment() pb.AttachmentManagerClient {
}
func SystemContext() context.Context {
ctx := context.Background()
ctx = ctxutil.ContextWithSender(ctx, sender.New(SystemUsername, SystemUserPath, ""))
return ctx
return ContextWithUsername(SystemUsername)
}
func ContextWithUsername(username string) context.Context {
ctx := context.Background()
if username == "" {
username = SystemUsername
}
ctx = ctxutil.ContextWithSender(ctx, sender.New(username, SystemUserPath, ""))
ownerPath := fmt.Sprintf(":%s", username)
ctx = ctxutil.ContextWithSender(ctx, sender.New(username, sender.OwnerPath(ownerPath), ""))
return ctx
}

View File

@@ -6,8 +6,7 @@ import (
"time"
osappsv1 "github.com/openshift/api/apps/v1"
"k8s.io/api/apps/v1beta1"
"k8s.io/api/apps/v1beta2"
appsv1 "k8s.io/api/apps/v1"
batch_v1 "k8s.io/api/batch/v1"
batch_v1beta1 "k8s.io/api/batch/v1beta1"
"k8s.io/api/core/v1"
@@ -123,10 +122,10 @@ func (in *WorkloadService) GetPods(namespace string, labelSelector string) (mode
func fetchWorkloads(k8s kubernetes.IstioClientInterface, namespace string, labelSelector string) (models.Workloads, error) {
var pods []v1.Pod
var repcon []v1.ReplicationController
var dep []v1beta1.Deployment
var repset []v1beta2.ReplicaSet
var dep []appsv1.Deployment
var repset []appsv1.ReplicaSet
var depcon []osappsv1.DeploymentConfig
var fulset []v1beta2.StatefulSet
var fulset []appsv1.StatefulSet
var jbs []batch_v1.Job
var conjbs []batch_v1beta1.CronJob
@@ -572,10 +571,10 @@ func fetchWorkloads(k8s kubernetes.IstioClientInterface, namespace string, label
func fetchWorkload(k8s kubernetes.IstioClientInterface, namespace string, workloadName string) (*models.Workload, error) {
var pods []v1.Pod
var repcon []v1.ReplicationController
var dep *v1beta1.Deployment
var repset []v1beta2.ReplicaSet
var dep *appsv1.Deployment
var repset []appsv1.ReplicaSet
var depcon *osappsv1.DeploymentConfig
var fulset *v1beta2.StatefulSet
var fulset *appsv1.StatefulSet
var jbs []batch_v1.Job
var conjbs []batch_v1beta1.CronJob

View File

@@ -6,8 +6,7 @@ import (
"sync"
"time"
"k8s.io/api/apps/v1beta1"
"k8s.io/api/apps/v1beta2"
appsv1 "k8s.io/api/apps/v1"
batch_v1 "k8s.io/api/batch/v1"
batch_v1beta1 "k8s.io/api/batch/v1beta1"
"k8s.io/api/core/v1"
@@ -31,17 +30,17 @@ type (
// Business methods
GetCronJobs(namespace string) ([]batch_v1beta1.CronJob, error)
GetDeployment(namespace string, name string) (*v1beta1.Deployment, error)
GetDeployments(namespace string) ([]v1beta1.Deployment, error)
GetDeployment(namespace string, name string) (*appsv1.Deployment, error)
GetDeployments(namespace string) ([]appsv1.Deployment, error)
GetEndpoints(namespace, name string) (*v1.Endpoints, error)
GetJobs(namespace string) ([]batch_v1.Job, error)
GetPods(namespace string) ([]v1.Pod, error)
GetReplicationControllers(namespace string) ([]v1.ReplicationController, error)
GetReplicaSets(namespace string) ([]v1beta2.ReplicaSet, error)
GetReplicaSets(namespace string) ([]appsv1.ReplicaSet, error)
GetService(namespace string, name string) (*v1.Service, error)
GetServices(namespace string) ([]v1.Service, error)
GetStatefulSet(namespace string, name string) (*v1beta2.StatefulSet, error)
GetStatefulSets(namespace string) ([]v1beta2.StatefulSet, error)
GetStatefulSet(namespace string, name string) (*appsv1.StatefulSet, error)
GetStatefulSets(namespace string) ([]appsv1.StatefulSet, error)
}
controllerImpl struct {
@@ -106,9 +105,9 @@ func initControllers(clientset kube.Interface, refreshDuration time.Duration) ma
controllers := make(map[string]cache.SharedIndexInformer)
controllers["Pod"] = sharedInformers.Core().V1().Pods().Informer()
controllers["ReplicationController"] = sharedInformers.Core().V1().ReplicationControllers().Informer()
controllers["Deployment"] = sharedInformers.Apps().V1beta1().Deployments().Informer()
controllers["ReplicaSet"] = sharedInformers.Apps().V1beta2().ReplicaSets().Informer()
controllers["StatefulSet"] = sharedInformers.Apps().V1beta2().StatefulSets().Informer()
controllers["Deployment"] = sharedInformers.Apps().V1().Deployments().Informer()
controllers["ReplicaSet"] = sharedInformers.Apps().V1().ReplicaSets().Informer()
controllers["StatefulSet"] = sharedInformers.Apps().V1().StatefulSets().Informer()
controllers["Job"] = sharedInformers.Batch().V1().Jobs().Informer()
controllers["CronJob"] = sharedInformers.Batch().V1beta1().CronJobs().Informer()
controllers["Service"] = sharedInformers.Core().V1().Services().Informer()
@@ -221,7 +220,7 @@ func (c *controllerImpl) GetCronJobs(namespace string) ([]batch_v1beta1.CronJob,
return []batch_v1beta1.CronJob{}, nil
}
func (c *controllerImpl) GetDeployment(namespace, name string) (*v1beta1.Deployment, error) {
func (c *controllerImpl) GetDeployment(namespace, name string) (*appsv1.Deployment, error) {
if err := c.checkStateAndRetry(); err != nil {
return nil, err
}
@@ -231,36 +230,36 @@ func (c *controllerImpl) GetDeployment(namespace, name string) (*v1beta1.Deploym
return nil, err
}
if exist {
dep, ok := deps.(*v1beta1.Deployment)
dep, ok := deps.(*appsv1.Deployment)
if !ok {
return nil, errors.New("Bad Deployment type found in cache")
}
return dep, nil
}
return nil, NewNotFound(name, "apps/v1beta1", "Deployment")
return nil, NewNotFound(name, "apps/v1", "Deployment")
}
func (c *controllerImpl) GetDeployments(namespace string) ([]v1beta1.Deployment, error) {
func (c *controllerImpl) GetDeployments(namespace string) ([]appsv1.Deployment, error) {
if err := c.checkStateAndRetry(); err != nil {
return []v1beta1.Deployment{}, err
return []appsv1.Deployment{}, err
}
indexer := c.controllers["Deployment"].GetIndexer()
deps, err := indexer.ByIndex("namespace", namespace)
if err != nil {
return []v1beta1.Deployment{}, err
return []appsv1.Deployment{}, err
}
if len(deps) > 0 {
_, ok := deps[0].(*v1beta1.Deployment)
_, ok := deps[0].(*appsv1.Deployment)
if !ok {
return nil, errors.New("Bad Deployment type found in cache")
}
nsDeps := make([]v1beta1.Deployment, len(deps))
nsDeps := make([]appsv1.Deployment, len(deps))
for i, dep := range deps {
nsDeps[i] = *(dep.(*v1beta1.Deployment))
nsDeps[i] = *(dep.(*appsv1.Deployment))
}
return nsDeps, nil
}
return []v1beta1.Deployment{}, nil
return []appsv1.Deployment{}, nil
}
func (c *controllerImpl) GetEndpoints(namespace, name string) (*v1.Endpoints, error) {
@@ -351,30 +350,30 @@ func (c *controllerImpl) GetReplicationControllers(namespace string) ([]v1.Repli
return []v1.ReplicationController{}, nil
}
func (c *controllerImpl) GetReplicaSets(namespace string) ([]v1beta2.ReplicaSet, error) {
func (c *controllerImpl) GetReplicaSets(namespace string) ([]appsv1.ReplicaSet, error) {
if err := c.checkStateAndRetry(); err != nil {
return []v1beta2.ReplicaSet{}, err
return []appsv1.ReplicaSet{}, err
}
indexer := c.controllers["ReplicaSet"].GetIndexer()
repsets, err := indexer.ByIndex("namespace", namespace)
if err != nil {
return []v1beta2.ReplicaSet{}, err
return []appsv1.ReplicaSet{}, err
}
if len(repsets) > 0 {
_, ok := repsets[0].(*v1beta2.ReplicaSet)
_, ok := repsets[0].(*appsv1.ReplicaSet)
if !ok {
return []v1beta2.ReplicaSet{}, errors.New("Bad ReplicaSet type found in cache")
return []appsv1.ReplicaSet{}, errors.New("Bad ReplicaSet type found in cache")
}
nsRepsets := make([]v1beta2.ReplicaSet, len(repsets))
nsRepsets := make([]appsv1.ReplicaSet, len(repsets))
for i, repset := range repsets {
nsRepsets[i] = *(repset.(*v1beta2.ReplicaSet))
nsRepsets[i] = *(repset.(*appsv1.ReplicaSet))
}
return nsRepsets, nil
}
return []v1beta2.ReplicaSet{}, nil
return []appsv1.ReplicaSet{}, nil
}
func (c *controllerImpl) GetStatefulSet(namespace, name string) (*v1beta2.StatefulSet, error) {
func (c *controllerImpl) GetStatefulSet(namespace, name string) (*appsv1.StatefulSet, error) {
if err := c.checkStateAndRetry(); err != nil {
return nil, err
}
@@ -384,36 +383,36 @@ func (c *controllerImpl) GetStatefulSet(namespace, name string) (*v1beta2.Statef
return nil, err
}
if exist {
fulset, ok := fulsets.(*v1beta2.StatefulSet)
fulset, ok := fulsets.(*appsv1.StatefulSet)
if !ok {
return nil, errors.New("Bad StatefulSet type found in cache")
}
return fulset, nil
}
return nil, NewNotFound(name, "apps/v1beta2", "StatefulSet")
return nil, NewNotFound(name, "apps/v1", "StatefulSet")
}
func (c *controllerImpl) GetStatefulSets(namespace string) ([]v1beta2.StatefulSet, error) {
func (c *controllerImpl) GetStatefulSets(namespace string) ([]appsv1.StatefulSet, error) {
if err := c.checkStateAndRetry(); err != nil {
return []v1beta2.StatefulSet{}, err
return []appsv1.StatefulSet{}, err
}
indexer := c.controllers["StatefulSet"].GetIndexer()
fulsets, err := indexer.ByIndex("namespace", namespace)
if err != nil {
return []v1beta2.StatefulSet{}, err
return []appsv1.StatefulSet{}, err
}
if len(fulsets) > 0 {
_, ok := fulsets[0].(*v1beta2.StatefulSet)
_, ok := fulsets[0].(*appsv1.StatefulSet)
if !ok {
return []v1beta2.StatefulSet{}, errors.New("Bad StatefulSet type found in cache")
return []appsv1.StatefulSet{}, errors.New("Bad StatefulSet type found in cache")
}
nsFulsets := make([]v1beta2.StatefulSet, len(fulsets))
nsFulsets := make([]appsv1.StatefulSet, len(fulsets))
for i, fulset := range fulsets {
nsFulsets[i] = *(fulset.(*v1beta2.StatefulSet))
nsFulsets[i] = *(fulset.(*appsv1.StatefulSet))
}
return nsFulsets, nil
}
return []v1beta2.StatefulSet{}, nil
return []appsv1.StatefulSet{}, nil
}
func (c *controllerImpl) GetService(namespace, name string) (*v1.Service, error) {

View File

@@ -7,8 +7,7 @@ import (
"os"
"time"
"k8s.io/api/apps/v1beta1"
"k8s.io/api/apps/v1beta2"
appsv1 "k8s.io/api/apps/v1"
auth_v1 "k8s.io/api/authorization/v1"
batch_v1 "k8s.io/api/batch/v1"
batch_v1beta1 "k8s.io/api/batch/v1beta1"
@@ -39,8 +38,8 @@ type IstioClientInterface interface {
GetAdapter(namespace, adapterType, adapterName string) (IstioObject, error)
GetAdapters(namespace string) ([]IstioObject, error)
GetCronJobs(namespace string) ([]batch_v1beta1.CronJob, error)
GetDeployment(namespace string, deploymentName string) (*v1beta1.Deployment, error)
GetDeployments(namespace string) ([]v1beta1.Deployment, error)
GetDeployment(namespace string, deploymentName string) (*appsv1.Deployment, error)
GetDeployments(namespace string) ([]appsv1.Deployment, error)
GetDeploymentConfig(namespace string, deploymentconfigName string) (*osappsv1.DeploymentConfig, error)
GetDeploymentConfigs(namespace string) ([]osappsv1.DeploymentConfig, error)
GetDestinationRule(namespace string, destinationrule string) (IstioObject, error)
@@ -62,14 +61,14 @@ type IstioClientInterface interface {
GetQuotaSpecBinding(namespace string, quotaSpecBindingName string) (IstioObject, error)
GetQuotaSpecBindings(namespace string) ([]IstioObject, error)
GetReplicationControllers(namespace string) ([]v1.ReplicationController, error)
GetReplicaSets(namespace string) ([]v1beta2.ReplicaSet, error)
GetReplicaSets(namespace string) ([]appsv1.ReplicaSet, error)
GetSelfSubjectAccessReview(namespace, api, resourceType string, verbs []string) ([]*auth_v1.SelfSubjectAccessReview, error)
GetService(namespace string, serviceName string) (*v1.Service, error)
GetServices(namespace string, selectorLabels map[string]string) ([]v1.Service, error)
GetServiceEntries(namespace string) ([]IstioObject, error)
GetServiceEntry(namespace string, serviceEntryName string) (IstioObject, error)
GetStatefulSet(namespace string, statefulsetName string) (*v1beta2.StatefulSet, error)
GetStatefulSets(namespace string) ([]v1beta2.StatefulSet, error)
GetStatefulSet(namespace string, statefulsetName string) (*appsv1.StatefulSet, error)
GetStatefulSets(namespace string) ([]appsv1.StatefulSet, error)
GetTemplate(namespace, templateType, templateName string) (IstioObject, error)
GetTemplates(namespace string) ([]IstioObject, error)
GetPolicy(namespace string, policyName string) (IstioObject, error)

View File

@@ -1,8 +1,7 @@
package kubernetes
import (
"k8s.io/api/apps/v1beta1"
"k8s.io/api/apps/v1beta2"
appsv1 "k8s.io/api/apps/v1"
auth_v1 "k8s.io/api/authorization/v1"
batch_v1 "k8s.io/api/batch/v1"
batch_v1beta1 "k8s.io/api/batch/v1beta1"
@@ -109,23 +108,23 @@ func (in *IstioClient) GetServices(namespace string, selectorLabels map[string]s
// GetDeployment returns the definition of a specific deployment.
// It returns an error on any problem.
func (in *IstioClient) GetDeployment(namespace, deploymentName string) (*v1beta1.Deployment, error) {
func (in *IstioClient) GetDeployment(namespace, deploymentName string) (*appsv1.Deployment, error) {
if in.k8sCache != nil {
return in.k8sCache.GetDeployment(namespace, deploymentName)
}
return in.k8s.AppsV1beta1().Deployments(namespace).Get(deploymentName, emptyGetOptions)
return in.k8s.AppsV1().Deployments(namespace).Get(deploymentName, emptyGetOptions)
}
// GetDeployments returns an array of deployments for a given namespace and a set of labels.
// It returns an error on any problem.
func (in *IstioClient) GetDeployments(namespace string) ([]v1beta1.Deployment, error) {
func (in *IstioClient) GetDeployments(namespace string) ([]appsv1.Deployment, error) {
if in.k8sCache != nil {
return in.k8sCache.GetDeployments(namespace)
}
if depList, err := in.k8s.AppsV1beta1().Deployments(namespace).List(emptyListOptions); err == nil {
if depList, err := in.k8s.AppsV1().Deployments(namespace).List(emptyListOptions); err == nil {
return depList.Items, nil
} else {
return []v1beta1.Deployment{}, err
return []appsv1.Deployment{}, err
}
}
@@ -152,32 +151,32 @@ func (in *IstioClient) GetDeploymentConfigs(namespace string) ([]osappsv1.Deploy
return result.Items, nil
}
func (in *IstioClient) GetReplicaSets(namespace string) ([]v1beta2.ReplicaSet, error) {
func (in *IstioClient) GetReplicaSets(namespace string) ([]appsv1.ReplicaSet, error) {
if in.k8sCache != nil {
return in.k8sCache.GetReplicaSets(namespace)
}
if rsList, err := in.k8s.AppsV1beta2().ReplicaSets(namespace).List(emptyListOptions); err == nil {
if rsList, err := in.k8s.AppsV1().ReplicaSets(namespace).List(emptyListOptions); err == nil {
return rsList.Items, nil
} else {
return []v1beta2.ReplicaSet{}, err
return []appsv1.ReplicaSet{}, err
}
}
func (in *IstioClient) GetStatefulSet(namespace string, statefulsetName string) (*v1beta2.StatefulSet, error) {
func (in *IstioClient) GetStatefulSet(namespace string, statefulsetName string) (*appsv1.StatefulSet, error) {
if in.k8sCache != nil {
return in.k8sCache.GetStatefulSet(namespace, statefulsetName)
}
return in.k8s.AppsV1beta2().StatefulSets(namespace).Get(statefulsetName, emptyGetOptions)
return in.k8s.AppsV1().StatefulSets(namespace).Get(statefulsetName, emptyGetOptions)
}
func (in *IstioClient) GetStatefulSets(namespace string) ([]v1beta2.StatefulSet, error) {
func (in *IstioClient) GetStatefulSets(namespace string) ([]appsv1.StatefulSet, error) {
if in.k8sCache != nil {
return in.k8sCache.GetStatefulSets(namespace)
}
if ssList, err := in.k8s.AppsV1beta2().StatefulSets(namespace).List(emptyListOptions); err == nil {
if ssList, err := in.k8s.AppsV1().StatefulSets(namespace).List(emptyListOptions); err == nil {
return ssList.Items, nil
} else {
return []v1beta2.StatefulSet{}, err
return []appsv1.StatefulSet{}, err
}
}

View File

@@ -6,8 +6,7 @@ import (
osappsv1 "github.com/openshift/api/apps/v1"
osv1 "github.com/openshift/api/project/v1"
"github.com/stretchr/testify/mock"
"k8s.io/api/apps/v1beta1"
"k8s.io/api/apps/v1beta2"
appsv1 "k8s.io/api/apps/v1"
auth_v1 "k8s.io/api/authorization/v1"
batch_v1 "k8s.io/api/batch/v1"
batch_v1beta1 "k8s.io/api/batch/v1beta1"
@@ -33,11 +32,11 @@ func NewK8SClientMock() *K8SClientMock {
// MockEmptyWorkloads setup the current mock to return empty workloads for every type of workloads (deployment, dc, rs, jobs, etc.)
func (o *K8SClientMock) MockEmptyWorkloads(namespace interface{}) {
o.On("GetDeployments", namespace).Return([]v1beta1.Deployment{}, nil)
o.On("GetReplicaSets", namespace).Return([]v1beta2.ReplicaSet{}, nil)
o.On("GetDeployments", namespace).Return([]appsv1.Deployment{}, nil)
o.On("GetReplicaSets", namespace).Return([]appsv1.ReplicaSet{}, nil)
o.On("GetReplicationControllers", namespace).Return([]v1.ReplicationController{}, nil)
o.On("GetDeploymentConfigs", namespace).Return([]osappsv1.DeploymentConfig{}, nil)
o.On("GetStatefulSets", namespace).Return([]v1beta2.StatefulSet{}, nil)
o.On("GetStatefulSets", namespace).Return([]appsv1.StatefulSet{}, nil)
o.On("GetJobs", namespace).Return([]batch_v1.Job{}, nil)
o.On("GetCronJobs", namespace).Return([]batch_v1beta1.CronJob{}, nil)
}
@@ -45,10 +44,10 @@ func (o *K8SClientMock) MockEmptyWorkloads(namespace interface{}) {
// MockEmptyWorkload setup the current mock to return an empty workload for every type of workloads (deployment, dc, rs, jobs, etc.)
func (o *K8SClientMock) MockEmptyWorkload(namespace interface{}, workload interface{}) {
notfound := fmt.Errorf("not found")
o.On("GetDeployment", namespace, workload).Return(&v1beta1.Deployment{}, notfound)
o.On("GetStatefulSet", namespace, workload).Return(&v1beta2.StatefulSet{}, notfound)
o.On("GetDeployment", namespace, workload).Return(&appsv1.Deployment{}, notfound)
o.On("GetStatefulSet", namespace, workload).Return(&appsv1.StatefulSet{}, notfound)
o.On("GetDeploymentConfig", namespace, workload).Return(&osappsv1.DeploymentConfig{}, notfound)
o.On("GetReplicaSets", namespace).Return([]v1beta2.ReplicaSet{}, nil)
o.On("GetReplicaSets", namespace).Return([]appsv1.ReplicaSet{}, nil)
o.On("GetReplicationControllers", namespace).Return([]v1.ReplicationController{}, nil)
o.On("GetJobs", namespace).Return([]batch_v1.Job{}, nil)
o.On("GetCronJobs", namespace).Return([]batch_v1beta1.CronJob{}, nil)
@@ -79,14 +78,14 @@ func (o *K8SClientMock) GetCronJobs(namespace string) ([]batch_v1beta1.CronJob,
return args.Get(0).([]batch_v1beta1.CronJob), args.Error(1)
}
func (o *K8SClientMock) GetDeployment(namespace string, deploymentName string) (*v1beta1.Deployment, error) {
func (o *K8SClientMock) GetDeployment(namespace string, deploymentName string) (*appsv1.Deployment, error) {
args := o.Called(namespace, deploymentName)
return args.Get(0).(*v1beta1.Deployment), args.Error(1)
return args.Get(0).(*appsv1.Deployment), args.Error(1)
}
func (o *K8SClientMock) GetDeployments(namespace string) ([]v1beta1.Deployment, error) {
func (o *K8SClientMock) GetDeployments(namespace string) ([]appsv1.Deployment, error) {
args := o.Called(namespace)
return args.Get(0).([]v1beta1.Deployment), args.Error(1)
return args.Get(0).([]appsv1.Deployment), args.Error(1)
}
func (o *K8SClientMock) GetDeploymentConfig(namespace string, deploymentName string) (*osappsv1.DeploymentConfig, error) {
@@ -194,9 +193,9 @@ func (o *K8SClientMock) GetReplicationControllers(namespace string) ([]v1.Replic
return args.Get(0).([]v1.ReplicationController), args.Error(1)
}
func (o *K8SClientMock) GetReplicaSets(namespace string) ([]v1beta2.ReplicaSet, error) {
func (o *K8SClientMock) GetReplicaSets(namespace string) ([]appsv1.ReplicaSet, error) {
args := o.Called(namespace)
return args.Get(0).([]v1beta2.ReplicaSet), args.Error(1)
return args.Get(0).([]appsv1.ReplicaSet), args.Error(1)
}
func (o *K8SClientMock) GetSelfSubjectAccessReview(namespace, api, resourceType string, verbs []string) ([]*auth_v1.SelfSubjectAccessReview, error) {
@@ -224,14 +223,14 @@ func (o *K8SClientMock) GetServiceEntry(namespace string, serviceEntryName strin
return args.Get(0).(kubernetes.IstioObject), args.Error(1)
}
func (o *K8SClientMock) GetStatefulSet(namespace string, statefulsetName string) (*v1beta2.StatefulSet, error) {
func (o *K8SClientMock) GetStatefulSet(namespace string, statefulsetName string) (*appsv1.StatefulSet, error) {
args := o.Called(namespace, statefulsetName)
return args.Get(0).(*v1beta2.StatefulSet), args.Error(1)
return args.Get(0).(*appsv1.StatefulSet), args.Error(1)
}
func (o *K8SClientMock) GetStatefulSets(namespace string) ([]v1beta2.StatefulSet, error) {
func (o *K8SClientMock) GetStatefulSets(namespace string) ([]appsv1.StatefulSet, error) {
args := o.Called(namespace)
return args.Get(0).([]v1beta2.StatefulSet), args.Error(1)
return args.Get(0).([]appsv1.StatefulSet), args.Error(1)
}
func (o *K8SClientMock) GetTemplate(namespace, templateType, templateName string) (kubernetes.IstioObject, error) {

View File

@@ -2,8 +2,7 @@ package models
import (
osappsv1 "github.com/openshift/api/apps/v1"
"k8s.io/api/apps/v1beta1"
"k8s.io/api/apps/v1beta2"
appsv1 "k8s.io/api/apps/v1"
batch_v1 "k8s.io/api/batch/v1"
batch_v1beta1 "k8s.io/api/batch/v1beta1"
"k8s.io/api/core/v1"
@@ -125,7 +124,7 @@ func (workload *WorkloadListItem) ParseWorkload(w *Workload) {
_, workload.VersionLabel = w.Labels[conf.IstioLabels.VersionLabelName]
}
func (workload *Workload) ParseDeployment(d *v1beta1.Deployment) {
func (workload *Workload) ParseDeployment(d *appsv1.Deployment) {
conf := config.Get()
workload.Name = d.Name
workload.Type = "Deployment"
@@ -144,7 +143,7 @@ func (workload *Workload) ParseDeployment(d *v1beta1.Deployment) {
workload.UnavailableReplicas = workload.Replicas - workload.AvailableReplicas
}
func (workload *Workload) ParseReplicaSet(r *v1beta2.ReplicaSet) {
func (workload *Workload) ParseReplicaSet(r *appsv1.ReplicaSet) {
conf := config.Get()
workload.Name = r.Name
workload.Type = "ReplicaSet"
@@ -195,7 +194,7 @@ func (workload *Workload) ParseDeploymentConfig(dc *osappsv1.DeploymentConfig) {
workload.UnavailableReplicas = workload.Replicas - workload.AvailableReplicas
}
func (workload *Workload) ParseStatefulSet(s *v1beta2.StatefulSet) {
func (workload *Workload) ParseStatefulSet(s *appsv1.StatefulSet) {
conf := config.Get()
workload.Name = s.Name
workload.Type = "StatefulSet"

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@@ -1,180 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 v1beta1
import (
"github.com/kubernetes-sigs/application/pkg/component"
cr "github.com/kubernetes-sigs/application/pkg/customresource"
"github.com/kubernetes-sigs/application/pkg/finalizer"
"github.com/kubernetes-sigs/application/pkg/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"strings"
)
// Mutate - mutate expected
func (a *Application) Mutate(rsrc interface{}, labels map[string]string, status interface{}, expected, dependent, observed *resource.ObjectBag) (*resource.ObjectBag, error) {
exp := resource.ObjectBag{}
for _, o := range observed.Items() {
o.Lifecycle = resource.LifecycleManaged
exp.Add(o)
}
return &exp, nil
}
// Finalize - execute finalizers
func (a *Application) Finalize(rsrc, sts interface{}, observed *resource.ObjectBag) error {
finalizer.Remove(a, finalizer.Cleanup)
return nil
}
//DependentResources - returns dependent rsrc
func (a *Application) DependentResources(rsrc interface{}) *resource.ObjectBag {
return &resource.ObjectBag{}
}
// ExpectedResources returns the list of resource/name for those resources created by
// the operator for this spec and those resources referenced by this operator.
// Mark resources as owned, referred
func (a *Application) ExpectedResources(rsrc interface{}, rsrclabels map[string]string, dependent, aggregated *resource.ObjectBag) (*resource.ObjectBag, error) {
return &resource.ObjectBag{}, nil
}
// GKVersions returns the gvks for the given gk
func GKVersions(s *runtime.Scheme, mgk metav1.GroupKind) []schema.GroupVersionKind {
gvks := []schema.GroupVersionKind{}
gk := schema.GroupKind{Group: mgk.Group, Kind: mgk.Kind}
for gvk := range s.AllKnownTypes() {
if gk != gvk.GroupKind() {
continue
}
gvks = append(gvks, gvk)
}
return gvks
}
// Observables - return selectors
func (a *Application) Observables(scheme *runtime.Scheme, rsrc interface{}, rsrclabels map[string]string, expected *resource.ObjectBag) []resource.Observable {
var observables []resource.Observable
if a.Spec.Selector == nil || a.Spec.Selector.MatchLabels == nil {
return observables
}
for _, gk := range a.Spec.ComponentGroupKinds {
listGK := gk
if !strings.HasSuffix(listGK.Kind, "List") {
listGK.Kind = listGK.Kind + "List"
}
for _, gvk := range GKVersions(scheme, listGK) {
ol, err := scheme.New(gvk)
if err == nil {
observable := resource.Observable{
ObjList: ol.(metav1.ListInterface),
Labels: a.Spec.Selector.MatchLabels,
Namespace: rsrc.(metav1.Object).GetNamespace(),
}
observables = append(observables, observable)
}
}
}
return observables
}
// Differs returns true if the resource needs to be updated
func (a *Application) Differs(expected metav1.Object, observed metav1.Object) bool {
return false
}
// UpdateComponentStatus use reconciled objects to update component status
func (a *Application) UpdateComponentStatus(rsrci, statusi interface{}, reconciled *resource.ObjectBag, err error) {
if a != nil {
stts := statusi.(*ApplicationStatus)
stts.UpdateStatus(reconciled.Objs(), err)
}
}
// ApplyDefaults default app crd
func (a *Application) ApplyDefaults() {
return
}
// UpdateRsrcStatus records status or error in status
func (a *Application) UpdateRsrcStatus(status interface{}, err error) bool {
appstatus := status.(*ApplicationStatus)
if status != nil {
a.Status = *appstatus
}
if err != nil {
a.Status.SetError("ErrorSeen", err.Error())
} else {
a.Status.ClearError()
}
return true
}
// Validate the Application
func (a *Application) Validate() error {
return nil
}
// Components returns components for this resource
func (a *Application) Components() []component.Component {
c := []component.Component{}
c = append(c, component.Component{
Handle: a,
Name: "app",
CR: a,
OwnerRef: a.OwnerRef(),
})
return c
}
// OwnerRef returns owner ref object with the component's resource as owner
func (a *Application) OwnerRef() *metav1.OwnerReference {
if !a.Spec.AddOwnerRef {
return nil
}
isController := false
gvk := schema.GroupVersionKind{
Group: SchemeGroupVersion.Group,
Version: SchemeGroupVersion.Version,
Kind: "Application",
}
ref := metav1.NewControllerRef(a, gvk)
ref.Controller = &isController
return ref
}
// NewRsrc - return a new resource object
func (a *Application) NewRsrc() cr.Handle {
return &Application{}
}
// NewStatus - return a resource status object
func (a *Application) NewStatus() interface{} {
s := a.Status.DeepCopy()
s.ComponentList = ComponentList{}
return s
}
// StatusDiffers returns True if there is a change in status
func (a *Application) StatusDiffers(new ApplicationStatus) bool {
return true
}

View File

@@ -1,168 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 v1beta1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (m *ApplicationStatus) addCondition(ctype ConditionType, status corev1.ConditionStatus, reason, message string) {
now := metav1.Now()
c := &Condition{
Type: ctype,
LastUpdateTime: now,
LastTransitionTime: now,
Status: status,
Reason: reason,
Message: message,
}
m.Conditions = append(m.Conditions, *c)
}
// setConditionValue updates or creates a new condition
func (m *ApplicationStatus) setConditionValue(ctype ConditionType, status corev1.ConditionStatus, reason, message string) {
var c *Condition
for i := range m.Conditions {
if m.Conditions[i].Type == ctype {
c = &m.Conditions[i]
}
}
if c == nil {
m.addCondition(ctype, status, reason, message)
} else {
// check message ?
if c.Status == status && c.Reason == reason && c.Message == message {
return
}
now := metav1.Now()
c.LastUpdateTime = now
if c.Status != status {
c.LastTransitionTime = now
}
c.Status = status
c.Reason = reason
c.Message = message
}
}
// RemoveCondition removes the condition with the provided type.
func (m *ApplicationStatus) RemoveCondition(ctype ConditionType) {
for i, c := range m.Conditions {
if c.Type == ctype {
m.Conditions[i] = m.Conditions[len(m.Conditions)-1]
m.Conditions = m.Conditions[:len(m.Conditions)-1]
break
}
}
}
// GetCondition get existing condition
func (m *ApplicationStatus) GetCondition(ctype ConditionType) *Condition {
for i := range m.Conditions {
if m.Conditions[i].Type == ctype {
return &m.Conditions[i]
}
}
return nil
}
// IsConditionTrue - if condition is true
func (m *ApplicationStatus) IsConditionTrue(ctype ConditionType) bool {
if c := m.GetCondition(ctype); c != nil {
return c.Status == corev1.ConditionTrue
}
return false
}
// IsReady returns true if ready condition is set
func (m *ApplicationStatus) IsReady() bool { return m.IsConditionTrue(Ready) }
// IsNotReady returns true if ready condition is set
func (m *ApplicationStatus) IsNotReady() bool { return !m.IsConditionTrue(Ready) }
// ConditionReason - return condition reason
func (m *ApplicationStatus) ConditionReason(ctype ConditionType) string {
if c := m.GetCondition(ctype); c != nil {
return c.Reason
}
return ""
}
// Ready - shortcut to set ready contition to true
func (m *ApplicationStatus) Ready(reason, message string) {
m.SetCondition(Ready, reason, message)
}
// NotReady - shortcut to set ready contition to false
func (m *ApplicationStatus) NotReady(reason, message string) {
m.ClearCondition(Ready, reason, message)
}
// SetError - shortcut to set error condition
func (m *ApplicationStatus) SetError(reason, message string) {
m.SetCondition(Error, reason, message)
}
// ClearError - shortcut to set error condition
func (m *ApplicationStatus) ClearError() {
m.ClearCondition(Error, "NoError", "No error seen")
}
// Settled - shortcut to set Settled contition to true
func (m *ApplicationStatus) Settled(reason, message string) {
m.SetCondition(Settled, reason, message)
}
// NotSettled - shortcut to set Settled contition to false
func (m *ApplicationStatus) NotSettled(reason, message string) {
m.ClearCondition(Settled, reason, message)
}
// EnsureCondition useful for adding default conditions
func (m *ApplicationStatus) EnsureCondition(ctype ConditionType) {
if c := m.GetCondition(ctype); c != nil {
return
}
m.addCondition(ctype, corev1.ConditionUnknown, ReasonInit, "Not Observed")
}
// EnsureStandardConditions - helper to inject standard conditions
func (m *ApplicationStatus) EnsureStandardConditions() {
m.EnsureCondition(Ready)
m.EnsureCondition(Settled)
m.EnsureCondition(Error)
}
// ClearCondition updates or creates a new condition
func (m *ApplicationStatus) ClearCondition(ctype ConditionType, reason, message string) {
m.setConditionValue(ctype, corev1.ConditionFalse, reason, message)
}
// SetCondition updates or creates a new condition
func (m *ApplicationStatus) SetCondition(ctype ConditionType, reason, message string) {
m.setConditionValue(ctype, corev1.ConditionTrue, reason, message)
}
// RemoveAllConditions updates or creates a new condition
func (m *ApplicationStatus) RemoveAllConditions() {
m.Conditions = []Condition{}
}
// ClearAllConditions updates or creates a new condition
func (m *ApplicationStatus) ClearAllConditions() {
for i := range m.Conditions {
m.Conditions[i].Status = corev1.ConditionFalse
}
}

View File

@@ -1,23 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 v1beta1 contains API Schema definitions for the app v1beta1 API group
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=github.com/kubernetes-sigs/application/pkg/apis/app
// +k8s:defaulter-gen=TypeMeta
// +groupName=app.k8s.io
package v1beta1

View File

@@ -1,46 +0,0 @@
/*
Copyright 2018 The Kubernetes 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.
*/
// NOTE: Boilerplate only. Ignore this file.
// Package v1beta1 contains API Schema definitions for the app v1beta1 API group
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=github.com/kubernetes-sigs/application/pkg/apis/app
// +k8s:defaulter-gen=TypeMeta
// +groupName=app.k8s.io
package v1beta1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/runtime/scheme"
)
var (
// SchemeGroupVersion is group version used to register these objects
SchemeGroupVersion = schema.GroupVersion{Group: "app.k8s.io", Version: "v1beta1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
// AddToScheme is required by pkg/client/...
AddToScheme = SchemeBuilder.AddToScheme
)
// Resource is required by pkg/client/listers/...
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

View File

@@ -1,193 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 v1beta1
import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
policyv1 "k8s.io/api/policy/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// Constants defining labels
const (
StatusReady = "Ready"
StatusInProgress = "InProgress"
StatusDisabled = "Disabled"
)
func (s *ObjectStatus) update(rsrc metav1.Object) {
ro := rsrc.(runtime.Object)
gvk := ro.GetObjectKind().GroupVersionKind()
s.Link = rsrc.GetSelfLink()
s.Name = rsrc.GetName()
s.Group = gvk.GroupVersion().String()
s.Kind = gvk.GroupKind().Kind
s.Status = StatusReady
}
// ResetComponentList - reset component list objects
func (m *ApplicationStatus) ResetComponentList() {
m.ComponentList.Objects = []ObjectStatus{}
}
// UpdateStatus the component status
func (m *ApplicationStatus) UpdateStatus(rsrcs []metav1.Object, err error) {
var ready = true
for _, r := range rsrcs {
os := ObjectStatus{}
os.update(r)
switch r.(type) {
case *appsv1.StatefulSet:
os.Status = stsStatus(r.(*appsv1.StatefulSet))
case *policyv1.PodDisruptionBudget:
os.Status = pdbStatus(r.(*policyv1.PodDisruptionBudget))
case *appsv1.Deployment:
os.Status = deploymentStatus(r.(*appsv1.Deployment))
case *appsv1.ReplicaSet:
os.Status = replicasetStatus(r.(*appsv1.ReplicaSet))
case *appsv1.DaemonSet:
os.Status = daemonsetStatus(r.(*appsv1.DaemonSet))
case *corev1.Pod:
os.Status = podStatus(r.(*corev1.Pod))
case *corev1.Service:
os.Status = serviceStatus(r.(*corev1.Service))
case *corev1.PersistentVolumeClaim:
os.Status = pvcStatus(r.(*corev1.PersistentVolumeClaim))
//case *corev1.ReplicationController:
// Ingress
default:
os.Status = StatusReady
}
m.ComponentList.Objects = append(m.ComponentList.Objects, os)
}
for _, os := range m.ComponentList.Objects {
if os.Status != StatusReady {
ready = false
}
}
if ready {
m.Ready("ComponentsReady", "all components ready")
} else {
m.NotReady("ComponentsNotReady", "some components not ready")
}
if err != nil {
m.SetCondition(Error, "ErrorSeen", err.Error())
}
}
// Resource specific logic -----------------------------------
// Statefulset
func stsStatus(rsrc *appsv1.StatefulSet) string {
if rsrc.Status.ReadyReplicas == *rsrc.Spec.Replicas && rsrc.Status.CurrentReplicas == *rsrc.Spec.Replicas {
return StatusReady
}
return StatusInProgress
}
// Deployment
func deploymentStatus(rsrc *appsv1.Deployment) string {
status := StatusInProgress
progress := true
available := true
for _, c := range rsrc.Status.Conditions {
switch c.Type {
case appsv1.DeploymentProgressing:
// https://github.com/kubernetes/kubernetes/blob/a3ccea9d8743f2ff82e41b6c2af6dc2c41dc7b10/pkg/controller/deployment/progress.go#L52
if c.Status != corev1.ConditionTrue || c.Reason != "NewReplicaSetAvailable" {
progress = false
}
case appsv1.DeploymentAvailable:
if c.Status == corev1.ConditionFalse {
available = false
}
}
}
if progress && available {
status = StatusReady
}
return status
}
// Replicaset
func replicasetStatus(rsrc *appsv1.ReplicaSet) string {
status := StatusInProgress
failure := false
for _, c := range rsrc.Status.Conditions {
switch c.Type {
// https://github.com/kubernetes/kubernetes/blob/a3ccea9d8743f2ff82e41b6c2af6dc2c41dc7b10/pkg/controller/replicaset/replica_set_utils.go
case appsv1.ReplicaSetReplicaFailure:
if c.Status == corev1.ConditionTrue {
failure = true
break
}
}
}
if !failure && rsrc.Status.ReadyReplicas == rsrc.Status.Replicas && rsrc.Status.Replicas == rsrc.Status.AvailableReplicas {
status = StatusReady
}
return status
}
// Daemonset
func daemonsetStatus(rsrc *appsv1.DaemonSet) string {
status := StatusInProgress
if rsrc.Status.DesiredNumberScheduled == rsrc.Status.NumberAvailable && rsrc.Status.DesiredNumberScheduled == rsrc.Status.NumberReady {
status = StatusReady
}
return status
}
// PVC
func pvcStatus(rsrc *corev1.PersistentVolumeClaim) string {
status := StatusInProgress
if rsrc.Status.Phase == corev1.ClaimBound {
status = StatusReady
}
return status
}
// Service
func serviceStatus(rsrc *corev1.Service) string {
status := StatusReady
return status
}
// Pod
func podStatus(rsrc *corev1.Pod) string {
status := StatusInProgress
for i := range rsrc.Status.Conditions {
if rsrc.Status.Conditions[i].Type == corev1.PodReady &&
rsrc.Status.Conditions[i].Status == corev1.ConditionTrue {
status = StatusReady
break
}
}
return status
}
// PodDisruptionBudget
func pdbStatus(rsrc *policyv1.PodDisruptionBudget) string {
if rsrc.Status.CurrentHealthy >= rsrc.Status.DesiredHealthy {
return StatusReady
}
return StatusInProgress
}

View File

@@ -1,52 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 component
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"reflect"
"strings"
)
// Constants defining labels
const (
LabelCR = "custom-resource"
LabelCRName = "custom-resource-name"
LabelCRNamespace = "custom-resource-namespace"
LabelComponent = "component"
)
// Labels return
func Labels(cr metav1.Object, component string) map[string]string {
return map[string]string{
LabelCR: strings.Trim(reflect.TypeOf(cr).String(), "*"),
LabelCRName: cr.GetName(),
LabelCRNamespace: cr.GetNamespace(),
LabelComponent: component,
}
}
// Labels return the common labels for a resource
func (c *Component) Labels() map[string]string {
return Labels(c.CR, c.Name)
}
// Merge is used to merge multiple maps into the target map
func (out KVMap) Merge(kvmaps ...KVMap) {
for _, kvmap := range kvmaps {
for k, v := range kvmap {
out[k] = v
}
}
}

View File

@@ -1,31 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 component
import (
"github.com/kubernetes-sigs/application/pkg/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
// Handle is an interface for operating on logical Components of a CR
type Handle interface {
DependentResources(rsrc interface{}) *resource.ObjectBag
ExpectedResources(rsrc interface{}, labels map[string]string, dependent, aggregated *resource.ObjectBag) (*resource.ObjectBag, error)
Observables(scheme *runtime.Scheme, rsrc interface{}, labels map[string]string, expected *resource.ObjectBag) []resource.Observable
Mutate(rsrc interface{}, rsrclabels map[string]string, status interface{}, expected, dependent, observed *resource.ObjectBag) (*resource.ObjectBag, error)
Differs(expected metav1.Object, observed metav1.Object) bool
UpdateComponentStatus(rsrc, status interface{}, reconciled *resource.ObjectBag, err error)
Finalize(rsrc, status interface{}, observed *resource.ObjectBag) error
}

View File

@@ -1,35 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 component
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Common const definitions
const (
LifecycleManaged = "managed"
LifecycleReferred = "referred"
)
// Component represents a logical collection of resources
type Component struct {
Handle
Name string
CR metav1.Object
OwnerRef *metav1.OwnerReference
}
// KVMap is a map[string]string
type KVMap map[string]string

View File

@@ -1,31 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 customresource
import (
component "github.com/kubernetes-sigs/application/pkg/component"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"reflect"
"strings"
)
// Labels return custom resource label
func (hv *HandleValue) Labels() map[string]string {
c := hv.Handle.(metav1.Object)
return map[string]string{
component.LabelCR: strings.Trim(reflect.TypeOf(c).String(), "*"),
component.LabelCRName: c.GetName(),
component.LabelCRNamespace: c.GetNamespace(),
}
}

View File

@@ -1,18 +0,0 @@
/*
Copyright 2018 The Kubernetes 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 customresource contains component definition
package customresource

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