refactor project

This commit is contained in:
Jeff
2019-03-23 00:51:03 +08:00
parent 870fc29309
commit 232b4efaad
2635 changed files with 0 additions and 918716 deletions

View File

@@ -1 +0,0 @@
tmp/

2
.env
View File

@@ -1,2 +0,0 @@
DATA_PATH=./tmp
KUBESPHERE_LOG_LEVEL=debug

2
.gitattributes vendored
View File

@@ -1,2 +0,0 @@
pkg/cmd/api/spec/api.swagger.json linguist-generated=true
pkg/cmd/api/spec/static.go linguist-generated=true

View File

@@ -1,32 +0,0 @@
sudo: required
services:
- docker
language: go
go:
- 1.10
- tip
go_import_path: kubesphere.io/kubesphere
before_install:
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
- sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
- sudo apt-get update
- sudo apt-get -y install docker-ce
- dep ensure -v
before_script:
- docker --version
script:
- make fmt-check && make build
deploy:
provider: script
script: bash install/scripts/docker_push
on:
branch: master

View File

@@ -1,17 +0,0 @@
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
FROM kubesphere/kubesphere-builder as builder
WORKDIR /go/src/kubesphere.io/kubesphere/
COPY . .
RUN go generate kubesphere.io/kubesphere/pkg/version && \
go install kubesphere.io/kubesphere/cmd/...
FROM alpine:3.6
RUN apk add --update ca-certificates && update-ca-certificates
COPY --from=builder /go/bin/* /usr/local/bin/
CMD ["sh"]

View File

@@ -1,10 +0,0 @@
FROM alpine:3.6
RUN apk add --update ca-certificates \
&& update-ca-certificates \
&& mkdir -p /etc/kubesphere/ingress-controller
COPY ./bin/* /usr/local/bin/
COPY ./install/ingress-controller /etc/kubesphere/ingress-controller
COPY ./install/swagger-ui /usr/lib/kubesphere/swagger-ui
CMD ["sh"]

812
Gopkg.lock generated
View File

@@ -1,812 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:bf42be3cb1519bf8018dfd99720b1005ee028d947124cab3ccf965da59381df6"
name = "github.com/Microsoft/go-winio"
packages = ["."]
pruneopts = "UT"
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
version = "v0.4.7"
[[projects]]
digest = "1:d1665c44bd5db19aaee18d1b6233c99b0b9a986e8bccb24ef54747547a48027f"
name = "github.com/PuerkitoBio/purell"
packages = ["."]
pruneopts = "UT"
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:c739832d67eb1e9cc478a19cc1a1ccd78df0397bf8a32978b759152e205f644b"
name = "github.com/PuerkitoBio/urlesc"
packages = ["."]
pruneopts = "UT"
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]]
digest = "1:9e9193aa51197513b3abcb108970d831fbcf40ef96aa845c4f03276e1fa316d2"
name = "github.com/Sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
version = "v1.0.5"
[[projects]]
digest = "1:e49fec8537ec021eeb41d394684bce0365c8db14c8099215f7b509189ddb5852"
name = "github.com/antonholmquist/jason"
packages = ["."]
pruneopts = "UT"
revision = "c23cef7eaa75a6a5b8810120e167bd590d8fd2ab"
version = "v1.0.0"
[[projects]]
digest = "1:4fe4dc4ce7ebb5a4b0544c5b411196d23e221800d279a207d76f02812f756c3d"
name = "github.com/coreos/etcd"
packages = [
"auth/authpb",
"clientv3",
"etcdserver/api/v3rpc/rpctypes",
"etcdserver/etcdserverpb",
"mvcc/mvccpb",
"pkg/tlsutil",
"pkg/transport",
"pkg/types",
]
pruneopts = "UT"
revision = "33245c6b5b49130ca99280408fadfab01aac0e48"
version = "v3.3.8"
[[projects]]
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = "UT"
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:4189ee6a3844f555124d9d2656fe7af02fca961c2a9bad9074789df13a0c62e0"
name = "github.com/docker/distribution"
packages = [
"digestset",
"reference",
]
pruneopts = "UT"
revision = "749f6afb4572201e3c37325d0ffedb6f32be8950"
[[projects]]
digest = "1:ec821dda59d7dd340498d74f798aa218b2c782bba54a690e866dc4f520d900d5"
name = "github.com/docker/docker"
packages = [
"api",
"api/types",
"api/types/blkiodev",
"api/types/container",
"api/types/events",
"api/types/filters",
"api/types/image",
"api/types/mount",
"api/types/network",
"api/types/registry",
"api/types/strslice",
"api/types/swarm",
"api/types/time",
"api/types/versions",
"api/types/volume",
"client",
"pkg/ioutils",
"pkg/longpath",
"pkg/system",
"pkg/tlsconfig",
]
pruneopts = "UT"
revision = "90d35abf7b3535c1c319c872900fbd76374e521c"
version = "v17.05.0-ce-rc3"
[[projects]]
branch = "master"
digest = "1:811c86996b1ca46729bad2724d4499014c4b9effd05ef8c71b852aad90deb0ce"
name = "github.com/docker/go-connections"
packages = [
"nat",
"sockets",
"tlsconfig",
]
pruneopts = "UT"
revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55"
[[projects]]
digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18"
name = "github.com/docker/go-units"
packages = ["."]
pruneopts = "UT"
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
version = "v0.3.3"
[[projects]]
branch = "master"
digest = "1:4841e14252a2cecf11840bd05230412ad469709bbacfc12467e2ce5ad07f339b"
name = "github.com/docker/libtrust"
packages = ["."]
pruneopts = "UT"
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
[[projects]]
branch = "master"
digest = "1:dbb3d1675f5beeb37de6e9b95cc460158ff212902a916e67688b01e0660f41bd"
name = "github.com/docker/spdystream"
packages = [
".",
"spdy",
]
pruneopts = "UT"
revision = "bc6354cbbc295e925e4c611ffe90c1f287ee54db"
[[projects]]
digest = "1:798072bbab2506719d8292cd9b5840a0b5babe0348393bd7097d8fb25ecf0b82"
name = "github.com/emicklei/go-restful"
packages = [
".",
"log",
]
pruneopts = "UT"
revision = "3658237ded108b4134956c1b3050349d93e7b895"
version = "v2.7.1"
[[projects]]
digest = "1:e2300c0b15e8b7cb908da64f50e748725c739bcf042a19ceb971680763339888"
name = "github.com/emicklei/go-restful-openapi"
packages = ["."]
pruneopts = "UT"
revision = "51bf251d405ad1e23511fef0a2dbe40bc70ce2c6"
version = "v0.11.0"
[[projects]]
digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda"
name = "github.com/ghodss/yaml"
packages = ["."]
pruneopts = "UT"
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:2997679181d901ac8aaf4330d11138ecf3974c6d3334995ff36f20cbd597daf8"
name = "github.com/go-openapi/jsonpointer"
packages = ["."]
pruneopts = "UT"
revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2"
[[projects]]
branch = "master"
digest = "1:1ae3f233d75a731b164ca9feafd8ed646cbedf1784095876ed6988ce8aa88b1f"
name = "github.com/go-openapi/jsonreference"
packages = ["."]
pruneopts = "UT"
revision = "3fb327e6747da3043567ee86abd02bb6376b6be2"
[[projects]]
branch = "master"
digest = "1:cbd9c1cc4ce36075f4ebf0e0525e6cda8597daac1a5eb5f7f88480a3c00e7319"
name = "github.com/go-openapi/spec"
packages = ["."]
pruneopts = "UT"
revision = "bce47c9386f9ecd6b86f450478a80103c3fe1402"
[[projects]]
branch = "master"
digest = "1:731022b436cdb9b4b2a53be2ead693467a1474b8b873d4f90cb424fffdc3d0ff"
name = "github.com/go-openapi/swag"
packages = ["."]
pruneopts = "UT"
revision = "2b0bd4f193d011c203529df626a65d63cb8a79e8"
[[projects]]
digest = "1:adea5a94903eb4384abef30f3d878dc9ff6b6b5b0722da25b82e5169216dfb61"
name = "github.com/go-sql-driver/mysql"
packages = ["."]
pruneopts = "UT"
revision = "d523deb1b23d913de5bdada721a6071e71283618"
version = "v1.4.0"
[[projects]]
digest = "1:cd559bf134bbedd0dfd5db4d988c88d8f96674fa3f2af0cb5b0dcd5fc0a0a019"
name = "github.com/gogo/protobuf"
packages = [
"gogoproto",
"proto",
"protoc-gen-gogo/descriptor",
"sortkeys",
]
pruneopts = "UT"
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467"
name = "github.com/golang/glog"
packages = ["."]
pruneopts = "UT"
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
digest = "1:17fe264ee908afc795734e8c4e63db2accabaf57326dbf21763a7d6b86096260"
name = "github.com/golang/protobuf"
packages = [
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp",
]
pruneopts = "UT"
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb"
name = "github.com/google/gofuzz"
packages = ["."]
pruneopts = "UT"
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]]
digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21"
name = "github.com/googleapis/gnostic"
packages = [
"OpenAPIv2",
"compiler",
"extensions",
]
pruneopts = "UT"
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
version = "v0.2.0"
[[projects]]
digest = "1:43dd08a10854b2056e615d1b1d22ac94559d822e1f8b6fcc92c1a1057e85188e"
name = "github.com/gorilla/websocket"
packages = ["."]
pruneopts = "UT"
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
branch = "master"
digest = "1:cf296baa185baae04a9a7004efee8511d08e2f5f51d4cbe5375da89722d681db"
name = "github.com/hashicorp/golang-lru"
packages = [
".",
"simplelru",
]
pruneopts = "UT"
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
[[projects]]
branch = "master"
digest = "1:0778dc7fce1b4669a8bfa7ae506ec1f595b6ab0f8989c1c0d22a8ca1144e9972"
name = "github.com/howeyc/gopass"
packages = ["."]
pruneopts = "UT"
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
[[projects]]
digest = "1:3e260afa138eab6492b531a3b3d10ab4cb70512d423faa78b8949dec76e66a21"
name = "github.com/imdario/mergo"
packages = ["."]
pruneopts = "UT"
revision = "9316a62528ac99aaecb4e47eadd6dc8aa6533d58"
version = "v0.3.5"
[[projects]]
digest = "1:235ae01f32fb5f12c5f6d2e0e05ab48e651ab31c126e45a4efc4f510810941ac"
name = "github.com/jinzhu/gorm"
packages = ["."]
pruneopts = "UT"
revision = "6ed508ec6a4ecb3531899a69cbc746ccf65a4166"
version = "v1.9.1"
[[projects]]
branch = "master"
digest = "1:fd97437fbb6b7dce04132cf06775bd258cce305c44add58eb55ca86c6c325160"
name = "github.com/jinzhu/inflection"
packages = ["."]
pruneopts = "UT"
revision = "04140366298a54a039076d798123ffa108fff46c"
[[projects]]
digest = "1:b1d4df033414c1a0d85fa7037b9aaf03746314811c860a95ea2d5fd481cd6c35"
name = "github.com/json-iterator/go"
packages = ["."]
pruneopts = "UT"
revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4"
version = "1.1.3"
[[projects]]
branch = "master"
digest = "1:ada518b8c338e10e0afa443d84671476d3bd1d926e13713938088e8ddbee1a3e"
name = "github.com/mailru/easyjson"
packages = [
"buffer",
"jlexer",
"jwriter",
]
pruneopts = "UT"
revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485"
[[projects]]
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
name = "github.com/modern-go/concurrent"
packages = ["."]
pruneopts = "UT"
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
version = "1.0.3"
[[projects]]
digest = "1:d711dfcf661439f1ef0b202a02e8a1ff4deac48f26f34253520dcdbecbd7c5f1"
name = "github.com/modern-go/reflect2"
packages = ["."]
pruneopts = "UT"
revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f"
version = "1.0.0"
[[projects]]
digest = "1:ee4d4af67d93cc7644157882329023ce9a7bcfce956a079069a9405521c7cc8d"
name = "github.com/opencontainers/go-digest"
packages = ["."]
pruneopts = "UT"
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
version = "v1.0.0-rc1"
[[projects]]
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
name = "github.com/pkg/errors"
packages = ["."]
pruneopts = "UT"
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
digest = "1:9424f440bba8f7508b69414634aef3b2b3a877e522d8a4624692412805407bb7"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "UT"
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
version = "v1.0.1"
[[projects]]
branch = "master"
digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
pruneopts = "UT"
revision = "7f39a6fea4fe9364fb61e1def6a268a51b4f3a06"
[[projects]]
branch = "master"
digest = "1:bae20a4ea45ad83eb54271a18c820a4ca7c03880aa20d964e2d5bb1d57b1a41a"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/socks",
"internal/timeseries",
"proxy",
"trace",
]
pruneopts = "UT"
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
[[projects]]
branch = "master"
digest = "1:a17927b3d78603ae6691d5bf8d3d91467a6edd4ca43c9509347e016a54477f96"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "UT"
revision = "fc8bd948cf46f9c7af0f07d34151ce25fe90e477"
[[projects]]
digest = "1:0c56024909189aee3364b7f21a95a27459f718aa7c199a5c111c36cfffd9eaef"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
"width",
]
pruneopts = "UT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
digest = "1:c9e7a4b4d47c0ed205d257648b0e5b0440880cb728506e318f8ac7cd36270bc4"
name = "golang.org/x/time"
packages = ["rate"]
pruneopts = "UT"
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
[[projects]]
digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3"
name = "google.golang.org/appengine"
packages = ["cloudsql"]
pruneopts = "UT"
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:601e63e7d4577f907118bec825902505291918859d223bce015539e79f1160e3"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
pruneopts = "UT"
revision = "32ee49c4dd805befd833990acba36cb75042378c"
[[projects]]
digest = "1:3a98314fd2e43bbd905b33125dad80b10111ba6e5e541db8ed2a953fe01fbb31"
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"balancer/base",
"balancer/roundrobin",
"codes",
"connectivity",
"credentials",
"encoding",
"encoding/proto",
"grpclog",
"health/grpc_health_v1",
"internal",
"internal/backoff",
"internal/channelz",
"internal/grpcrand",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"resolver/dns",
"resolver/passthrough",
"stats",
"status",
"tap",
"transport",
]
pruneopts = "UT"
revision = "168a6198bcb0ef175f7dacec0b8691fc141dc9b8"
version = "v1.13.0"
[[projects]]
digest = "1:7a23929a5a0d4266c8f5444dae1e7594dbb0cae1c3091834119b162f81e229ff"
name = "gopkg.in/igm/sockjs-go.v2"
packages = ["sockjs"]
pruneopts = "UT"
revision = "d276e9ffe5cc5c271b81198cc77a2adf6c4482d2"
version = "v2.0.0"
[[projects]]
digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a"
name = "gopkg.in/inf.v0"
packages = ["."]
pruneopts = "UT"
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
version = "v0.9.1"
[[projects]]
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "UT"
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[[projects]]
digest = "1:cae8f1d1d786aa486a7ed236a8c1f099b3b44697ec6bbb5951d7e9bdb53a5125"
name = "k8s.io/api"
packages = [
"admissionregistration/v1alpha1",
"admissionregistration/v1beta1",
"apps/v1",
"apps/v1beta1",
"apps/v1beta2",
"authentication/v1",
"authentication/v1beta1",
"authorization/v1",
"authorization/v1beta1",
"autoscaling/v1",
"autoscaling/v2beta1",
"batch/v1",
"batch/v1beta1",
"batch/v2alpha1",
"certificates/v1beta1",
"core/v1",
"events/v1beta1",
"extensions/v1beta1",
"networking/v1",
"policy/v1beta1",
"rbac/v1",
"rbac/v1alpha1",
"rbac/v1beta1",
"scheduling/v1alpha1",
"settings/v1alpha1",
"storage/v1",
"storage/v1alpha1",
"storage/v1beta1",
]
pruneopts = "UT"
revision = "73d903622b7391f3312dcbac6483fed484e185f8"
version = "kubernetes-1.10.0"
[[projects]]
digest = "1:d0089d5f7811ded4279da7a8a66d2721488afec8208d86bdad3f4a20d3687e81"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/errors",
"pkg/api/meta",
"pkg/api/resource",
"pkg/apis/meta/internalversion",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
"pkg/apis/meta/v1beta1",
"pkg/conversion",
"pkg/conversion/queryparams",
"pkg/fields",
"pkg/labels",
"pkg/runtime",
"pkg/runtime/schema",
"pkg/runtime/serializer",
"pkg/runtime/serializer/json",
"pkg/runtime/serializer/protobuf",
"pkg/runtime/serializer/recognizer",
"pkg/runtime/serializer/streaming",
"pkg/runtime/serializer/versioning",
"pkg/selection",
"pkg/types",
"pkg/util/cache",
"pkg/util/clock",
"pkg/util/diff",
"pkg/util/errors",
"pkg/util/framer",
"pkg/util/httpstream",
"pkg/util/httpstream/spdy",
"pkg/util/intstr",
"pkg/util/json",
"pkg/util/net",
"pkg/util/rand",
"pkg/util/remotecommand",
"pkg/util/runtime",
"pkg/util/sets",
"pkg/util/validation",
"pkg/util/validation/field",
"pkg/util/wait",
"pkg/util/yaml",
"pkg/version",
"pkg/watch",
"third_party/forked/golang/netutil",
"third_party/forked/golang/reflect",
]
pruneopts = "UT"
revision = "302974c03f7e50f16561ba237db776ab93594ef6"
version = "kubernetes-1.10.0"
[[projects]]
digest = "1:7ee72261d268f7443085aad95b39fefc17fca826a9bfd8bd2d431bc081852a62"
name = "k8s.io/client-go"
packages = [
"discovery",
"informers",
"informers/admissionregistration",
"informers/admissionregistration/v1alpha1",
"informers/admissionregistration/v1beta1",
"informers/apps",
"informers/apps/v1",
"informers/apps/v1beta1",
"informers/apps/v1beta2",
"informers/autoscaling",
"informers/autoscaling/v1",
"informers/autoscaling/v2beta1",
"informers/batch",
"informers/batch/v1",
"informers/batch/v1beta1",
"informers/batch/v2alpha1",
"informers/certificates",
"informers/certificates/v1beta1",
"informers/core",
"informers/core/v1",
"informers/events",
"informers/events/v1beta1",
"informers/extensions",
"informers/extensions/v1beta1",
"informers/internalinterfaces",
"informers/networking",
"informers/networking/v1",
"informers/policy",
"informers/policy/v1beta1",
"informers/rbac",
"informers/rbac/v1",
"informers/rbac/v1alpha1",
"informers/rbac/v1beta1",
"informers/scheduling",
"informers/scheduling/v1alpha1",
"informers/settings",
"informers/settings/v1alpha1",
"informers/storage",
"informers/storage/v1",
"informers/storage/v1alpha1",
"informers/storage/v1beta1",
"kubernetes",
"kubernetes/scheme",
"kubernetes/typed/admissionregistration/v1alpha1",
"kubernetes/typed/admissionregistration/v1beta1",
"kubernetes/typed/apps/v1",
"kubernetes/typed/apps/v1beta1",
"kubernetes/typed/apps/v1beta2",
"kubernetes/typed/authentication/v1",
"kubernetes/typed/authentication/v1beta1",
"kubernetes/typed/authorization/v1",
"kubernetes/typed/authorization/v1beta1",
"kubernetes/typed/autoscaling/v1",
"kubernetes/typed/autoscaling/v2beta1",
"kubernetes/typed/batch/v1",
"kubernetes/typed/batch/v1beta1",
"kubernetes/typed/batch/v2alpha1",
"kubernetes/typed/certificates/v1beta1",
"kubernetes/typed/core/v1",
"kubernetes/typed/events/v1beta1",
"kubernetes/typed/extensions/v1beta1",
"kubernetes/typed/networking/v1",
"kubernetes/typed/policy/v1beta1",
"kubernetes/typed/rbac/v1",
"kubernetes/typed/rbac/v1alpha1",
"kubernetes/typed/rbac/v1beta1",
"kubernetes/typed/scheduling/v1alpha1",
"kubernetes/typed/settings/v1alpha1",
"kubernetes/typed/storage/v1",
"kubernetes/typed/storage/v1alpha1",
"kubernetes/typed/storage/v1beta1",
"listers/admissionregistration/v1alpha1",
"listers/admissionregistration/v1beta1",
"listers/apps/v1",
"listers/apps/v1beta1",
"listers/apps/v1beta2",
"listers/autoscaling/v1",
"listers/autoscaling/v2beta1",
"listers/batch/v1",
"listers/batch/v1beta1",
"listers/batch/v2alpha1",
"listers/certificates/v1beta1",
"listers/core/v1",
"listers/events/v1beta1",
"listers/extensions/v1beta1",
"listers/networking/v1",
"listers/policy/v1beta1",
"listers/rbac/v1",
"listers/rbac/v1alpha1",
"listers/rbac/v1beta1",
"listers/scheduling/v1alpha1",
"listers/settings/v1alpha1",
"listers/storage/v1",
"listers/storage/v1alpha1",
"listers/storage/v1beta1",
"pkg/apis/clientauthentication",
"pkg/apis/clientauthentication/v1alpha1",
"pkg/version",
"plugin/pkg/client/auth/exec",
"rest",
"rest/watch",
"tools/auth",
"tools/cache",
"tools/clientcmd",
"tools/clientcmd/api",
"tools/clientcmd/api/latest",
"tools/clientcmd/api/v1",
"tools/metrics",
"tools/pager",
"tools/reference",
"tools/remotecommand",
"transport",
"transport/spdy",
"util/buffer",
"util/cert",
"util/exec",
"util/flowcontrol",
"util/homedir",
"util/integer",
"util/retry",
]
pruneopts = "UT"
revision = "23781f4d6632d88e869066eaebb743857aa1ef9b"
version = "v7.0.0"
[[projects]]
digest = "1:2bdbea32607f4effd9e91dadd90baab1ecf224839b613bcaa8f50db5a5f133f5"
name = "k8s.io/kubernetes"
packages = [
"pkg/apis/core",
"pkg/util/slice",
"pkg/util/version",
]
pruneopts = "UT"
revision = "5ca598b4ba5abb89bb773071ce452e33fb66339d"
version = "v1.10.4"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/antonholmquist/jason",
"github.com/coreos/etcd/clientv3",
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes",
"github.com/coreos/etcd/pkg/transport",
"github.com/docker/docker/api/types",
"github.com/docker/docker/client",
"github.com/emicklei/go-restful",
"github.com/emicklei/go-restful-openapi",
"github.com/go-openapi/spec",
"github.com/go-sql-driver/mysql",
"github.com/golang/glog",
"github.com/jinzhu/gorm",
"github.com/pkg/errors",
"github.com/spf13/pflag",
"gopkg.in/igm/sockjs-go.v2/sockjs",
"gopkg.in/yaml.v2",
"k8s.io/api/apps/v1",
"k8s.io/api/apps/v1beta2",
"k8s.io/api/autoscaling/v1",
"k8s.io/api/batch/v1",
"k8s.io/api/batch/v1beta1",
"k8s.io/api/core/v1",
"k8s.io/api/extensions/v1beta1",
"k8s.io/api/policy/v1beta1",
"k8s.io/api/rbac/v1",
"k8s.io/api/storage/v1",
"k8s.io/apimachinery/pkg/api/errors",
"k8s.io/apimachinery/pkg/api/resource",
"k8s.io/apimachinery/pkg/apis/meta/v1",
"k8s.io/apimachinery/pkg/labels",
"k8s.io/apimachinery/pkg/types",
"k8s.io/apimachinery/pkg/util/sets",
"k8s.io/apimachinery/pkg/util/wait",
"k8s.io/client-go/informers",
"k8s.io/client-go/kubernetes",
"k8s.io/client-go/kubernetes/scheme",
"k8s.io/client-go/listers/apps/v1",
"k8s.io/client-go/listers/batch/v1",
"k8s.io/client-go/listers/batch/v1beta1",
"k8s.io/client-go/listers/core/v1",
"k8s.io/client-go/listers/extensions/v1beta1",
"k8s.io/client-go/listers/rbac/v1",
"k8s.io/client-go/listers/storage/v1",
"k8s.io/client-go/rest",
"k8s.io/client-go/tools/cache",
"k8s.io/client-go/tools/clientcmd",
"k8s.io/client-go/tools/remotecommand",
"k8s.io/kubernetes/pkg/apis/core",
"k8s.io/kubernetes/pkg/util/slice",
"k8s.io/kubernetes/pkg/util/version",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,90 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/coreos/etcd"
version = "3.3.7"
[[constraint]]
name = "github.com/docker/docker"
version = "v17.05.0-ce"
[[constraint]]
name = "github.com/emicklei/go-restful"
version = "2.7.1"
[[constraint]]
branch = "master"
name = "github.com/golang/glog"
[[constraint]]
name = "github.com/spf13/pflag"
version = "1.0.1"
[[constraint]]
name = "gopkg.in/igm/sockjs-go.v2"
version = "2.0.0"
[[constraint]]
name = "gopkg.in/yaml.v2"
version = "2.2.1"
[[constraint]]
name = "k8s.io/api"
version = "kubernetes-1.10.0"
[[constraint]]
name = "k8s.io/apimachinery"
version = "kubernetes-1.10.0"
[[constraint]]
name = "k8s.io/client-go"
version = "7.0.0"
[[constraint]]
name = "k8s.io/kubernetes"
version = "1.10.4"
[prune]
go-tests = true
unused-packages = true
# To use reference package:
# vendor/github.com/docker/docker/client/container_commit.go:17: undefined: reference.ParseNormalizedNamed
# vendor/github.com/docker/docker/client/container_commit.go:25: undefined: reference.TagNameOnly
# vendor/github.com/docker/docker/client/container_commit.go:30: undefined: reference.FamiliarNam
[[override]]
name = "github.com/docker/distribution"
branch = "master"
# To use reference package:
# vendor/github.com/docker/docker/registry/registry.go:30: cannot call non-function tlsconfig.ServerDefault (type tls.Config)
# vendor/github.com/docker/docker/registry/registry.go:66: undefined: tlsconfig.SystemCertPool
# vendor/github.com/docker/docker/registry/registry.go:168: cannot call non-function tlsconfig.ServerDefault (type tls.Config)
# vendor/github.com/docker/docker/registry/service_v2.go:11: cannot call non-function tlsconfig.ServerDefault (type tls.Config)
[[override]]
name = "github.com/docker/go-connections"
branch = "master"

201
LICENSE
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.

106
Makefile
View File

@@ -1,106 +0,0 @@
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
TRAG.Org:=kubesphere
TRAG.Name:=ks-apiserver
TRAG.Gopkg:=kubesphere.io/kubesphere
TRAG.Version:=$(TRAG.Gopkg)/pkg/version
DOCKER_TAGS=latest
RUN_IN_DOCKER:=docker run -it --rm -v `pwd`:/go/src/$(TRAG.Gopkg) -v `pwd`/tmp/cache:/root/.cache/go-build -w /go/src/$(TRAG.Gopkg) -e GOBIN=/go/src/$(TRAG.Gopkg)/tmp/bin -e USER_ID=`id -u` -e GROUP_ID=`id -g` kubesphere/kubesphere-builder
GO_FMT:=goimports -l -w -e -local=kubesphere -srcdir=/go/src/$(TRAG.Gopkg)
GO_FILES:=./cmd ./pkg
define get_diff_files
$(eval DIFF_FILES=$(shell git diff --name-only --diff-filter=ad | grep -E "^(test|cmd|pkg)/.+\.go"))
endef
define get_build_flags
$(eval SHORT_VERSION=$(shell git describe --tags --always --dirty="-dev"))
$(eval SHA1_VERSION=$(shell git show --quiet --pretty=format:%H))
$(eval DATE=$(shell date +'%Y-%m-%dT%H:%M:%S'))
$(eval BUILD_FLAG= -X $(TRAG.Version).ShortVersion="$(SHORT_VERSION)" \
-X $(TRAG.Version).GitSha1Version="$(SHA1_VERSION)" \
-X $(TRAG.Version).BuildDate="$(DATE)")
endef
.PHONY: all
all: generate build
.PHONY: help
help:
# TODO: update help info to last version
@echo "TODO"
.PHONY: init-vendor
init-vendor:
@if [[ ! -f "$$(which govendor)" ]]; then \
go get -u github.com/kardianos/govendor; \
fi
govendor init
govendor add +external
@echo "init-vendor done"
.PHONY: update-vendor
update-vendor:
@if [[ ! -f "$$(which govendor)" ]]; then \
go get -u github.com/kardianos/govendor; \
fi
govendor update +external
govendor list
@echo "update-vendor done"
.PHONY: update-builder
update-builder:
docker pull kubesphere/kubesphere-builder
@echo "update-builder done"
.PHONY: generate-in-local
generate-in-local:
go generate ./pkg/version/
.PHONY: generate
generate:
$(RUN_IN_DOCKER) make generate-in-local
@echo "generate done"
.PHONY: fmt-all
fmt-all:
mkdir -p ./tmp/bin && cp -r ./install ./tmp/
$(RUN_IN_DOCKER) $(GO_FMT) $(GO_FILES)
@echo "fmt done"
.PHONY: fmt
fmt:
$(call get_diff_files)
$(if $(DIFF_FILES), \
$(RUN_IN_DOCKER) $(GO_FMT) ${DIFF_FILES}, \
$(info cannot find modified files from git) \
)
@echo "fmt done"
.PHONY: fmt-check
fmt-check: fmt-all
$(call get_diff_files)
$(if $(DIFF_FILES), \
exit 2 \
)
.PHONY: build
build: fmt
mkdir -p ./tmp/bin && cp -r ./install/ ./tmp/
$(call get_build_flags)
$(RUN_IN_DOCKER) time go install -ldflags '$(BUILD_FLAG)' $(TRAG.Gopkg)/cmd/...
mv ./tmp/bin/cmd ./tmp/bin/$(TRAG.Name)
@docker build -t $(TRAG.Org)/$(TRAG.Name) -f ./Dockerfile.dev ./tmp
@docker image prune -f 1>/dev/null 2>&1
@echo "build done"
.PHONY: release
release:
@echo "TODO"
.PHONY: clean
clean:
-make -C ./pkg/version clean
@echo "ok"

View File

@@ -1,37 +0,0 @@
# KubeSphere
[![License](http://img.shields.io/badge/license-apache%20v2-blue.svg)](https://github.com/KubeSphere/KubeSphere/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/kubesphere/kubesphere.svg?branch=master)](https://travis-ci.org/kubesphere/kubesphere)
----
***KubeSphere*** is a distribution of [Kubernetes](https://kubernetes.io), aimed to provide quick setup, friendly and easily use, and powerful management features for Kubernetes clusters, which could help both personal and enterprise users, reduce their learning curve of Kubernetes, accelerate their transform process from other container platforms to Kubernetes.  
**Features:**
- Multiple IaaS platform support, including baremetal/KVM/QingCloud, and more will be supported in future release.
- Easy setup of Kubernetes standalone(only one master node) and cluster environment(including High Availability support).
- Powerful management console to help business users to manage and monitor the Kubernetes.
- Integrate with [OpenPitrix](https://github.com/openpitrix) to provide full life cycle of application management and be compatible of helm package.
- Support popular open source network solutions, including calico and flannel, also could use [qingcloud hostnic solution](https://github.com/yunify/hostnic-cni) if the Kubernetes is deployed on QingCloud platform.
- Support popular open source storage solutions, including Glusterfs and Cephfs, also could use [qingcloud storage solution](https://github.com/yunify/qingcloud-csi) or [qingstor storage solution](https://github.com/yunify/qingstor-csi) if the Kubernetes is deployed on QingCloud platform or QingStor NeonSAN.
- CI/CD support.
- Service Mesh support.
- Multiple image registries support.
- Integrate with QingCloud IAM.
----
## Motivation
The project originates from the requirement and pains we heard from our customers on public and private QingCloud platform, who have strong will to deploy Kubernetes in their IT system but struggle on completed setup process and long learning curve. With help of KubeSphere, their IT operators could setup Kubernetes environment quickly and use an easy management UI interface to mange their applications, also KubeSphere provides more features to help customers to handle daily business more easily, including CI/CD, micro services management...etc.
Getting Started
---------------
**TBD**
## Design
## Contributing to the project
All members of the KubeSphere community must abide by [Code of Conduct](docs/code-of-conduct.md). Only by respecting each other can we develop a productive, collaborative community.
You can then find out more detail [here](docs/welcome-toKubeSphere-new-developer-guide.md).

View File

@@ -1,3 +0,0 @@
ls /go/bin
go version
exit

View File

@@ -1,19 +0,0 @@
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
FROM golang:1.10.2-alpine3.7 as builder
RUN apk add --no-cache git curl openssl
RUN go get github.com/tools/godep
#RUN go get github.com/emicklei/go-restful
#RUN go get github.com/golang/glog
#RUN go get github.com/spf13/pflag
RUN go get golang.org/x/tools/cmd/goimports
FROM golang:1.10.2-alpine3.7
RUN apk add --no-cache git make curl openssl jq rsync godep
COPY --from=builder /go/bin /go/bin

View File

@@ -1,17 +0,0 @@
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
default:
docker build -t kubesphere/kubesphere-builder .
@echo "ok"
pull:
docker pull kubesphere/kubesphere-builder
@echo "ok"
run:
docker run --rm -it -v `pwd`:/root kubesphere/kubesphere-builder
clean:
@echo "ok"

View File

@@ -1,40 +0,0 @@
/*
Copyright 2018 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 main
import (
"github.com/spf13/pflag"
"kubesphere.io/kubesphere/pkg/app"
"kubesphere.io/kubesphere/pkg/logs"
"kubesphere.io/kubesphere/pkg/options"
"kubesphere.io/kubesphere/pkg/version"
)
func main() {
options.AddFlags(pflag.CommandLine)
pflag.Parse()
logs.InitLogs()
defer logs.FlushLogs()
version.PrintAndExitIfRequested()
app.Run()
}

6
doc.go
View File

@@ -1,6 +0,0 @@
// Copyright 2017 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.
// Package openpitrix provides the best Paas and Iaas platform.
package kubesphere

View File

@@ -1,14 +0,0 @@
# KubeSphere Code of Conduct
KubeSphere follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
# Best practice of committing code
Besides following above conduct from CNCF, we also hope every contributor in this project could help us to improve the quality of code, something you should know before checking in any new code:
- As gopher, make sure you already read [the conduct of Go language](https://golang.org/conduct) and [the instruction of writting Go](https://golang.org/doc/effective_go.html).
- Fork the project under your account and make the changes you want there.
- Execute 'go fmt' for every piece of new code.
- Every pulling request(PR) would be better constructed with only one commit, this could help code reviewer to go through your code efficiently, also helpful for every follower of this project to understand what happens in this PR. If you need to make any further code change to address the comments from reviewers, which means some new commits will be generated under this PR, you need to use 'git rebase' to combine those commits together.
- Every PR should only solve one problem or provide one feature, don't put several different fixes into one PR.
- At lease two code reviewers should involve into code reviewing process.
- Please introduce new third-party packages as little as possible to reduce the vendor dependency of this project. For example, don't import a full unit converting package but only use one function from it. For this case, you'd better write that function by yourself.
- more.

View File

@@ -1,6 +0,0 @@
# Architecture
Basic idea is to decouple application repository and runtime environment. The runtime environment an application can run is by matching the labels of runtime environment and the selector of the repository where the application is from.
## Design key points:

View File

@@ -1,99 +0,0 @@
// Copyright 2017 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.
// dot -Tpng -o output.png input.dot
digraph G {
rankdir = LR;
subgraph clusterClient {
node [
fixedsize = true,
width = 1, height = 1,
]
WebUI [shape = doublecircle];
MobileApp [shape = doublecircle];
XClient [shape = doublecircle];
}
WebUI -> ApiGateway[
label = "rest api",
dir = both,
style = bold,
];
MobileApp -> ApiGateway[
label = "rest api",
dir = both,
style = bold,
];
XClient -> ApiGateway[
label = "rest api",
dir = both,
style = bold,
];
subgraph clusterOpenpitrix {
// rest api gateway
ApiGateway [shape = rect,
fixedsize = true,
width = 1.4, height = 6.2,
];
// microservice
subgraph clusterServices {
node [
shape=record,
fixedsize = true,
width = 2.6, height = 1.3,
];
Cluster [shape = Mrecord];
Runtime [shape = Mrecord,
label="Runtime |{ plugin |{k8s|QingCloud|Other} }"
];
App [shape = Mrecord];
Repo [shape = Mrecord];
}
// service database
subgraph clusterDB {
node [
fixedsize = true,
width = 2.6, height = 1.3,
];
RepoDB [shape = cylinder];
AppDB [shape = cylinder];
RuntimeDB [shape = cylinder];
ClusterDB [shape = cylinder];
}
// api gateway
ApiGateway -> Cluster [
label = "grpc",
dir = both,
style = bold,
];
ApiGateway -> Repo [
label = "grpc",
dir = both,
style = bold,
];
ApiGateway -> App [
label = "grpc",
dir = both,
style = bold,
];
ApiGateway -> Runtime [
label = "grpc",
dir = both,
style = bold,
];
Repo -> RepoDB [label="SQL"];
App -> AppDB [label="SQL"];
Runtime -> RuntimeDB [label="SQL"];
Cluster -> ClusterDB [label="SQL"];
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 KiB

View File

@@ -1,57 +0,0 @@
# Developing for KubeSphere [deprecated]
This document is intended to be the canonical source of truth for things like
supported toolchain versions for building KubeSphere.
If you find a requirement that this doc does not capture, or if you find other
docs with references to requirements that are not simply links to this doc,
please [submit an issue](https://github.com/kubesphere/kubesphere/issues/new).
This document is intended to be relative to the branch in which it is found.
It is guaranteed that requirements will change over time for the development
branch, but release branches should not change.
- [Prerequisites](#prerequisites)
- [Setting up Go](#setting-up-go)
- [To start developing KubeSphere](#to-start-developing-kubesphere)
- [DevOps](#devops)
## Prerequisites
KubeSphere only has few external dependencies you need to setup before being
able to build and run the code.
### Setting up Go
KubeSphere written in the [Go](http://golang.org) programming language.
To build, you'll need a Go (version 1.9+) development environment.
If you haven't set up a Go development environment, please follow
[these instructions](https://golang.org/doc/install)
to install the Go tools.
Set up your GOPATH and add a path entry for Go binaries to your PATH. Typically
added to your ~/.profile:
```shell
$ export GOPATH=~/go
$ export PATH=$PATH:$GOPATH/bin
```
## To start developing KubeSphere
There are two options to get KubeSphere source code and build the project:
**You have a working Go environment.**
```shell
$ go get -d kubesphere.io/kubesphere
$ cd $GOPATH/src/kubesphere.io/kubesphere
$ make all
```
**You have a working Docker environment.**
```shell
$ git clone https://github.com/kubesphere/kubesphere
$ cd kubesphere
$ make
```

View File

@@ -1,316 +0,0 @@
# Pull Request Process
This doc explains the process and best practices for submitting a PR to the [KubeSphere project](https://github.com/kubeSphere/kubeSphere). It should serve as a reference for all contributors, and be useful especially to new and infrequent submitters.
- [Before You Submit a PR](#before-you-submit-a-pr)
* [Run Local Verifications](#run-local-verifications)
- [The PR Submit Process](#the-pr-submit-process)
* [Write Release Notes if Needed](#write-release-notes-if-needed)
* [The Testing and Merge Workflow](#the-testing-and-merge-workflow)
* [Marking Unfinished Pull Requests](#marking-unfinished-pull-requests)
* [Comment Commands Reference](#comment-commands-reference)
* [Automation](#automation)
* [How the e2e Tests Work](#how-the-e2e-tests-work)
- [Why was my PR closed?](#why-was-my-pr-closed)
- [Why is my PR not getting reviewed?](#why-is-my-pr-not-getting-reviewed)
- [Best Practices for Faster Reviews](#best-practices-for-faster-reviews)
* [0. Familiarize yourself with project conventions](#0-familiarize-yourself-with-project-conventions)
* [1. Is the feature wanted? Make a Design Doc or Sketch PR](#1-is-the-feature-wanted-make-a-design-doc-or-sketch-pr)
* [2. Smaller Is Better: Small Commits, Small PRs](#2-smaller-is-better-small-commits-small-prs)
* [3. Open a Different PR for Fixes and Generic Features](#3-open-a-different-pr-for-fixes-and-generic-features)
* [4. Comments Matter](#4-comments-matter)
* [5. Test](#5-test)
* [6. Squashing and Commit Titles](#6-squashing-and-commit-titles)
* [7. KISS, YAGNI, MVP, etc.](#7-kiss-yagni-mvp-etc)
* [8. It's OK to Push Back](#8-its-ok-to-push-back)
* [9. Common Sense and Courtesy](#9-common-sense-and-courtesy)
# Before You Submit a PR
This guide is for contributors who already have a PR to submit. If you're looking for information on setting up your developer environment and creating code to contribute to KubeSphere, see the [development guide](development.md).
**Make sure your PR adheres to our best practices. These include following project conventions, making small PRs, and commenting thoroughly. Please read the more detailed section on [Best Practices for Faster Reviews](#best-practices-for-faster-reviews) at the end of this doc.**
## Run Local Verifications
You can run these local verifications before you submit your PR to predict the
pass or fail of continuous integration.
# The PR Submit Process
Merging a PR requires the following steps to be completed before the PR will be merged automatically. For details about each step, see the [The Testing and Merge Workflow](#the-testing-and-merge-workflow) section below.
- Make the PR
- Release notes - do one of the following:
- Add notes in the release notes block, or
- Update the release note label
- Pass all tests
- Get a `/lgtm` from a reviewer
- Get approval from an owner
If your PR meets all of the steps above, it will enter the submit queue to be merged. When it is next in line to be merged, the tests will run a second time. If all tests pass, the PR will be merged automatically.
## Write Release Notes if Needed
Release notes are required for any PR with user-visible changes, such as bug-fixes, feature additions, and output format changes.
If you don't add release notes in the PR template, the `do-not-merge/release-note-label-needed` label is added to your PR automatically after you create it. There are a few ways to update it.
To add a release-note section to the PR description:
For PRs with a release note:
```release-note
Your release note here
```
For PRs that require additional action from users switching to the new release, include the string "action required" (case insensitive) in the release note:
```release-note
action required: your release note here
```
For PRs that don't need to be mentioned at release time, just write "NONE" (case insensitive):
```release-note
NONE
```
The `/release-note-none` comment command can still be used as an alternative to writing "NONE" in the release-note block if it is left empty.
To see how to format your release notes, view the [PR template](https://github.com/) for a brief example. PR titles and body comments can be modified at any time prior to the release to make them friendly for release notes.
// PR template TODO
Release notes apply to PRs on the master branch. For cherry-pick PRs, see the [cherry-pick instructions](cherry-picks.md). The only exception to these rules is when a PR is not a cherry-pick and is targeted directly to the non-master branch. In this case, a `release-note-*` label is required for that non-master PR.
// cherry-pick TODO
Now that your release notes are in shape, let's look at how the PR gets tested and merged.
## The Testing and Merge Workflow
The KubeSphere merge workflow uses comments to run tests and labels for merging PRs.
NOTE: For pull requests that are in progress but not ready for review,
prefix the PR title with `WIP` or `[WIP]` and track any remaining TODOs
in a checklist in the pull request description.
Here's the process the PR goes through on its way from submission to merging:
1. Make the pull request
1. `@o8x-merge-robot` assigns reviewers //TODO
If you're **not** a member of the KubeSphere organization:
1. Reviewer/KubeSphere Member checks that the PR is safe to test. If so, they comment `/ok-to-test`
1. Reviewer suggests edits
1. Push edits to your PR branch
1. Repeat the prior two steps as needed
1. (Optional) Some reviewers prefer that you squash commits at this step
1. Owner is assigned and will add the `/approve` label to the PR
If you are a member, or a member comments `/ok-to-test`, the PR will be considered to be trusted. Then the pre-submit tests will run:
1. Automatic tests run. See the current list of tests on the
1. If tests fail, resolve issues by pushing edits to your PR branch
1. If the failure is a flake, anyone on trusted PRs can comment `/retest` to rerun failed tests
Once the tests pass, all failures are commented as flakes, or the reviewer adds the labels `lgtm` and `approved`, the PR enters the final merge queue. The merge queue is needed to make sure no incompatible changes have been introduced by other PRs since the tests were last run on your PR.
Either the [on call contributor](on-call-rotations.md) will manage the merge queue manually. //TODO
1. The PR enters the merge queue ([http://submit-queue.KubeSphere.io]())
1. The merge queue triggers a test re-run with the comment `/test all [submit-queue is verifying that this PR is safe to merge]`
1. Author has signed the CLA (`cncf-cla: yes` label added to PR)
1. No changes made since last `lgtm` label applied
1. If tests fail, resolve issues by pushing edits to your PR branch
1. If the failure is a flake, anyone can comment `/retest` if the PR is trusted
1. If tests pass, the merge queue automatically merges the PR
That's the last step. Your PR is now merged.
## Marking Unfinished Pull Requests
If you want to solicit reviews before the implementation of your pull request is complete, you should hold your pull request to ensure that the merge queue does not pick it up and attempt to merge it. There are two methods to achieve this:
1. You may add the `/hold` or `/hold cancel` comment commands
2. You may add or remove a `WIP` or `[WIP]` prefix to your pull request title
The GitHub robots will add and remove the `do-not-merge/hold` label as you use the comment commands and the `do-not-merge/work-in-progress` label as you edit your title. While either label is present, your pull request will not be considered for merging.
## Comment Commands Reference//TODO
[The commands doc]() contains a reference for all comment commands. //TODO
## Automation//TODO
The KubeSphere developer community uses a variety of automation to manage pull requests. This automation is described in detail [in the automation doc](automation.md). //TODO
## How the Tests Work//TODO
The tests will post the status results to the PR. If an e2e test fails,
`@o8x-ci-robot` will comment on the PR with the test history and the
comment-command to re-run that test. e.g.
> The following tests failed, say /retest to rerun them all.
# Why was my PR closed?
Pull requests older than 90 days will be closed. Exceptions can be made for PRs that have active review comments, or that are awaiting other dependent PRs. Closed pull requests are easy to recreate, and little work is lost by closing a pull request that subsequently needs to be reopened. We want to limit the total number of PRs in flight to:
* Maintain a clean project
* Remove old PRs that would be difficult to rebase as the underlying code has changed over time
* Encourage code velocity
# Why is my PR not getting reviewed?
A few factors affect how long your PR might wait for review.
If it's the last few weeks of a milestone, we need to reduce churn and stabilize.
Or, it could be related to best practices. One common issue is that the PR is too big to review. Let's say you've touched 39 files and have 8657 insertions. When your would-be reviewers pull up the diffs, they run away - this PR is going to take 4 hours to review and they don't have 4 hours right now. They'll get to it later, just as soon as they have more free time (ha!).
There is a detailed rundown of best practices, including how to avoid too-lengthy PRs, in the next section.
But, if you've already followed the best practices and you still aren't getting any PR love, here are some
things you can do to move the process along:
* Make sure that your PR has an assigned reviewer (assignee in GitHub). If not, reply to the PR comment stream asking for a reviewer to be assigned.
* Ping the assignee (@username) on the PR comment stream, and ask for an estimate of when they can get to the review.
* Ping the assignee on [Slack](http://KubeSphere.slack.com). Remember that a person's GitHub username might not be the same as their Slack username.
* Ping the assignee by email (many of us have publicly available email addresses).
* If you're a member of the organization ping the [team](https://github.com/orgs/KubeSphere/teams) (via @team-name) that works in the area you're submitting code.
* If you have fixed all the issues from a review, and you haven't heard back, you should ping the assignee on the comment stream with a "please take another look" (`PTAL`) or similar comment indicating that you are ready for another review.
Read on to learn more about how to get faster reviews by following best practices.
# Best Practices for Faster Reviews
Most of this section is not specific to KubeSphere, but it's good to keep these best practices in mind when you're making a PR.
You've just had a brilliant idea on how to make KubeSphere better. Let's call that idea Feature-X. Feature-X is not even that complicated. You have a pretty good idea of how to implement it. You jump in and implement it, fixing a bunch of stuff along the way. You send your PR - this is awesome! And it sits. And sits. A week goes by and nobody reviews it. Finally, someone offers a few comments, which you fix up and wait for more review. And you wait. Another week or two go by. This is horrible.
Let's talk about best practices so your PR gets reviewed quickly.
## 0. Familiarize yourself with project conventions
* [Development guide](code-of-conduct.md)
## 1. Is the feature wanted? Make a Design Doc or Sketch PR
Are you sure Feature-X is something the KubeSphere team wants or will accept? Is it implemented to fit with other changes in flight? Are you willing to bet a few days or weeks of work on it?
It's better to get confirmation beforehand. There are two ways to do this:
- Make a proposal doc (in docs/proposals; for example [the QoS proposal]()
- Coordinate your effort with [SIG Docs]() ahead of time. //TODO
- Make a sketch PR (e.g., just the API or Go interface). Write or code up just enough to express the idea and the design and why you made those choices
Or, do all of the above.
Be clear about what type of feedback you are asking for when you submit a proposal doc or sketch PR.
Now, if we ask you to change the design, you won't have to re-write it all.
## 2. Smaller Is Better: Small Commits, Small PRs
Small commits and small PRs get reviewed faster and are more likely to be correct than big ones.
Attention is a scarce resource. If your PR takes 60 minutes to review, the reviewer's eye for detail is not as keen in the last 30 minutes as it was in the first. It might not get reviewed at all if it requires a large continuous block of time from the reviewer.
**Breaking up commits**
Break up your PR into multiple commits, at logical break points.
Making a series of discrete commits is a powerful way to express the evolution of an idea or the
different ideas that make up a single feature. Strive to group logically distinct ideas into separate commits.
For example, if you found that Feature-X needed some prefactoring to fit in, make a commit that JUST does that prefactoring. Then make a new commit for Feature-X.
Strike a balance with the number of commits. A PR with 25 commits is still very cumbersome to review, so use
judgment.
**Breaking up PRs**
Or, going back to our prefactoring example, you could also fork a new branch, do the prefactoring there and send a PR for that. If you can extract whole ideas from your PR and send those as PRs of their own, you can avoid the painful problem of continually rebasing.
KubeSphere is a fast-moving codebase - lock in your changes ASAP with your small PR, and make merges be someone else's problem.
Multiple small PRs are often better than multiple commits. Don't worry about flooding us with PRs. We'd rather have 100 small, obvious PRs than 10 unreviewable monoliths.
We want every PR to be useful on its own, so use your best judgment on what should be a PR vs. a commit.
As a rule of thumb, if your PR is directly related to Feature-X and nothing else, it should probably be part of the Feature-X PR. If you can explain why you are doing seemingly no-op work ("it makes the Feature-X change easier, I promise") we'll probably be OK with it. If you can imagine someone finding value independently of Feature-X, try it as a PR. (Do not link pull requests by `#` in a commit description, because GitHub creates lots of spam. Instead, reference other PRs via the PR your commit is in.)
## 3. Open a Different PR for Fixes and Generic Features
**Put changes that are unrelated to your feature into a different PR.**
Often, as you are implementing Feature-X, you will find bad comments, poorly named functions, bad structure, weak type-safety, etc.
You absolutely should fix those things (or at least file issues, please) - but not in the same PR as your feature. Otherwise, your diff will have way too many changes, and your reviewer won't see the forest for the trees.
**Look for opportunities to pull out generic features.**
For example, if you find yourself touching a lot of modules, think about the dependencies you are introducing between packages. Can some of what you're doing be made more generic and moved up and out of the Feature-X package? Do you need to use a function or type from an otherwise unrelated package? If so, promote! We have places for hosting more generic code.
Likewise, if Feature-X is similar in form to Feature-W which was checked in last month, and you're duplicating some tricky stuff from Feature-W, consider prefactoring the core logic out and using it in both Feature-W and
Feature-X. (Do that in its own commit or PR, please.)
## 4. Comments Matter
In your code, if someone might not understand why you did something (or you won't remember why later), comment it. Many code-review comments are about this exact issue.
If you think there's something pretty obvious that we could follow up on, add a TODO.
Read up on [GoDoc](https://blog.golang.org/godoc-documenting-go-code) - follow those general rules for comments.
## 5. Test
Nothing is more frustrating than starting a review, only to find that the tests are inadequate or absent. Very few PRs can touch code and NOT touch tests.
If you don't know how to test Feature-X, please ask! We'll be happy to help you design things for easy testing or to suggest appropriate test cases.
## 6. Squashing and Commit Titles
Your reviewer has finally sent you feedback on Feature-X.
Make the fixups, and don't squash yet. Put them in a new commit, and re-push. That way your reviewer can look at the new commit on its own, which is much faster than starting over.
We might still ask you to clean up your commits at the very end for the sake of a more readable history, but don't do this until asked: typically at the point where the PR would otherwise be tagged `LGTM`.
Each commit should have a good title line (<70 characters) and include an additional description paragraph describing in more detail the change intended.
**General squashing guidelines:**
* Sausage => squash
Do squash when there are several commits to fix bugs in the original commit(s), address reviewer feedback, etc. Really we only want to see the end state and commit message for the whole PR.
* Layers => don't squash
Don't squash when there are independent changes layered to achieve a single goal. For instance, writing a code munger could be one commit, applying it could be another, and adding a precommit check could be a third. One could argue they should be separate PRs, but there's really no way to test/review the munger without seeing it applied, and there needs to be a precommit check to ensure the munged output doesn't immediately get out of date.
A commit, as much as possible, should be a single logical change.
## 7. KISS, YAGNI, MVP, etc.
Sometimes we need to remind each other of core tenets of software design - Keep It Simple, You Aren't Gonna Need It, Minimum Viable Product, and so on. Adding a feature "because we might need it later" is antithetical to software that ships. Add the things you need NOW and (ideally) leave room for things you might need later - but don't implement them now.
## 8. It's OK to Push Back
Sometimes reviewers make mistakes. It's OK to push back on changes your reviewer requested. If you have a good reason for doing something a certain way, you are absolutely allowed to debate the merits of a requested change. Both the reviewer and reviewee should strive to discuss these issues in a polite and respectful manner.
You might be overruled, but you might also prevail. We're pretty reasonable people. Mostly.
Another phenomenon of open-source projects (where anyone can comment on any issue) is the dog-pile - your PR gets so many comments from so many people it becomes hard to follow. In this situation, you can ask the primary reviewer (assignee) whether they want you to fork a new PR to clear out all the comments. You don't HAVE to fix every issue raised by every person who feels like commenting, but you should answer reasonable comments with an explanation.
## 9. Common Sense and Courtesy
No document can take the place of common sense and good taste. Use your best judgment, while you put
a bit of thought into how your work can be made easier to review. If you do these things your PRs will get merged with less friction.

View File

@@ -1,37 +0,0 @@
Welcome to KubeSphere! (New Developer Guide)
============================================
_This document assumes that you know what KubeSphere does.
Introduction
------------
This
document will help you understand the organization of the KubeSphere project and
direct you to the best places to get started. By the end of this doc, you'll be
able to pick up issues, write code to fix them, and get your work reviewed and
merged.
If you have questions about the development process, feel free to jump into our
[Slack workspace](http://KubeSphere.slack.com/). If you join the
Slack workspace it is recommended to set your Slack display name to your GitHub
account handle.
Downloading, Building, and Testing KubeSphere
---------------------------------------------
This guide is non-technical, so it does not cover the technical details of
working KubeSphere. We have plenty of documentation available under
[docs.kubesphere.io](https://docs.kubesphere.io).
Pull-Request Process
--------------------
The pull-request process is documented in [pull-requests.md](pull-requests.md).
As described in that document, you must sign the CLA before
KubeSphere can accept your contribution.
Thanks for reading!

View File

@@ -1,24 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: kubesphere-router-gateway
labels:
app: kubesphere
component: ks-router
tier: backend
spec:
selector:
app: kubesphere
component: ks-router
tier: backend
type: LoadBalancer
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
- name: https
protocol: TCP
port: 443
targetPort: 443

View File

@@ -1,69 +0,0 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ks-router
spec:
replicas: 1
selector:
matchLabels:
app: kubesphere
component: ks-router
tier: backend
template:
metadata:
labels:
app: kubesphere
component: ks-router
tier: backend
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
spec:
serviceAccountName: kubesphere-router-serviceaccount
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.16.2
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --annotations-prefix=nginx.ingress.kubernetes.io
- --force-namespace-isolation
- --update-status
- --update-status-on-shutdown
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
securityContext:
runAsNonRoot: false

View File

@@ -1,4 +0,0 @@
#!/bin/bash
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
docker push kubesphere/ks-apiserver:latest

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,60 +0,0 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "/swagger-ui/api.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>
</body>
</html>

View File

@@ -1,67 +0,0 @@
<!doctype html>
<html lang="en-US">
<body onload="run()">
</body>
</html>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
</script>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,87 +0,0 @@
/*
Copyright 2018 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 components
import (
"net/http"
"github.com/golang/glog"
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath).To(handleGetComponents).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/{namespace}/{componentName}").To(handleGetComponentStatus).
Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/health").To(handleGetSystemHealthStatus).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}
func handleGetSystemHealthStatus(request *restful.Request, response *restful.Response) {
if status, err := models.GetSystemHealthStatus(); err != nil {
err = response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
if err != nil {
glog.Errorln(err)
}
} else {
err = response.WriteAsJson(status)
if err != nil {
glog.Errorln(err)
}
}
}
// get a specific component status
func handleGetComponentStatus(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
componentName := request.PathParameter("componentName")
if component, err := models.GetComponentStatus(namespace, componentName); err != nil {
err = response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
if err != nil {
glog.Errorln(err)
}
} else {
if err = response.WriteAsJson(component); err != nil {
glog.Errorln(err)
}
}
}
// get all components
func handleGetComponents(request *restful.Request, response *restful.Response) {
result, err := models.GetAllComponentsStatus()
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}

View File

@@ -1,61 +0,0 @@
/*
Copyright 2018 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 containers
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models/metrics"
)
// {namespace} namespace name
// {node} node host name
// {pod} pod name
// {container} container name
func Register(ws *restful.WebService) {
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers/{container}").To(handleContainerUnderNameSpaceAndPod).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers").To(handleContainersUnderNameSpaceAndPod).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/nodes/{node}/namespaces/{namespace}/pods/{pod}/containers").To(handleContainersUnderNodeAndNameSpaceAndPod).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}
func handleContainerUnderNameSpaceAndPod(request *restful.Request, response *restful.Response) {
var resultContainer metrics.ContainerMetrics
resultContainer = metrics.FormatContainerMetrics(request.PathParameter("namespace"), request.PathParameter("pod"), request.PathParameter("container"))
resultContainer.NodeName = metrics.GetNodeNameForPod(request.PathParameter("pod"), request.PathParameter("namespace"))
response.WriteAsJson(resultContainer)
}
func handleContainersUnderNameSpaceAndPod(request *restful.Request, response *restful.Response) {
var resultNameSpace constants.PageableResponse
resultNameSpace = metrics.FormatContainersMetrics("", request.PathParameter("namespace"), request.PathParameter("pod"))
response.WriteAsJson(resultNameSpace)
}
func handleContainersUnderNodeAndNameSpaceAndPod(request *restful.Request, response *restful.Response) {
var resultNameSpace constants.PageableResponse
resultNameSpace = metrics.FormatContainersMetrics(request.PathParameter("node"), request.PathParameter("namespace"), request.PathParameter("pod"))
response.WriteAsJson(resultNameSpace)
}

View File

@@ -1,56 +0,0 @@
/*
Copyright 2018 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 daemonsets
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"daemonsets"}
ws.Route(ws.GET(subPath).To(getDaemonSetRevision).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Handle daemonset" +
" operation").Param(ws.PathParameter("daemonset", "daemonset's name").DataType("string")).Param(ws.PathParameter("namespace",
"daemonset's namespace").DataType("string")).Param(ws.PathParameter("revision", "daemonset's revision")).Writes(v1.DaemonSet{}))
}
func getDaemonSetRevision(req *restful.Request, resp *restful.Response) {
daemonset := req.PathParameter("daemonset")
namespace := req.PathParameter("namespace")
revision := req.PathParameter("revision")
res, err := models.GetDaemonSetRevision(namespace, daemonset, revision)
if err != nil {
if errors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: err.Error()})
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
}
resp.WriteEntity(res)
}

View File

@@ -1,56 +0,0 @@
/*
Copyright 2018 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 deployments
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"deployments"}
ws.Route(ws.GET(subPath).To(getDeployRevision).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Handle deployment" +
" operation").Param(ws.PathParameter("deployment", "deployment's name").DataType("string")).Param(ws.PathParameter("namespace",
"deployment's namespace").DataType("string")).Param(ws.PathParameter("deployment", "deployment's name")).Writes(v1.ReplicaSet{}))
}
func getDeployRevision(req *restful.Request, resp *restful.Response) {
deploy := req.PathParameter("deployment")
namespace := req.PathParameter("namespace")
revision := req.PathParameter("revision")
res, err := models.GetDeployRevision(namespace, deploy, revision)
if err != nil {
if errors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: err.Error()})
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
}
resp.WriteEntity(res)
}

View File

@@ -1,57 +0,0 @@
/*
Copyright 2018 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 hpa
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/api/errors"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/client"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"horizontalpodautoscalers"}
ws.Route(ws.GET(subPath).To(getHpa).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc(
"get horizontalpodautoscalers").Param(ws.PathParameter("namespace",
"horizontalpodautoscalers's namespace").DataType("string")).Param(ws.PathParameter(
"horizontalpodautoscaler", "horizontalpodautoscaler's name")).Writes(v1.HorizontalPodAutoscaler{}))
}
func getHpa(req *restful.Request, resp *restful.Response) {
hpa := req.PathParameter("horizontalpodautoscaler")
namespace := req.PathParameter("namespace")
client := client.NewK8sClient()
res, err := client.AutoscalingV1().HorizontalPodAutoscalers(namespace).Get(hpa, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusOK, nil)
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, nil)
}
}
resp.WriteEntity(res)
}

View File

@@ -1,240 +0,0 @@
/*
Copyright 2018 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 iam
import (
"net/http"
"strings"
"github.com/emicklei/go-restful"
"k8s.io/api/rbac/v1"
"k8s.io/kubernetes/pkg/util/slice"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models/iam"
)
type roleList struct {
ClusterRoles []v1.ClusterRole `json:"clusterRoles" protobuf:"bytes,2,rep,name=clusterRoles"`
Roles []v1.Role `json:"roles" protobuf:"bytes,2,rep,name=roles"`
}
type userRuleList struct {
ClusterRules []iam.Rule `json:"clusterRules"`
Rules map[string][]iam.Rule `json:"rules"`
}
func Register(ws *restful.WebService) {
//roles
ws.Route(ws.GET("/users/{username}/roles").To(userRolesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
//rules define
ws.Route(ws.GET("/roles/rules").To(roleRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
ws.Route(ws.GET("/clusterroles/rules").To(clusterRoleRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
//user->rules
ws.Route(ws.GET("/rules").To(usersRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
ws.Route(ws.GET("/users/{username}/rules").To(userRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
//role->rules
ws.Route(ws.GET("/clusterroles/{name}/rules").To(clusterRoleRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
ws.Route(ws.GET("/namespaces/{namespace}/roles/{name}/rules").To(roleRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
//role->users
ws.Route(ws.GET("/namespaces/{namespace}/roles/{name}/users").To(roleUsersHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
ws.Route(ws.GET("/clusterroles/{name}/users").To(clusterRoleUsersHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
}
// username -> roles
func userRolesHandler(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("username")
roles, err := iam.GetRoles("", username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
roleList := roleList{}
roleList.Roles = roles
roleList.ClusterRoles = clusterRoles
resp.WriteEntity(roleList)
}
// namespaces + role name -> users
func roleUsersHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
namespace := req.PathParameter("namespace")
roleBindings, err := iam.GetRoleBindings(namespace, name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
users := make([]string, 0)
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind &&
!strings.HasPrefix(subject.Name, "system") &&
!slice.ContainsString(users, subject.Name, nil) {
users = append(users, subject.Name)
}
}
}
resp.WriteEntity(users)
}
// cluster role name -> users
func clusterRoleUsersHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
roleBindings, err := iam.GetClusterRoleBindings(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
users := make([]string, 0)
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && !strings.HasPrefix(subject.Name, "system") &&
!slice.ContainsString(users, subject.Name, nil) {
users = append(users, subject.Name)
}
}
}
resp.WriteEntity(users)
}
// username -> rules
func usersRulesHandler(req *restful.Request, resp *restful.Response) {
users := strings.Split(req.QueryParameter("users"), ",")
usersRules := make(map[string]userRuleList, 0)
for _, username := range users {
_, contains := usersRules[username]
if username != "" && !contains {
userRuleList := userRuleList{}
clusterRules, err := iam.GetUserClusterRules(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
rules, err := iam.GetUserRules(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
userRuleList.ClusterRules = clusterRules
userRuleList.Rules = rules
usersRules[username] = userRuleList
}
}
resp.WriteEntity(usersRules)
}
// username -> rules
func userRulesHandler(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("username")
userRuleList := userRuleList{}
clusterRules, err := iam.GetUserClusterRules(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
rules, err := iam.GetUserRules(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
userRuleList.ClusterRules = clusterRules
userRuleList.Rules = rules
resp.WriteEntity(userRuleList)
}
// cluster role name -> rules
func clusterRoleRulesHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
var rules []iam.Rule
if name == "" {
rules = iam.ClusterRoleRuleMapping
} else {
var err error
rules, err = iam.GetClusterRoleRules(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
}
resp.WriteEntity(rules)
}
// role name -> rules
func roleRulesHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
namespace := req.PathParameter("namespace")
var rules []iam.Rule
if namespace == "" && name == "" {
rules = iam.RoleRuleMapping
} else {
var err error
rules, err = iam.GetRoleRules(namespace, name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
}
resp.WriteEntity(rules)
}

View File

@@ -1,77 +0,0 @@
/*
Copyright 2018 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 v1alpha
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/components"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/containers"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/daemonsets"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/deployments"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/hpa"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/iam"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/jobs"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/monitoring"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/nodes"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/pods"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/quota"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/registries"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/resources"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/routes"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/statefulsets"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/storage"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/terminal"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/users"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/volumes"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/workloadstatus"
"kubesphere.io/kubesphere/pkg/apis/v1alpha/workspaces"
_ "kubesphere.io/kubesphere/pkg/filter/container"
)
func init() {
ws := new(restful.WebService)
ws.Path("/api/v1alpha1")
registries.Register(ws, "/registries")
storage.Register(ws, "/storage")
volumes.Register(ws, "/volumes")
nodes.Register(ws, "/nodes")
pods.Register(ws)
containers.Register(ws)
iam.Register(ws)
components.Register(ws, "/components")
routes.Register(ws)
user.Register(ws, "/users/{user}")
terminal.Register(ws, "/namespaces/{namespace}/pod/{pod}/shell/{container}")
workloadstatus.Register(ws, "/status")
quota.Register(ws, "/quota")
hpa.Register(ws, "/namespaces/{namespace}/horizontalpodautoscalers/{horizontalpodautoscaler}")
jobs.Register(ws, "/namespaces/{namespace}/jobs/{job}")
deployments.Register(ws, "/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}")
daemonsets.Register(ws, "/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}")
statefulsets.Register(ws, "/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}")
resources.Register(ws, "/resources")
monitoring.Register(ws, "/monitoring")
workspaces.Register(ws, "/workspaces")
// add webservice to default container
restful.Add(ws)
// add websocket handler to default container
terminal.RegisterWebSocketHandler(restful.DefaultContainer, "/api/v1alpha1/sockjs/")
}

View File

@@ -1,63 +0,0 @@
/*
Copyright 2018 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 jobs
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"fmt"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/controllers"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"jobs"}
ws.Route(ws.POST(subPath).To(handleJob).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Handle job" +
" operation").Param(ws.PathParameter("job", "job name").DataType("string")).Param(ws.PathParameter("namespace",
"job's namespace").DataType("string")).Param(ws.QueryParameter("a",
"action").DataType("string")).Writes(""))
}
func handleJob(req *restful.Request, resp *restful.Response) {
var res interface{}
var err error
job := req.PathParameter("job")
namespace := req.PathParameter("namespace")
action := req.QueryParameter("a")
switch action {
case "rerun":
res, err = controllers.JobReRun(namespace, job)
default:
resp.WriteHeaderAndEntity(http.StatusForbidden, constants.MessageResponse{Message: fmt.Sprintf("invalid operation %s", action)})
return
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(res)
}

View File

@@ -1,443 +0,0 @@
/*
Copyright 2018 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 monitoring
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models/metrics"
)
func (u Monitor) monitorPod(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
podName := requestParams.PodName
metricName := requestParams.MetricsName
if podName != "" {
// single pod single metric
queryType, params, nullRule := metrics.AssemblePodMetricRequestInfo(requestParams, metricName)
var res *metrics.FormatedMetric
if !nullRule {
res = metrics.GetMetric(queryType, params, metricName)
}
response.WriteAsJson(res)
} else {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelPod)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
}
func (u Monitor) monitorContainer(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if requestParams.MetricsFilter != "" {
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelContainer)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelContainerName)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
} else {
res := metrics.MonitorContainer(requestParams, metricName)
response.WriteAsJson(res)
}
}
func (u Monitor) monitorWorkload(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkload)
var sortedMetrics *metrics.FormatedLevelMetric
var maxMetricCount int
wlKind := requestParams.WorkloadKind
// sorting
if wlKind == "" {
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkload)
} else {
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelPodName)
}
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
func (u Monitor) monitorAllWorkspaces(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
tp := requestParams.Tp
if tp == "_statistics" {
// merge multiple metric: all-devops, all-roles, all-projects...this api is designed for admin
res := metrics.MonitorAllWorkspacesStatistics()
response.WriteAsJson(res)
} else if tp == "rank" {
rawMetrics := metrics.MonitorAllWorkspaces(requestParams)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelWorkspace)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
} else {
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
response.WriteAsJson(res)
}
}
func (u Monitor) monitorOneWorkspace(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
tp := requestParams.Tp
if tp == "rank" {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
} else if tp == "_statistics" {
wsName := requestParams.WsName
// merge multiple metric: devops, roles, projects...
res := metrics.MonitorOneWorkspaceStatistics(wsName)
response.WriteAsJson(res)
} else {
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
response.WriteAsJson(res)
}
}
func (u Monitor) monitorNamespace(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
nsName := requestParams.NsName
if nsName != "" {
// single
queryType, params := metrics.AssembleNamespaceMetricRequestInfo(requestParams, metricName)
res := metrics.GetMetric(queryType, params, metricName)
response.WriteAsJson(res)
} else {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNamespace)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNamespace)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
}
func (u Monitor) monitorCluster(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if metricName != "" {
// single
queryType, params := metrics.AssembleClusterMetricRequestInfo(requestParams, metricName)
res := metrics.GetMetric(queryType, params, metricName)
response.WriteAsJson(res)
} else {
// multiple
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelCluster)
response.WriteAsJson(res)
}
}
func (u Monitor) monitorNode(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if metricName != "" {
// single
queryType, params := metrics.AssembleNodeMetricRequestInfo(requestParams, metricName)
res := metrics.GetMetric(queryType, params, metricName)
nodeAddress := metrics.GetNodeAddressInfo()
metrics.AddNodeAddressMetric(res, nodeAddress)
response.WriteAsJson(res)
} else {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNode)
nodeAddress := metrics.GetNodeAddressInfo()
for i := 0; i < len(rawMetrics.Results); i++ {
metrics.AddNodeAddressMetric(&rawMetrics.Results[i], nodeAddress)
}
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics, metrics.MetricLevelNode)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
}
// k8s component(controller, scheduler, etcd) status
func (u Monitor) monitorComponentStatus(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
status := metrics.MonitorComponentStatus(requestParams)
response.WriteAsJson(status)
}
type Monitor struct {
}
func Register(ws *restful.WebService, subPath string) {
tags := []string{"monitoring apis"}
u := Monitor{}
ws.Route(ws.GET(subPath+"/clusters").To(u.monitorCluster).
Filter(route.RouteLogging).
Doc("monitor cluster level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("cluster_cpu_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes").To(u.monitorNode).
Filter(route.RouteLogging).
Doc("monitor nodes level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("node_cpu_utilisation")).
Param(ws.QueryParameter("nodes_filter", "node re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes/{node_id}").To(u.monitorNode).
Filter(route.RouteLogging).
Doc("monitor specific node level metrics").
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("node_cpu_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces").To(u.monitorNamespace).
Filter(route.RouteLogging).
Doc("monitor namespaces level metrics").
Param(ws.QueryParameter("namespaces_filter", "namespaces re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("namespace_memory_utilisation")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}").To(u.monitorNamespace).
Filter(route.RouteLogging).
Doc("monitor specific namespace level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("namespace_memory_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/pods").To(u.monitorPod).
Filter(route.RouteLogging).
Doc("monitor pods level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/pods/{pod_name}").To(u.monitorPod).
Filter(route.RouteLogging).
Doc("monitor specific pod level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes/{node_id}/pods").To(u.monitorPod).
Filter(route.RouteLogging).
Doc("monitor pods level metrics by nodeid").
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("i-k89a62il")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes/{node_id}/pods/{pod_name}").To(u.monitorPod).
Filter(route.RouteLogging).
Doc("monitor specific pod level metrics by nodeid").
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true).DefaultValue("i-k89a62il")).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/nodes/{node_id}/pods/{pod_name}/containers").To(u.monitorContainer).
Filter(route.RouteLogging).
Doc("monitor specific pod level metrics by nodeid").
Param(ws.PathParameter("node_id", "specific node").DataType("string").Required(true)).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true)).
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/pods/{pod_name}/containers").To(u.monitorContainer).
Filter(route.RouteLogging).
Doc("monitor containers level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/pods/{pod_name}/containers/{container_name}").To(u.monitorContainer).
Filter(route.RouteLogging).
Doc("monitor specific container level metrics").
Param(ws.PathParameter("ns_name", "specific namespace").DataType("string").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod_name", "specific pod").DataType("string").Required(true).DefaultValue("")).
Param(ws.PathParameter("container_name", "specific container").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").DataType("string").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/workloads/{workload_kind}").To(u.monitorWorkload).
Filter(route.RouteLogging).
Doc("monitor specific workload level metrics").
Param(ws.PathParameter("ns_name", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.PathParameter("workload_kind", "workload kind").DataType("string").Required(false).DefaultValue("daemonset")).
Param(ws.QueryParameter("workload_name", "workload name").DataType("string").Required(true).DefaultValue("")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "max metric items in a page").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/namespaces/{ns_name}/workloads").To(u.monitorWorkload).
Filter(route.RouteLogging).
Doc("monitor all workload level metrics").
Param(ws.PathParameter("ns_name", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.QueryParameter("workloads_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
// list all namespace in this workspace by selected metrics
ws.Route(ws.GET(subPath+"/workspaces/{workspace_name}").To(u.monitorOneWorkspace).
Filter(route.RouteLogging).
Doc("monitor workspaces level metrics").
Param(ws.PathParameter("workspace_name", "workspace name").DataType("string").Required(true)).
Param(ws.QueryParameter("namespaces_filter", "namespaces filter").DataType("string").Required(false).DefaultValue("k.*")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("namespace_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/workspaces").To(u.monitorAllWorkspaces).
Filter(route.RouteLogging).
Doc("monitor workspaces level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("workspace_memory_utilisation")).
Param(ws.QueryParameter("workspaces_filter", "workspaces re2 expression filter").DataType("string").Required(false).DefaultValue(".*")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/components").To(u.monitorComponentStatus).
Filter(route.RouteLogging).
Doc("monitor k8s components status").
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}

View File

@@ -1,96 +0,0 @@
/*
Copyright 2018 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 nodes
import (
"github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models/metrics"
)
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath).To(handleNodes).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/{nodename}").To(handleSingleNode).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.POST(subPath+"/{nodename}/drainage").To(handleDrainNode).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}
func MakeRequest(node string, ch chan<- metrics.NodeMetrics) {
resultNode := metrics.FormatNodeMetrics(node)
ch <- resultNode
}
func handleNodes(request *restful.Request, response *restful.Response) {
var result constants.PageableResponse
nodes := metrics.GetNodes()
ch := make(chan metrics.NodeMetrics)
for _, node := range nodes {
go MakeRequest(node, ch)
}
for _, _ = range nodes {
result.Items = append(result.Items, <-ch)
}
if result.Items == nil {
result.Items = make([]interface{}, 0)
}
result.TotalCount = len(result.Items)
response.WriteAsJson(result)
}
func handleSingleNode(request *restful.Request, response *restful.Response) {
nodeName := request.PathParameter("nodename")
var resultNode metrics.NodeMetrics
resultNode = metrics.FormatNodeMetrics(nodeName)
response.WriteAsJson(resultNode)
}
func handleDrainNode(request *restful.Request, response *restful.Response) {
nodeName := request.PathParameter("nodename")
result, err := metrics.DrainNode(nodeName)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}

View File

@@ -1,126 +0,0 @@
/*
Copyright 2018 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 pods
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/metrics"
)
func Register(ws *restful.WebService) {
ws.Route(ws.GET("/pods").To(handleAllPods).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}").To(handlePodUnderNameSpace).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/namespaces/{namespace}/deployments/{deployment}/pods").
To(handleGetDeploymentPodsMetrics).
Filter(route.RouteLogging).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON))
ws.Route(ws.GET("/namespaces/{namespace}/daemonsets/{daemonset}/pods").
To(handleGetDaemonsetPodsMetrics).
Filter(route.RouteLogging).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON))
ws.Route(ws.GET("/namespaces/{namespace}/statefulsets/{statefulset}/pods").
To(handleGetStatefulsetPodsMetrics).
Filter(route.RouteLogging).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON))
ws.Route(ws.GET("/namespaces/{namespace}/pods").To(handlePodsUnderNameSpace).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/nodes/{node}/pods").To(handlePodsUnderNode).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/nodes/{node}/namespaces/{namespace}/pods").To(handlePodsUnderNodeAndNameSpace).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}
// Get all pods metrics in cluster
func handleAllPods(_ *restful.Request, response *restful.Response) {
var result constants.PageableResponse
result = metrics.GetAllPodMetrics()
response.WriteAsJson(result)
}
// Get pods metrics in namespace
func handlePodsUnderNameSpace(request *restful.Request, response *restful.Response) {
var result constants.PageableResponse
labelSelector := request.QueryParameter("labelSelector")
result = metrics.GetPodMetricsInNamespace(request.PathParameter("namespace"), labelSelector)
response.WriteAsJson(result)
}
// Get pods metrics in a deployment
func handleGetDeploymentPodsMetrics(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
deployment := request.PathParameter("deployment")
result := metrics.GetPodMetricsInDeployment(namespace, deployment)
response.WriteAsJson(result)
}
// Get pods metrics in daemonset deployment
func handleGetDaemonsetPodsMetrics(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
daemonset := request.PathParameter("daemonset")
result := metrics.GetPodMetricsInDaemonset(namespace, daemonset)
response.WriteAsJson(result)
}
// Get pods metrics in statefulset deployment
func handleGetStatefulsetPodsMetrics(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
statefulset := request.PathParameter("statefulset")
result := metrics.GetPodMetricsInStatefulSet(namespace, statefulset)
response.WriteAsJson(result)
}
// Get all pods metrics located in node
func handlePodsUnderNode(request *restful.Request, response *restful.Response) {
var result constants.PageableResponse
result = metrics.GetPodMetricsInNode(request.PathParameter("node"))
response.WriteAsJson(result)
}
// Get a specific pod metrics
func handlePodUnderNameSpace(request *restful.Request, response *restful.Response) {
var resultPod metrics.PodMetrics
resultPod = metrics.FormatPodMetrics(request.PathParameter("namespace"), request.PathParameter("pod"))
response.WriteAsJson(resultPod)
}
// Get pod metrics in a namespace located in deployment
func handlePodsUnderNodeAndNameSpace(request *restful.Request, response *restful.Response) {
var result constants.PageableResponse
nodeName := request.PathParameter("node")
namespace := request.PathParameter("namespace")
result = metrics.GetPodMetricsInNamespaceOfNode(namespace, nodeName)
response.WriteAsJson(result)
}

View File

@@ -1,63 +0,0 @@
/*
Copyright 2018 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 quota
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"quota"}
ws.Route(ws.GET(subPath).To(getClusterQuota).Produces(restful.MIME_JSON).Doc("get whole "+
"cluster's resource usage").Writes(models.ResourceQuota{}).Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET(subPath+"/namespaces/{namespace}").Doc("get specified namespace's resource "+
"quota and usage").Param(ws.PathParameter("namespace",
"namespace's name").DataType("string")).Writes(models.ResourceQuota{}).
Metadata(restfulspec.KeyOpenAPITags, tags).To(getNamespaceQuota).Produces(restful.MIME_JSON))
}
func getNamespaceQuota(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
quota, err := models.GetNamespaceQuota(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
resp.WriteEntity(quota)
}
func getClusterQuota(req *restful.Request, resp *restful.Response) {
quota, err := models.GetClusterQuota()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
resp.WriteEntity(quota)
}

View File

@@ -1,243 +0,0 @@
/*
Copyright 2018 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 registries
import (
"net/http"
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.POST(subPath + "/validation").To(handlerRegistryValidation).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.POST(subPath).To(handleCreateRegistries).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.PUT(subPath + "/{name}").To(handleUpdateRegistries).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath + "/{project}").To(handleQueryRegistries).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath).To(handlerListRegistries).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.DELETE(subPath + "/{name}").To(handlerDeleteRegistries).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath + "/detail/{name}").To(handlerGetRegistries).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath + "/{name}/namespaces/{namespace}/searchwords/{searchWord}").
Param(ws.PathParameter("namespace", "registry secret's namespace")).
Param(ws.PathParameter("name", "registry secret's name")).
Param(ws.PathParameter("searchWord", "keyword use to search image")).
To(handlerImageSearch).
Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath + "/{name}/namespaces/{namespace}/tags").
Param(ws.QueryParameter("image", "imageName")).
Param(ws.PathParameter("namespace", "registry secret's namespace")).
Param(ws.PathParameter("name", "registry secret's name")).
To(handlerGetImageTags).
Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
}
func handlerRegistryValidation(request *restful.Request, response *restful.Response) {
authinfo := models.AuthInfo{}
err := request.ReadEntity(&authinfo)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
result := models.RegistryLoginAuth(authinfo)
response.WriteAsJson(result)
}
}
func handlerImageSearch(request *restful.Request, response *restful.Response) {
registry := request.PathParameter("name")
searchWord := request.PathParameter("searchWord")
namespace := request.PathParameter("namespace")
res := models.ImageSearch(namespace, registry, searchWord)
response.WriteEntity(res)
}
func handlerGetImageTags(request *restful.Request, response *restful.Response) {
registry := request.PathParameter("name")
image := request.QueryParameter("image")
namespace := request.PathParameter("namespace")
res := models.GetImageTags(namespace, registry, image)
response.WriteEntity(res)
}
func handleCreateRegistries(request *restful.Request, response *restful.Response) {
registries := models.Registries{}
err := request.ReadEntity(&registries)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
result, err := models.CreateRegistries(registries)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}
}
func handleQueryRegistries(request *restful.Request, response *restful.Response) {
project := request.PathParameter("project")
result, err := models.QueryRegistries(project)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}
func handlerListRegistries(request *restful.Request, response *restful.Response) {
result, err := models.ListAllRegistries()
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}
func handlerDeleteRegistries(request *restful.Request, response *restful.Response) {
name := request.PathParameter("name")
result, err := models.DeleteRegistries(name)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}
func handleUpdateRegistries(request *restful.Request, response *restful.Response) {
name := request.PathParameter("name")
registries := models.Registries{}
err := request.ReadEntity(&registries)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
result, err := models.UpdateRegistries(name, registries)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}
}
func handlerGetRegistries(request *restful.Request, response *restful.Response) {
name := request.PathParameter("name")
result, err := models.GetReisgtries(name)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(result)
}
}

View File

@@ -1,125 +0,0 @@
/*
Copyright 2018 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 resources
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"fmt"
"strings"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"resources"}
ws.Route(ws.GET(subPath+"/{resource}").To(listResource).
Produces(restful.MIME_JSON).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get resource list").
Param(ws.PathParameter("resource", "resource name").DataType("string")).
Param(ws.QueryParameter("conditions", "search conditions").DataType("string")).
Param(ws.QueryParameter("reverse", "support reverse ordering").DataType("bool").DefaultValue("false")).
Param(ws.QueryParameter("order", "the field for sorting").DataType("string")).
Param(ws.QueryParameter("paging", "support paging function").DataType("string")).
Writes(models.ResourceList{}))
}
func isInvalid(str string) bool {
invalidList := []string{"exec", "insert", "select", "delete", "update", "count", "*", "%", "truncate", "drop"}
str = strings.Replace(str, "=", " ", -1)
str = strings.Replace(str, ",", " ", -1)
str = strings.Replace(str, "~", " ", -1)
items := strings.Split(str, " ")
for _, invalid := range invalidList {
for _, item := range items {
if item == invalid || strings.ToLower(item) == invalid {
return true
}
}
}
return false
}
func listResource(req *restful.Request, resp *restful.Response) {
resource := req.PathParameter("resource")
if resource == "applications" {
handleApplication(req, resp)
return
}
conditions := req.QueryParameter("conditions")
paging := req.QueryParameter("paging")
orderField := req.QueryParameter("order")
reverse := req.QueryParameter("reverse")
if len(orderField) > 0 {
if reverse == "true" {
orderField = fmt.Sprintf("%s %s", orderField, "desc")
} else {
orderField = fmt.Sprintf("%s %s", orderField, "asc")
}
}
if isInvalid(conditions) || isInvalid(paging) || isInvalid(orderField) {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid input"})
return
}
res, err := models.ListResource(resource, conditions, paging, orderField)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(res)
}
func handleApplication(req *restful.Request, resp *restful.Response) {
paging := req.QueryParameter("paging")
clusterId := req.QueryParameter("cluster_id")
runtimeId := req.QueryParameter("runtime_id")
conditions := req.QueryParameter("conditions")
if len(clusterId) > 0 {
app, err := models.GetApplication(clusterId)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(app)
return
}
res, err := models.ListApplication(runtimeId, conditions, paging)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(res)
}

View File

@@ -1,202 +0,0 @@
/*
Copyright 2018 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 routes
import (
"github.com/emicklei/go-restful"
"net/http"
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService) {
ws.Route(ws.GET("/routers").To(GetAllRouters).
Doc("Get all routers").
Filter(route.RouteLogging).
Produces(restful.MIME_JSON))
ws.Route(ws.GET("/users/{user}/routers").To(GetAllRoutersOfUser).
Doc("Get routers for user").
Filter(route.RouteLogging).
Produces(restful.MIME_JSON))
ws.Route(ws.GET("/namespaces/{namespace}/router").To(GetRouter).
Doc("Get router of a specified project").
Param(ws.PathParameter("namespace", "name of the project").DataType("string")).
Filter(route.RouteLogging).
Produces(restful.MIME_JSON))
ws.Route(ws.DELETE("/namespaces/{namespace}/router").To(DeleteRouter).
Doc("Get router of a specified project").
Param(ws.PathParameter("namespace", "name of the project").DataType("string")).
Filter(route.RouteLogging).
Produces(restful.MIME_JSON))
ws.Route(ws.POST("/namespaces/{namespace}/router").To(CreateRouter).
Doc("Create a router for a specified project").
Param(ws.PathParameter("namespace", "name of the project").DataType("string")).
Filter(route.RouteLogging).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON))
ws.Route(ws.PUT("/namespaces/{namespace}/router").To(UpdateRouter).
Doc("Update a router for a specified project").
Param(ws.PathParameter("namespace", "name of the project").DataType("string")).
Filter(route.RouteLogging).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON))
}
type Router struct {
RouterType string `json:"type"`
Annotations map[string]string `json:"annotations"`
}
// Get all namespace ingress controller services
func GetAllRouters(request *restful.Request, response *restful.Response) {
routers, err := models.GetAllRouters()
if err != nil {
glog.Error(err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(routers)
}
}
// Get all namespace ingress controller services for user
func GetAllRoutersOfUser(request *restful.Request, response *restful.Response) {
username := request.PathParameter("user")
routers, err := models.GetAllRoutersOfUser(username)
if err != nil {
glog.Error(err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(routers)
}
}
// Get ingress controller service for specified namespace
func GetRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
router, err := models.GetRouter(namespace)
if err != nil {
glog.Error(err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else if router == nil {
response.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: "Reseource Not Found"})
} else {
response.WriteAsJson(router)
}
}
// Create ingress controller and related services
func CreateRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
newRouter := Router{}
err := request.ReadEntity(&newRouter)
if err != nil {
response.WriteAsJson(err)
return
}
var router *v1.Service
serviceType, annotationMap, err := ParseParameter(newRouter)
if err != nil {
glog.Error("Wrong annotations, missing key or value")
response.WriteHeaderAndEntity(http.StatusBadRequest,
constants.MessageResponse{Message: "Wrong annotations, missing key or value"})
return
}
router, err = models.CreateRouter(namespace, serviceType, annotationMap)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
} else {
response.WriteAsJson(*router)
}
}
// Delete ingress controller and services
func DeleteRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
router, err := models.DeleteRouter(namespace)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
} else {
response.WriteAsJson(router)
}
}
func UpdateRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
newRouter := Router{}
err := request.ReadEntity(&newRouter)
if err != nil {
glog.Error(err)
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
serviceType, annotationMap, err := ParseParameter(newRouter)
router, err := models.UpdateRouter(namespace, serviceType, annotationMap)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
} else {
response.WriteAsJson(router)
}
}
func ParseParameter(router Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) {
routerType = v1.ServiceTypeNodePort
if strings.Compare(strings.ToLower(router.RouterType), "loadbalancer") == 0 {
return v1.ServiceTypeLoadBalancer, router.Annotations, nil
} else {
return v1.ServiceTypeNodePort, make(map[string]string, 0), nil
}
}

View File

@@ -1,56 +0,0 @@
/*
Copyright 2018 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 statefulsets
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"statefulsets"}
ws.Route(ws.GET(subPath).To(getDaemonSetRevision).Consumes("*/*").Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Handle statefulset" +
" operation").Param(ws.PathParameter("statefulset", "statefulset's name").DataType("string")).Param(ws.PathParameter("namespace",
"statefulset's namespace").DataType("string")).Param(ws.PathParameter("revision", "statefulset's revision")).Writes(v1.StatefulSet{}))
}
func getDaemonSetRevision(req *restful.Request, resp *restful.Response) {
statefulset := req.PathParameter("statefulset")
namespace := req.PathParameter("namespace")
revision := req.PathParameter("revision")
res, err := models.GetStatefulSetRevision(namespace, statefulset, revision)
if err != nil {
if errors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: err.Error()})
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
}
resp.WriteEntity(res)
}

View File

@@ -1,61 +0,0 @@
package storage
import (
"net/http"
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath+"/storageclasses/{storageclass}/persistentvolumeclaims").
To(GetPvcListBySc).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/storageclasses/{storageclass}/metrics").
To(GetScMetrics).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/storageclasses/metrics").
To(GetScMetricsList).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}
// List all PersistentVolumeClaims of a specific StorageClass
// Extended API URL: "GET /api/v1alpha1/storage/storageclasses/{storageclass}/persistentvolumeclaims"
func GetPvcListBySc(request *restful.Request, response *restful.Response) {
scName := request.PathParameter("storageclass")
claims, err := models.GetPvcListBySc(scName)
if err != nil {
response.WriteError(http.StatusInternalServerError, err)
}
result := models.PvcListBySc{scName, claims}
response.WriteAsJson(result)
}
// Get StorageClass item
// Extended API URL: "GET /api/v1alpha1/storage/storageclasses/{storageclass}/metrics"
func GetScMetrics(request *restful.Request, response *restful.Response) {
scName := request.PathParameter("storageclass")
result, err := models.GetScItemMetrics(scName)
if err != nil {
response.WriteError(http.StatusInternalServerError, err)
}
response.WriteAsJson(result)
}
// Get StorageClass item list
// Extended API URL: "GET /api/v1alpha1/storage/storageclasses/metrics"
func GetScMetricsList(request *restful.Request, response *restful.Response) {
result, err := models.GetScItemMetricsList()
if err != nil {
response.WriteError(http.StatusInternalServerError, err)
}
response.WriteAsJson(result)
}

View File

@@ -1,44 +0,0 @@
// Copyright 2018 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 terminal
import (
"github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath).To(handleExecShell))
}
func handleExecShell(req *restful.Request, resp *restful.Response) {
res, err := models.HandleExecShell(req)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
}
resp.WriteEntity(res)
}
func RegisterWebSocketHandler(container *restful.Container, path string) {
handler := models.CreateTerminalHandler(path[0 : len(path)-1])
container.Handle(path, handler)
}

View File

@@ -1,108 +0,0 @@
/*
Copyright 2018 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 user
import (
"net/http"
"github.com/emicklei/go-restful"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"github.com/emicklei/go-restful-openapi"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/kubectl"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"users"}
ws.Route(ws.POST(subPath).Doc("create user").Param(ws.PathParameter("user",
"the username to be created").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).
To(createUser).Consumes("*/*").Produces(restful.MIME_JSON))
ws.Route(ws.DELETE(subPath).Doc("delete user").Param(ws.PathParameter("user",
"the username to be deleted").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(delUser).Produces(restful.MIME_JSON))
ws.Route(ws.GET(subPath+"/kubectl").Doc("get user's kubectl pod").Param(ws.PathParameter("user",
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(getKubectl).Produces(restful.MIME_JSON))
ws.Route(ws.GET(subPath+"/kubeconfig").Doc("get users' kubeconfig").Param(ws.PathParameter("user",
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(getKubeconfig).Produces(restful.MIME_JSON))
}
func createUser(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user")
err := models.CreateKubeConfig(user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(constants.MessageResponse{Message: "successfully created"})
}
func delUser(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user")
err := kubectl.DelKubectlDeploy(user)
if err != nil && !apierrors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
err = models.DelKubeConfig(user)
if err != nil && !apierrors.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(constants.MessageResponse{Message: "successfully deleted"})
}
func getKubectl(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user")
kubectlPod, err := kubectl.GetKubectlPod(user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(kubectlPod)
}
func getKubeconfig(req *restful.Request, resp *restful.Response) {
user := req.PathParameter("user")
kubectlConfig, err := models.GetKubeConfig(user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(kubectlConfig)
}

View File

@@ -1,30 +0,0 @@
package volumes
import (
"net/http"
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/filter/route"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath+"/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").
To(GetPodListByPvc).Filter(route.RouteLogging)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}
// List all pods of a specific PVC
// Extended API URL: "GET /api/v1alpha1/volumes/namespaces/{namespace}/persistentvolumeclaims/{name}/pods"
func GetPodListByPvc(request *restful.Request, response *restful.Response) {
pvcName := request.PathParameter("pvc")
nsName := request.PathParameter("namespace")
pods, err := models.GetPodListByPvc(pvcName, nsName)
if err != nil {
response.WriteError(http.StatusInternalServerError, err)
}
result := models.PodListByPvc{Name: pvcName, Namespace: nsName, Pods: pods}
response.WriteAsJson(result)
}

View File

@@ -1,54 +0,0 @@
/*
Copyright 2018 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 workloadstatus
import (
"net/http"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
func Register(ws *restful.WebService, subPath string) {
tags := []string{"workloadStatus"}
ws.Route(ws.GET(subPath).Doc("get abnormal workloads' count of whole cluster").Metadata(restfulspec.KeyOpenAPITags, tags).To(getClusterStatus).Produces(restful.MIME_JSON))
ws.Route(ws.GET(subPath+"/namespaces/{namespace}").Doc("get abnormal workloads' count of specified namespace").Param(ws.PathParameter("namespace",
"the name of namespace").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(getNamespaceStatus).Produces(restful.MIME_JSON))
}
func getClusterStatus(req *restful.Request, resp *restful.Response) {
res, err := models.GetClusterResourceStatus()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
resp.WriteEntity(res)
}
func getNamespaceStatus(req *restful.Request, resp *restful.Response) {
res, err := models.GetNamespacesResourceStatus(req.PathParameter("namespace"))
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
}
resp.WriteEntity(res)
}

View File

@@ -1,536 +0,0 @@
package workspaces
import (
"net/http"
"github.com/emicklei/go-restful"
"k8s.io/api/core/v1"
"fmt"
"strings"
"k8s.io/kubernetes/pkg/util/slice"
"strconv"
"regexp"
"sort"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/metrics"
"kubesphere.io/kubesphere/pkg/models/workspaces"
)
const UserNameHeader = "X-Token-Username"
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath).To(UserWorkspaceListHandler))
ws.Route(ws.POST(subPath).To(WorkspaceCreateHandler))
ws.Route(ws.DELETE(subPath + "/{name}").To(DeleteWorkspaceHandler))
ws.Route(ws.GET(subPath + "/{name}").To(WorkspaceDetailHandler))
ws.Route(ws.PUT(subPath + "/{name}").To(WorkspaceEditHandler))
ws.Route(ws.GET(subPath + "/{workspace}/namespaces").To(UserNamespaceListHandler))
ws.Route(ws.GET(subPath + "/{workspace}/members/{username}/namespaces").To(UserNamespaceListHandler))
ws.Route(ws.POST(subPath + "/{name}/namespaces").To(NamespaceCreateHandler))
ws.Route(ws.DELETE(subPath + "/{name}/namespaces/{namespace}").To(NamespaceDeleteHandler))
ws.Route(ws.GET(subPath + "/{name}/namespaces/{namespace}").To(NamespaceCheckHandler))
ws.Route(ws.GET("/namespaces/{namespace}").To(NamespaceCheckHandler))
ws.Route(ws.GET(subPath + "/{name}/devops").To(DevOpsProjectHandler))
ws.Route(ws.GET(subPath + "/{name}/members/{username}/devops").To(DevOpsProjectHandler))
ws.Route(ws.POST(subPath + "/{name}/devops").To(DevOpsProjectCreateHandler))
ws.Route(ws.DELETE(subPath + "/{name}/devops/{id}").To(DevOpsProjectDeleteHandler))
ws.Route(ws.GET(subPath + "/{name}/members").To(MembersHandler))
ws.Route(ws.GET(subPath + "/{name}/members/{member}").To(MemberHandler))
ws.Route(ws.GET(subPath + "/{name}/roles").To(RolesHandler))
ws.Route(ws.GET(subPath + "/{name}/roles/{role}").To(RoleHandler))
ws.Route(ws.POST(subPath + "/{name}/members").To(MembersInviteHandler))
ws.Route(ws.DELETE(subPath + "/{name}/members").To(MembersRemoveHandler))
}
func RoleHandler(req *restful.Request, resp *restful.Response) {
workspaceName := req.PathParameter("name")
roleName := req.PathParameter("role")
if !slice.ContainsString(constants.WorkSpaceRoles, roleName, nil) {
resp.WriteHeaderAndEntity(http.StatusNotFound, constants.MessageResponse{Message: fmt.Sprintf("role %s not found", roleName)})
return
}
role, rules, err := iam.WorkspaceRoleRules(workspaceName, roleName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
users, err := iam.WorkspaceRoleUsers(workspaceName, roleName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(map[string]interface{}{"role": role, "rules": rules, "users": users})
}
func RolesHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
roles, err := workspaces.Roles(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(roles)
}
func MembersHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
keyword := req.QueryParameter("keyword")
users, err := workspaces.GetWorkspaceMembers(workspace, keyword)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(users)
}
func MemberHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("member")
user, err := iam.GetUser(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
namespaces, err := workspaces.Namespaces(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
user.WorkspaceRole = user.WorkspaceRoles[workspace]
roles := make(map[string]string)
for _, namespace := range namespaces {
if role := user.Roles[namespace.Name]; role != "" {
roles[namespace.Name] = role
}
}
user.Roles = roles
user.Rules = nil
user.WorkspaceRules = nil
user.WorkspaceRoles = nil
user.ClusterRules = nil
resp.WriteEntity(user)
}
func MembersInviteHandler(req *restful.Request, resp *restful.Response) {
var users []workspaces.UserInvite
workspace := req.PathParameter("name")
err := req.ReadEntity(&users)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
err = workspaces.Invite(workspace, users)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteHeaderAndEntity(http.StatusOK, constants.MessageResponse{Message: "success"})
}
func MembersRemoveHandler(req *restful.Request, resp *restful.Response) {
query := req.QueryParameter("name")
workspace := req.PathParameter("name")
names := strings.Split(query, ",")
err := workspaces.RemoveMembers(workspace, names)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteHeaderAndEntity(http.StatusOK, constants.MessageResponse{Message: "success"})
}
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
exist, err := workspaces.NamespaceExistCheck(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(map[string]bool{"exist": exist})
}
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
workspace := req.PathParameter("name")
err := workspaces.DeleteNamespace(workspace, namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteHeaderAndEntity(http.StatusOK, constants.MessageResponse{Message: "success"})
}
func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
devops := req.PathParameter("id")
workspace := req.PathParameter("name")
force := req.QueryParameter("force")
username := req.HeaderParameter(UserNameHeader)
err := workspaces.UnBindDevopsProject(workspace, devops)
if err != nil && force != "true" {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
err = workspaces.DeleteDevopsProject(username, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(constants.MessageResponse{Message: "success"})
}
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
var devops workspaces.DevopsProject
err := req.ReadEntity(&devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(project)
}
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
namespace := &v1.Namespace{}
err := req.ReadEntity(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
if namespace.Annotations == nil {
namespace.Annotations = make(map[string]string, 0)
}
namespace.Annotations["creator"] = username
namespace.Annotations["workspace"] = workspace
if namespace.Labels == nil {
namespace.Labels = make(map[string]string, 0)
}
namespace.Labels["kubesphere.io/workspace"] = workspace
namespace, err = workspaces.CreateNamespace(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(namespace)
}
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("username")
keyword := req.QueryParameter("keyword")
if username == "" {
username = req.HeaderParameter(UserNameHeader)
}
limit := 65535
offset := 0
orderBy := "createTime"
reverse := true
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
offset = (page - 1) * limit
}
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
orderBy = groups[1]
reverse = false
}
if q := req.QueryParameter("reverse"); q != "" {
b, err := strconv.ParseBool(q)
if err == nil {
reverse = b
}
}
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
result := constants.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range devOpsProjects {
result.Items = append(result.Items, n)
}
resp.WriteEntity(result)
}
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
var workspace workspaces.Workspace
username := req.HeaderParameter(UserNameHeader)
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid workspace name"})
return
}
workspace.Path = workspace.Name
workspace.Members = nil
if workspace.Admin != "" {
workspace.Creator = workspace.Admin
} else {
workspace.Creator = username
}
created, err := workspaces.Create(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(created)
}
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
if name == "" || strings.Contains(name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid workspace name"})
return
}
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
err = workspaces.Delete(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(constants.MessageResponse{Message: "success"})
}
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
var workspace workspaces.Workspace
name := req.PathParameter("name")
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
if name != workspace.Name {
resp.WriteError(http.StatusBadRequest, fmt.Errorf("the name of workspace (%s) does not match the name on the URL (%s)", workspace.Name, name))
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid workspace name"})
return
}
workspace.Path = workspace.Name
workspace.Members = nil
edited, err := workspaces.Edit(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(edited)
}
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(workspace)
}
// List all workspaces for the current user
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
keyword := req.QueryParameter("keyword")
username := req.HeaderParameter(UserNameHeader)
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
sort.Slice(ws, func(i, j int) bool {
t1, err := ws[i].GetCreateTime()
if err != nil {
return false
}
t2, err := ws[j].GetCreateTime()
if err != nil {
return true
}
return t1.After(t2)
})
resp.WriteEntity(ws)
}
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
withMetrics, err := strconv.ParseBool(req.QueryParameter("metrics"))
if err != nil {
withMetrics = false
}
username := req.PathParameter("username")
keyword := req.QueryParameter("keyword")
if username == "" {
username = req.HeaderParameter(UserNameHeader)
}
limit := 65535
offset := 0
orderBy := "createTime"
reverse := true
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
if page < 0 {
page = 1
}
offset = (page - 1) * limit
}
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
orderBy = groups[1]
reverse = false
}
if q := req.QueryParameter("reverse"); q != "" {
b, err := strconv.ParseBool(q)
if err == nil {
reverse = b
}
}
workspaceName := req.PathParameter("workspace")
total, namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username, keyword, orderBy, reverse, limit, offset)
if withMetrics {
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
result := constants.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range namespaces {
result.Items = append(result.Items, n)
}
resp.WriteEntity(result)
}

View File

@@ -1,189 +0,0 @@
/*
Copyright 2018 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 app
import (
"crypto/tls"
"fmt"
"github.com/emicklei/go-restful"
"github.com/golang/glog"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net"
"net/http"
"github.com/emicklei/go-restful-openapi"
"github.com/go-openapi/spec"
"k8s.io/apimachinery/pkg/api/errors"
"os"
"os/signal"
"sync"
"syscall"
"k8s.io/api/core/v1"
_ "kubesphere.io/kubesphere/pkg/apis/v1alpha"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/controllers"
"kubesphere.io/kubesphere/pkg/models/kubectl"
"kubesphere.io/kubesphere/pkg/models/workspaces"
"kubesphere.io/kubesphere/pkg/options"
)
type kubeSphereServer struct {
insecureBindAddress net.IP
bindAddress net.IP
insecurePort int
port int
certFile string
keyFile string
container *restful.Container
}
func newKubeSphereServer(options *options.ServerRunOptions) *kubeSphereServer {
s := kubeSphereServer{
insecureBindAddress: options.GetInsecureBindAddress(),
bindAddress: options.GetBindAddress(),
insecurePort: options.GetInsecurePort(),
port: options.GetPort(),
certFile: options.GetCertFile(),
keyFile: options.GetKeyFile(),
}
return &s
}
func preCheck() error {
k8sClient := client.NewK8sClient()
_, err := k8sClient.CoreV1().Namespaces().Get(constants.KubeSphereControlNamespace, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
_, err = k8sClient.CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metaV1.ObjectMeta{Name: constants.KubeSphereControlNamespace}})
if err != nil {
return err
}
} else {
return err
}
}
_, err = k8sClient.AppsV1().Deployments(constants.KubeSphereControlNamespace).Get(constants.AdminUserName, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
if err = models.CreateKubeConfig(constants.AdminUserName); err != nil {
return err
}
if err = kubectl.CreateKubectlDeploy(constants.AdminUserName); err != nil {
return err
}
} else {
return err
}
}
db := client.NewSharedDBClient()
defer db.Close()
if !db.HasTable(&workspaces.WorkspaceDPBinding{}) {
if err := db.CreateTable(&workspaces.WorkspaceDPBinding{}).Error; err != nil {
return err
}
}
return nil
}
func registerSwagger() {
config := restfulspec.Config{
WebServices: restful.RegisteredWebServices(), // you control what services are visible
APIPath: "/swagger-ui/api.json",
PostBuildSwaggerObjectHandler: enrichSwaggerObject}
restful.DefaultContainer.Add(restfulspec.NewOpenAPIService(config))
http.Handle("/swagger-ui/", http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir("/usr/lib/kubesphere/swagger-ui"))))
}
func enrichSwaggerObject(swo *spec.Swagger) {
swo.Info = &spec.Info{
InfoProps: spec.InfoProps{
Title: "KubeSphere",
Description: "The extend apis of kubesphere",
Version: "v1.0-alpha",
},
}
swo.Tags = []spec.Tag{spec.Tag{TagProps: spec.TagProps{
Name: "extend apis"}}}
}
func (server *kubeSphereServer) run() {
err := preCheck()
if err != nil {
glog.Error(err)
return
}
var wg sync.WaitGroup
stopChan := make(chan struct{})
wg.Add(1)
go controllers.Run(stopChan, &wg)
registerSwagger()
if len(server.certFile) > 0 && len(server.keyFile) > 0 {
servingCert, err := tls.LoadX509KeyPair(server.certFile, server.keyFile)
if err != nil {
glog.Error(err)
return
}
secureAddr := fmt.Sprintf("%s:%d", server.bindAddress, server.port)
glog.Infof("Serving securely on addr: %s", secureAddr)
httpServer := &http.Server{
Addr: secureAddr,
Handler: restful.DefaultContainer,
TLSConfig: &tls.Config{Certificates: []tls.Certificate{servingCert}},
}
go func() { glog.Fatal(httpServer.ListenAndServeTLS("", "")) }()
} else {
insecureAddr := fmt.Sprintf("%s:%d", server.insecureBindAddress, server.insecurePort)
glog.Infof("Serving insecurely on addr: %s", insecureAddr)
go func() { glog.Fatal(http.ListenAndServe(insecureAddr, nil)) }()
}
sigs := make(chan os.Signal)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
<-sigs
close(stopChan)
wg.Wait()
}
func Run() {
server := newKubeSphereServer(options.ServerOptions)
server.run()
}

View File

@@ -1,63 +0,0 @@
/*
Copyright 2018 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 client
import (
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
"github.com/golang/glog"
"github.com/jinzhu/gorm"
"kubesphere.io/kubesphere/pkg/logs"
"kubesphere.io/kubesphere/pkg/options"
)
var dbClient *gorm.DB
const database = "kubesphere"
func NewDBClient() *gorm.DB {
user := options.ServerOptions.GetMysqlUser()
passwd := options.ServerOptions.GetMysqlPassword()
addr := options.ServerOptions.GetMysqlAddr()
conn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, passwd, addr, database)
db, err := gorm.Open("mysql", conn)
if err != nil {
glog.Error(err)
panic(err)
}
db.SetLogger(log.New(logs.GlogWriter{}, " ", 0))
return db
}
func NewSharedDBClient() *gorm.DB {
if dbClient != nil {
err := dbClient.DB().Ping()
if err == nil {
return dbClient
} else {
glog.Error(err)
panic(err)
}
}
return NewDBClient()
}

View File

@@ -1,130 +0,0 @@
/*
Copyright 2018 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 client
import (
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/pkg/transport"
"context"
"fmt"
"time"
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
"github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/options"
)
type EtcdClient struct {
cli *clientv3.Client
}
func (cli EtcdClient) Put(key, value string) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(10)*time.Second)
_, err := cli.cli.Put(ctx, key, value)
cancel()
if err != nil {
switch err {
case context.Canceled:
glog.Errorf("ctx is canceled by another routine: %v\n", err)
case context.DeadlineExceeded:
glog.Errorf("ctx is attached with a deadline is exceeded: %v\n", err)
case rpctypes.ErrEmptyKey:
glog.Errorf("client-side error: %v\n", err)
default:
glog.Errorf("bad cluster endpoints, which are not etcd servers: %v\n", err)
}
return err
}
return nil
}
func (cli EtcdClient) Get(key string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(10)*time.Second)
resp, err := cli.cli.Get(ctx, key)
cancel()
if err != nil {
glog.Error(err)
return nil, err
}
if len(resp.Kvs) == 0 {
return nil, fmt.Errorf("empty value of key: %s", key)
}
return resp.Kvs[0].Value, nil
}
func (cli EtcdClient) Close() {
cli.cli.Close()
}
func newEtcdClientWithHttps(certFile, keyFile, caFile string, endpoints []string, dialTimeout int) (*clientv3.Client, error) {
tlsInfo := transport.TLSInfo{
CertFile: certFile,
KeyFile: keyFile,
TrustedCAFile: caFile,
}
tlsConfig, err := tlsInfo.ClientConfig()
if err != nil {
glog.Errorln(err)
return nil, err
}
cli, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: time.Duration(dialTimeout) * time.Second,
TLS: tlsConfig,
})
if err != nil {
glog.Errorln(err)
return nil, err
}
return cli, nil // make sure to close the client
}
func newEtcdClient(endpoints []string, dialTimeout int) (*clientv3.Client, error) {
cli, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: time.Duration(dialTimeout) * time.Second,
})
if err != nil {
glog.Errorln(err)
return nil, err
}
return cli, nil // make sure to close the client
}
func NewEtcdClient() (*EtcdClient, error) {
var cli *clientv3.Client
var err error
cert := options.ServerOptions.GetEtcdCertFile()
key := options.ServerOptions.GetEtcdKeyFile()
ca := options.ServerOptions.GetEtcdCaFile()
endpoints := options.ServerOptions.GetEtcdEndPoints()
if len(cert) > 0 && len(key) > 0 && len(ca) > 0 {
cli, err = newEtcdClientWithHttps(cert, key, ca, endpoints, 20)
} else {
cli, err = newEtcdClient(endpoints, 20)
}
if err != nil {
return nil, err
}
return &EtcdClient{cli}, nil
}

View File

@@ -1,101 +0,0 @@
/*
Copyright 2018 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 client
import (
"net/http"
"io/ioutil"
"time"
"github.com/antonholmquist/jason"
"github.com/golang/glog"
)
const (
DefaultHeapsterScheme = "http"
DefaultHeapsterService = "heapster.kube-system.svc.cluster.local" //"heapster"
DefaultHeapsterPort = "80" // use the first exposed port on the service
HeapsterApiPath = "/api/v1/model"
HeapsterEndpointUrl = DefaultHeapsterScheme + "://" + DefaultHeapsterService + ":" + DefaultHeapsterPort + HeapsterApiPath
)
var httpClient = &http.Client{Timeout: 30 * time.Second}
// Get heapster response in python-like dictionary
func GetHeapsterMetricsJson(url string) *jason.Object {
response, err := httpClient.Get(HeapsterEndpointUrl + url)
var data *jason.Object
if err != nil {
glog.Error(url, err)
} else {
defer response.Body.Close()
data, err = jason.NewObjectFromReader(response.Body)
if err != nil {
glog.Error(url, err)
}
}
// return empty json in case of error response from es-node
if data == nil {
emptyJSON := `{}`
data, _ = jason.NewObjectFromBytes([]byte(emptyJSON))
}
return data
}
func GetHeapsterMetrics(url string) string {
response, err := httpClient.Get(HeapsterEndpointUrl + url)
if err != nil {
glog.Error(err)
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
glog.Error(err)
}
return string(contents)
}
return ""
}
func GetCAdvisorMetrics(nodeAddr string) string {
response, err := httpClient.Get("http://" + nodeAddr + ":10255/stats/summary")
if err != nil {
glog.Error(err)
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
glog.Error(err)
}
return string(contents)
}
return ""
}

View File

@@ -1,42 +0,0 @@
/*
Copyright 2018 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 client
import (
"github.com/golang/glog"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/options"
)
var k8sClient *kubernetes.Clientset
func NewK8sClient() *kubernetes.Clientset {
if k8sClient != nil {
return k8sClient
}
kubeConfig, err := options.ServerOptions.GetKubeConfig()
if err != nil {
glog.Error(err)
panic(err)
}
k8sClient, err = kubernetes.NewForConfig(kubeConfig)
if err != nil {
glog.Error(err)
panic(err)
}
return k8sClient
}

View File

@@ -1,198 +0,0 @@
/*
Copyright 2018 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 client
import (
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"os"
"github.com/emicklei/go-restful"
"github.com/golang/glog"
)
const (
DefaultScheme = "http"
DefaultPrometheusPort = "9090"
PrometheusApiPath = "/api/v1/"
DefaultQueryStep = "10m"
DefaultQueryTimeout = "10s"
RangeQueryType = "query_range?"
DefaultQueryType = "query?"
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
)
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
var PrometheusEndpointUrl string
func init() {
if env := os.Getenv(PrometheusAPIServerEnv); env != "" {
PrometheusAPIServer = env
}
PrometheusEndpointUrl = DefaultScheme + "://" + PrometheusAPIServer + ":" + DefaultPrometheusPort + PrometheusApiPath
}
type MonitoringRequestParams struct {
Params url.Values
QueryType string
SortMetricName string
SortType string
PageNum string
LimitNum string
Tp string
MetricsFilter string
NodesFilter string
WsFilter string
NsFilter string
PodsFilter string
ContainersFilter string
MetricsName string
WorkloadName string
WlFilter string
NodeId string
WsName string
NsName string
PodName string
ContainerName string
WorkloadKind string
}
var client = &http.Client{}
func SendMonitoringRequest(queryType string, params string) string {
epurl := PrometheusEndpointUrl + queryType + params
response, err := client.Get(epurl)
if err != nil {
glog.Error(err)
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
glog.Error(err)
}
return string(contents)
}
return ""
}
func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestParams {
instantTime := strings.Trim(request.QueryParameter("time"), " ")
start := strings.Trim(request.QueryParameter("start"), " ")
end := strings.Trim(request.QueryParameter("end"), " ")
step := strings.Trim(request.QueryParameter("step"), " ")
timeout := strings.Trim(request.QueryParameter("timeout"), " ")
sortMetricName := strings.Trim(request.QueryParameter("sort_metric"), " ")
sortType := strings.Trim(request.QueryParameter("sort_type"), " ")
pageNum := strings.Trim(request.QueryParameter("page"), " ")
limitNum := strings.Trim(request.QueryParameter("limit"), " ")
tp := strings.Trim(request.QueryParameter("type"), " ")
metricsFilter := strings.Trim(request.QueryParameter("metrics_filter"), " ")
nodesFilter := strings.Trim(request.QueryParameter("nodes_filter"), " ")
wsFilter := strings.Trim(request.QueryParameter("workspaces_filter"), " ")
nsFilter := strings.Trim(request.QueryParameter("namespaces_filter"), " ")
wlFilter := strings.Trim(request.QueryParameter("workloads_filter"), " ")
podsFilter := strings.Trim(request.QueryParameter("pods_filter"), " ")
containersFilter := strings.Trim(request.QueryParameter("containers_filter"), " ")
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
nodeId := strings.Trim(request.PathParameter("node_id"), " ")
wsName := strings.Trim(request.PathParameter("workspace_name"), " ")
nsName := strings.Trim(request.PathParameter("ns_name"), " ")
podName := strings.Trim(request.PathParameter("pod_name"), " ")
containerName := strings.Trim(request.PathParameter("container_name"), " ")
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
var requestParams = MonitoringRequestParams{
SortMetricName: sortMetricName,
SortType: sortType,
PageNum: pageNum,
LimitNum: limitNum,
Tp: tp,
MetricsFilter: metricsFilter,
NodesFilter: nodesFilter,
WsFilter: wsFilter,
NsFilter: nsFilter,
PodsFilter: podsFilter,
ContainersFilter: containersFilter,
MetricsName: metricsName,
WorkloadName: workloadName,
WlFilter: wlFilter,
NodeId: nodeId,
WsName: wsName,
NsName: nsName,
PodName: podName,
ContainerName: containerName,
WorkloadKind: workloadKind,
}
if timeout == "" {
timeout = DefaultQueryTimeout
}
if step == "" {
step = DefaultQueryStep
}
// Whether query or query_range request
u := url.Values{}
if start != "" && end != "" {
u.Set("start", convertTimeGranularity(start))
u.Set("end", convertTimeGranularity(end))
u.Set("step", step)
u.Set("timeout", timeout)
requestParams.QueryType = RangeQueryType
requestParams.Params = u
return &requestParams
}
if instantTime != "" {
u.Set("time", instantTime)
u.Set("timeout", timeout)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u
return &requestParams
} else {
//u.Set("time", strconv.FormatInt(int64(time.Now().Unix()), 10))
u.Set("timeout", timeout)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u
return &requestParams
}
glog.Errorln("Parse request %s failed", u)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u
return &requestParams
}
func convertTimeGranularity(ts string) string {
timeFloat, err := strconv.ParseFloat(ts, 64)
if err != nil {
glog.Errorf("convert second timestamp %s to minute timestamp failed", ts)
return strconv.FormatInt(int64(time.Now().Unix()), 10)
}
timeInt := int64(timeFloat)
// convert second timestamp to minute timestamp
secondTime := time.Unix(timeInt, 0).Truncate(time.Minute).Unix()
return strconv.FormatInt(secondTime, 10)
}

View File

@@ -1,77 +0,0 @@
/*
Copyright 2018 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 constants
import "os"
type MessageResponse struct {
Message string `json:"message"`
}
type PageableResponse struct {
Items []interface{} `json:"items"`
TotalCount int `json:"total_count"`
}
const (
APIVersion = "v1alpha1"
KubeSystemNamespace = "kube-system"
OpenPitrixNamespace = "openpitrix-system"
IstioNamespace = "istio-system"
KubeSphereNamespace = "kubesphere-system"
KubeSphereControlNamespace = "kubesphere-controls-system"
IngressControllerNamespace = KubeSphereControlNamespace
AdminUserName = "admin"
DataHome = "/etc/kubesphere"
IngressControllerFolder = DataHome + "/ingress-controller"
IngressControllerPrefix = "kubesphere-router-"
DevopsAPIServerEnv = "DEVOPS_API_SERVER"
AccountAPIServerEnv = "ACCOUNT_API_SERVER"
DevopsProxyTokenEnv = "DEVOPS_PROXY_TOKEN"
OpenPitrixProxyTokenEnv = "OPENPITRIX_PROXY_TOKEN"
WorkspaceLabelKey = "kubesphere.io/workspace"
WorkspaceAdmin = "workspace-admin"
ClusterAdmin = "cluster-admin"
WorkspaceRegular = "workspace-regular"
WorkspaceViewer = "workspace-viewer"
DevopsOwner = "owner"
DevopsReporter = "reporter"
)
var (
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
AccountAPIServer = "ks-account.kubesphere-system.svc"
DevopsProxyToken = ""
OpenPitrixProxyToken = ""
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
)
func init() {
if env := os.Getenv(DevopsAPIServerEnv); env != "" {
DevopsAPIServer = env
}
if env := os.Getenv(AccountAPIServerEnv); env != "" {
AccountAPIServer = env
}
if env := os.Getenv(DevopsProxyTokenEnv); env != "" {
DevopsProxyToken = env
}
if env := os.Getenv(OpenPitrixProxyTokenEnv); env != "" {
OpenPitrixProxyToken = env
}
}

View File

@@ -1,25 +0,0 @@
/*
Copyright 2018 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 container
import "github.com/emicklei/go-restful"
// add filter to default container
func init() {
restful.Filter(logFilter())
}

View File

@@ -1,41 +0,0 @@
/*
Copyright 2018 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 container
import (
"strings"
"time"
"github.com/emicklei/go-restful"
"github.com/golang/glog"
)
func logFilter() restful.FilterFunction {
return func(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
start := time.Now()
chain.ProcessFilter(req, resp)
glog.Infof("%s - \"%s %s %s\" %d %d in %dms",
strings.Split(req.Request.RemoteAddr, ":")[0],
req.Request.Method,
req.Request.URL.RequestURI(),
req.Request.Proto,
resp.StatusCode(),
resp.ContentLength(),
time.Since(start)/time.Millisecond,
)
}
}

View File

@@ -1,41 +0,0 @@
/*
Copyright 2018 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 route
import (
"strings"
"time"
"github.com/emicklei/go-restful"
"github.com/golang/glog"
)
// Route Filter (defines FilterFunction)
func RouteLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
start := time.Now()
chain.ProcessFilter(req, resp)
glog.Infof("%s - \"%s %s %s\" %d %dms",
strings.Split(req.Request.RemoteAddr, ":")[0],
req.Request.Method,
req.Request.URL.RequestURI(),
req.Request.Proto,
resp.StatusCode(),
time.Now().Sub(start)/1000000,
)
}

View File

@@ -1,52 +0,0 @@
/*
Copyright 2018 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 logs
import (
"flag"
"log"
"github.com/golang/glog"
)
func init() {
flag.Set("logtostderr", "true")
}
// GlogWriter serves as a bridge between the standard log package and the glog package.
type GlogWriter struct{}
// Write implements the io.Writer interface.
func (writer GlogWriter) Write(data []byte) (n int, err error) {
glog.Info(string(data))
return len(data), nil
}
// InitLogs initializes logs the way we want for kubeSphere.
func InitLogs() {
log.SetOutput(GlogWriter{})
log.SetFlags(0)
}
// FlushLogs flushes logs immediately.
func FlushLogs() {
glog.Flush()
}

View File

@@ -1,244 +0,0 @@
/*
Copyright 2018 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 models
import (
"time"
v13 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/client"
v12 "k8s.io/client-go/listers/core/v1"
"kubesphere.io/kubesphere/pkg/models/controllers"
"k8s.io/apimachinery/pkg/labels"
"github.com/golang/glog"
)
// Namespaces need to watch
var SYSTEM_NAMESPACES = [...]string{"kubesphere-system", "openpitrix-system", "kube-system"}
type Component struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
SelfLink string `json:"selfLink"`
Label interface{} `json:"label"`
StartedAt time.Time `json:"startedAt"`
TotalBackends int `json:"totalBackends"`
HealthyBackends int `json:"healthyBackends"`
}
func GetComponentStatus(namespace string, componentName string) (interface{}, error) {
lister, err := controllers.GetLister(controllers.Services)
if err != nil {
glog.Errorln(err)
return nil, err
}
serviceLister := lister.(v12.ServiceLister)
service, err := serviceLister.Services(namespace).Get(componentName)
if err != nil {
glog.Error(err)
return nil, err
}
lister, err = controllers.GetLister(controllers.Pods)
if err != nil {
glog.Errorln(err)
return nil, err
}
podLister := lister.(v12.PodLister)
set := labels.Set(service.Spec.Selector)
pods, err := podLister.Pods(namespace).List(set.AsSelector())
if err != nil {
glog.Errorln(err)
return nil, err
} else {
component := Component{
Name: service.Name,
Namespace: service.Namespace,
SelfLink: service.SelfLink,
Label: service.Spec.Selector,
StartedAt: service.CreationTimestamp.Time,
HealthyBackends: 0,
TotalBackends: 0,
}
for _, v := range pods {
component.TotalBackends++
component.HealthyBackends++
for _, c := range v.Status.ContainerStatuses {
if !c.Ready {
component.HealthyBackends--
break
}
}
}
return component, nil
}
}
func GetSystemHealthStatus() (map[string]interface{}, error) {
status := make(map[string]interface{})
k8sClient := client.NewK8sClient()
csList, err := k8sClient.Core().ComponentStatuses().List(v1.ListOptions{})
if err != nil {
glog.Errorln(err)
return nil, err
}
for _, cs := range csList.Items {
status[cs.Name] = cs.Conditions[0]
}
// get kubesphere-system components
systemComponentStatus, err := GetAllComponentsStatus()
if err != nil {
glog.Errorln(err)
}
for k, v := range systemComponentStatus {
status[k] = v
}
// get node status
lister, err := controllers.GetLister(controllers.Nodes)
if err != nil {
glog.Errorln(err)
return status, nil
}
nodeLister := lister.(v12.NodeLister)
nodes, err := nodeLister.List(labels.Everything())
if err != nil {
glog.Errorln(err)
return status, nil
}
nodeStatus := make(map[string]int)
totalNodes := 0
healthyNodes := 0
for _, nodes := range nodes {
totalNodes++
for _, condition := range nodes.Status.Conditions {
if condition.Type == v13.NodeReady && condition.Status == v13.ConditionTrue {
healthyNodes++
}
}
}
nodeStatus["totalNodes"] = totalNodes
nodeStatus["healthyNodes"] = healthyNodes
status["nodes"] = nodeStatus
return status, nil
}
func GetAllComponentsStatus() (map[string]interface{}, error) {
status := make(map[string]interface{})
var err error
lister, err := controllers.GetLister(controllers.Services)
if err != nil {
glog.Errorln(err)
return nil, err
}
serviceLister := lister.(v12.ServiceLister)
lister, err = controllers.GetLister(controllers.Pods)
if err != nil {
glog.Errorln(err)
return nil, err
}
podLister := lister.(v12.PodLister)
for _, ns := range SYSTEM_NAMESPACES {
nsStatus := make(map[string]interface{})
services, err := serviceLister.Services(ns).List(labels.Everything())
if err != nil {
glog.Error(err)
continue
}
for _, service := range services {
set := labels.Set(service.Spec.Selector)
if len(set) == 0 {
continue
}
component := Component{
Name: service.Name,
Namespace: service.Namespace,
SelfLink: service.SelfLink,
Label: service.Spec.Selector,
StartedAt: service.CreationTimestamp.Time,
HealthyBackends: 0,
TotalBackends: 0,
}
pods, err := podLister.Pods(ns).List(set.AsSelector())
if err != nil {
glog.Errorln(err)
continue
}
for _, pod := range pods {
component.TotalBackends++
component.HealthyBackends++
for _, c := range pod.Status.ContainerStatuses {
if !c.Ready {
component.HealthyBackends--
break
}
}
}
nsStatus[service.Name] = component
}
if len(nsStatus) > 0 {
status[ns] = nsStatus
}
}
return status, err
}

View File

@@ -1,490 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/client"
)
const (
unknown = "-"
deploySurffix = "-Deployment"
daemonSurffix = "-DaemonSet"
stateSurffix = "-StatefulSet"
)
type ApplicationCtl struct {
OpenpitrixAddr string
}
type Application struct {
Name string `json:"name"`
RepoName string `json:"repoName"`
Runtime string `json:"namespace"`
RuntimeId string `json:"runtime_id"`
Version string `json:"version"`
VersionId string `json:"version_id"`
Status string `json:"status"`
UpdateTime time.Time `json:"updateTime"`
CreateTime time.Time `json:"createTime"`
App string `json:"app"`
AppId string `json:"app_id"`
Description string `json:"description,omitempty"`
WorkLoads *workLoads `json:"workloads,omitempty"`
Services *[]Service `json:"services,omitempty"`
Ingresses *[]ing `json:"ingresses,omitempty"`
ClusterID string `json:"cluster_id"`
}
type ing struct {
Name string `json:"name"`
Rules []ingressRule `json:"rules"`
}
type clusterRole struct {
ClusterID string `json:"cluster_id"`
Role string `json:"role"`
}
type cluster struct {
ClusterID string `json:"cluster_id"`
Name string `json:"name"`
AppID string `json:"app_id"`
VersionID string `json:"version_id"`
Status string `json:"status"`
UpdateTime time.Time `json:"status_time"`
CreateTime time.Time `json:"create_time"`
RunTimeId string `json:"runtime_id"`
Description string `json:"description"`
ClusterRoleSets []clusterRole `json:"cluster_role_set"`
}
type clusters struct {
Total int `json:"total_count"`
Clusters []cluster `json:"cluster_set"`
}
type versionList struct {
Total int `json:"total_count"`
Versions []version `json:"app_version_set"`
}
type version struct {
Name string `json:"name"`
VersionID string `json:"version_id"`
}
type runtime struct {
RuntimeID string `json:"runtime_id"`
Zone string `json:"zone"`
}
type runtimeList struct {
Total int `json:"total_count"`
Runtimes []runtime `json:"runtime_set"`
}
type app struct {
AppId string `json:"app_id"`
Name string `json:"name"`
ChartName string `json:"chart_name"`
RepoId string `json:"repo_id"`
}
type repo struct {
RepoId string `json:"repo_id"`
Name string `json:"name"`
Url string `json:"url"`
}
type workLoads struct {
Deployments []Deployment `json:"deployments,omitempty"`
Statefulsets []Statefulset `json:"statefulsets,omitempty"`
Daemonsets []Daemonset `json:"daemonsets,omitempty"`
}
//type description struct {
// Creator string `json:"creator"`
//}
type appList struct {
Total int `json:"total_count"`
Apps []app `json:"app_set"`
}
type repoList struct {
Total int `json:"total_count"`
Repos []repo `json:"repo_set"`
}
func (ctl *ApplicationCtl) GetAppInfo(appId string) (string, string, string, error) {
url := fmt.Sprintf("%s/v1/apps?app_id=%s", ctl.OpenpitrixAddr, appId)
resp, err := makeHttpRequest("GET", url, "")
if err != nil {
glog.Error(err)
return unknown, unknown, unknown, err
}
var apps appList
err = json.Unmarshal(resp, &apps)
if err != nil {
glog.Error(err)
return unknown, unknown, unknown, err
}
if len(apps.Apps) == 0 {
return unknown, unknown, unknown, err
}
return apps.Apps[0].ChartName, apps.Apps[0].RepoId, apps.Apps[0].AppId, nil
}
func (ctl *ApplicationCtl) GetRepo(repoId string) (string, error) {
url := fmt.Sprintf("%s/v1/repos?repo_id=%s", ctl.OpenpitrixAddr, repoId)
resp, err := makeHttpRequest("GET", url, "")
if err != nil {
glog.Error(err)
return unknown, err
}
var repos repoList
err = json.Unmarshal(resp, &repos)
if err != nil {
glog.Error(err)
return unknown, err
}
if len(repos.Repos) == 0 {
return unknown, err
}
return repos.Repos[0].Name, nil
}
func (ctl *ApplicationCtl) GetVersion(versionId string) (string, error) {
versionUrl := fmt.Sprintf("%s/v1/app_versions?version_id=%s", ctl.OpenpitrixAddr, versionId)
resp, err := makeHttpRequest("GET", versionUrl, "")
if err != nil {
glog.Error(err)
return unknown, err
}
var versions versionList
err = json.Unmarshal(resp, &versions)
if err != nil {
glog.Error(err)
return unknown, err
}
if len(versions.Versions) == 0 {
return unknown, nil
}
return versions.Versions[0].Name, nil
}
func (ctl *ApplicationCtl) GetRuntime(runtimeId string) (string, error) {
versionUrl := fmt.Sprintf("%s/v1/runtimes?runtime_id=%s", ctl.OpenpitrixAddr, runtimeId)
resp, err := makeHttpRequest("GET", versionUrl, "")
if err != nil {
glog.Error(err)
return unknown, err
}
var runtimes runtimeList
err = json.Unmarshal(resp, &runtimes)
if err != nil {
glog.Error(err)
return unknown, err
}
if len(runtimes.Runtimes) == 0 {
return unknown, nil
}
return runtimes.Runtimes[0].Zone, nil
}
func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []clusterRole) *workLoads {
var works workLoads
for _, clusterRole := range clusterRoles {
workLoadName := clusterRole.Role
if len(workLoadName) > 0 {
if strings.HasSuffix(workLoadName, deploySurffix) {
name := strings.Split(workLoadName, deploySurffix)[0]
ctl := ResourceControllers.Controllers[Deployments]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "")
works.Deployments = append(works.Deployments, items.([]Deployment)...)
continue
}
if strings.HasSuffix(workLoadName, daemonSurffix) {
name := strings.Split(workLoadName, daemonSurffix)[0]
ctl := ResourceControllers.Controllers[Daemonsets]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "")
works.Daemonsets = append(works.Daemonsets, items.([]Daemonset)...)
continue
}
if strings.HasSuffix(workLoadName, stateSurffix) {
name := strings.Split(workLoadName, stateSurffix)[0]
ctl := ResourceControllers.Controllers[Statefulsets]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "")
works.Statefulsets = append(works.Statefulsets, items.([]Statefulset)...)
continue
}
}
}
return &works
}
func (ctl *ApplicationCtl) getLabels(namespace string, workloads *workLoads) *[]map[string]string {
k8sClient := client.NewK8sClient()
var workloadLables []map[string]string
if workloads == nil {
return nil
}
for _, workload := range workloads.Deployments {
deploy, err := k8sClient.AppsV1().Deployments(namespace).Get(workload.Name, metaV1.GetOptions{})
if errors.IsNotFound(err) {
continue
}
workloadLables = append(workloadLables, deploy.Labels)
}
for _, workload := range workloads.Daemonsets {
daemonset, err := k8sClient.AppsV1().DaemonSets(namespace).Get(workload.Name, metaV1.GetOptions{})
if errors.IsNotFound(err) {
continue
}
workloadLables = append(workloadLables, daemonset.Labels)
}
for _, workload := range workloads.Statefulsets {
statefulset, err := k8sClient.AppsV1().StatefulSets(namespace).Get(workload.Name, metaV1.GetOptions{})
if errors.IsNotFound(err) {
continue
}
workloadLables = append(workloadLables, statefulset.Labels)
}
return &workloadLables
}
func isExist(svcs []Service, svc v1.Service) bool {
for _, item := range svcs {
if item.Name == svc.Name && item.Namespace == svc.Namespace {
return true
}
}
return false
}
func (ctl *ApplicationCtl) getSvcs(namespace string, workLoadLabels *[]map[string]string) *[]Service {
if len(*workLoadLabels) == 0 {
return nil
}
k8sClient := client.NewK8sClient()
var services []Service
for _, label := range *workLoadLabels {
labelSelector := labels.Set(label).AsSelector().String()
svcs, err := k8sClient.CoreV1().Services(namespace).List(metaV1.ListOptions{LabelSelector: labelSelector})
if err != nil {
glog.Errorf("get app's svc failed, reason: %v", err)
}
for _, item := range svcs.Items {
if !isExist(services, item) {
services = append(services, *generateSvcObject(item))
}
}
}
return &services
}
func (ctl *ApplicationCtl) getIng(namespace string, services *[]Service) *[]ing {
if services == nil {
return nil
}
ingCtl := ResourceControllers.Controllers[Ingresses]
var ings []ing
for _, svc := range *services {
_, items, err := ingCtl.ListWithConditions(fmt.Sprintf("namespace = '%s' and rules like '%%%s%%' ", namespace, svc.Name), nil, "")
if err != nil {
glog.Error(err)
return nil
}
glog.Error(items)
for _, ingress := range items.([]Ingress) {
var rules []ingressRule
err := json.Unmarshal([]byte(ingress.Rules), &rules)
if err != nil {
return nil
}
exist := false
var tmpRules []ingressRule
for _, rule := range rules {
if rule.Service == svc.Name {
exist = true
tmpRules = append(tmpRules, rule)
}
}
if exist {
ings = append(ings, ing{Name: ingress.Name, Rules: tmpRules})
}
}
}
return &ings
}
func (ctl *ApplicationCtl) ListApplication(runtimeId string, match, fuzzy map[string]string, paging *Paging) (int, interface{}, error) {
limit := paging.Limit
offset := paging.Offset
if strings.HasSuffix(ctl.OpenpitrixAddr, "/") {
ctl.OpenpitrixAddr = strings.TrimSuffix(ctl.OpenpitrixAddr, "/")
}
defaultStatus := "status=active&status=stopped&status=pending&status=ceased"
url := fmt.Sprintf("%s/v1/clusters?limit=%s&offset=%s", ctl.OpenpitrixAddr, strconv.Itoa(limit), strconv.Itoa(offset))
if len(fuzzy["name"]) > 0 {
url = fmt.Sprintf("%s&search_word=%s", url, fuzzy["name"])
}
if len(match["status"]) > 0 {
url = fmt.Sprintf("%s&status=%s", url, match["status"])
} else {
url = fmt.Sprintf("%s&%s", url, defaultStatus)
}
if len(runtimeId) > 0 {
url = fmt.Sprintf("%s&runtime_id=%s", url, runtimeId)
}
resp, err := makeHttpRequest("GET", url, "")
if err != nil {
glog.Errorf("request %s failed, reason: %s", url, err)
return 0, nil, err
}
var clusterList clusters
err = json.Unmarshal(resp, &clusterList)
if err != nil {
return 0, nil, err
}
var apps []Application
for _, item := range clusterList.Clusters {
var app Application
app.Name = item.Name
app.ClusterID = item.ClusterID
app.UpdateTime = item.UpdateTime
app.Status = item.Status
versionInfo, _ := ctl.GetVersion(item.VersionID)
app.Version = versionInfo
app.VersionId = item.VersionID
runtimeInfo, _ := ctl.GetRuntime(item.RunTimeId)
app.Runtime = runtimeInfo
app.RuntimeId = item.RunTimeId
appInfo, _, appId, _ := ctl.GetAppInfo(item.AppID)
app.App = appInfo
app.AppId = appId
app.Description = item.Description
apps = append(apps, app)
}
return clusterList.Total, apps, nil
}
func (ctl *ApplicationCtl) GetApp(clusterId string) (*Application, error) {
if strings.HasSuffix(ctl.OpenpitrixAddr, "/") {
ctl.OpenpitrixAddr = strings.TrimSuffix(ctl.OpenpitrixAddr, "/")
}
url := fmt.Sprintf("%s/v1/clusters?cluster_id=%s", ctl.OpenpitrixAddr, clusterId)
resp, err := makeHttpRequest("GET", url, "")
if err != nil {
glog.Error(err)
return nil, err
}
var clusterList clusters
err = json.Unmarshal(resp, &clusterList)
if err != nil {
glog.Error(err)
return nil, err
}
if len(clusterList.Clusters) == 0 {
return nil, fmt.Errorf("NotFound, clusterId:%s", clusterId)
}
item := clusterList.Clusters[0]
var app Application
app.Name = item.Name
app.ClusterID = item.ClusterID
app.UpdateTime = item.UpdateTime
app.CreateTime = item.CreateTime
app.Status = item.Status
versionInfo, _ := ctl.GetVersion(item.VersionID)
app.Version = versionInfo
app.VersionId = item.VersionID
runtimeInfo, _ := ctl.GetRuntime(item.RunTimeId)
app.Runtime = runtimeInfo
app.RuntimeId = item.RunTimeId
appInfo, repoId, appId, _ := ctl.GetAppInfo(item.AppID)
app.App = appInfo
app.AppId = appId
app.Description = item.Description
app.RepoName, _ = ctl.GetRepo(repoId)
app.WorkLoads = ctl.GetWorkLoads(app.Runtime, item.ClusterRoleSets)
workloadLabels := ctl.getLabels(app.Runtime, app.WorkLoads)
app.Services = ctl.getSvcs(app.Runtime, workloadLabels)
app.Ingresses = ctl.getIng(app.Runtime, app.Services)
return &app, nil
}

View File

@@ -1,185 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"fmt"
"regexp"
"strings"
"github.com/golang/glog"
"github.com/pkg/errors"
rbac "k8s.io/api/rbac/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/kubectl"
)
func (ctl *ClusterRoleBindingCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ClusterRoleBindingCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ClusterRoleBindingCtl) total() int {
return 0
}
func (ctl *ClusterRoleBindingCtl) handleWorkspaceRoleChange(clusterRole *rbac.ClusterRoleBinding) {
if groups := regexp.MustCompile(fmt.Sprintf(`^system:(\S+):(%s)$`, strings.Join(constants.WorkSpaceRoles, "|"))).FindStringSubmatch(clusterRole.Name); len(groups) == 3 {
workspace := groups[1]
go ctl.restNamespaceRoleBinding(workspace)
}
}
func (ctl *ClusterRoleBindingCtl) restNamespaceRoleBinding(workspace string) {
selector := labels.SelectorFromSet(labels.Set{"kubesphere.io/workspace": workspace})
namespaces, err := ctl.K8sClient.CoreV1().Namespaces().List(meta_v1.ListOptions{LabelSelector: selector.String()})
if err != nil {
glog.Warning("workspace roles sync failed", workspace, err)
return
}
for _, namespace := range namespaces.Items {
pathJson := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, initTimeAnnotateKey, "")
_, err := ctl.K8sClient.CoreV1().Namespaces().Patch(namespace.Name, "application/strategic-merge-patch+json", []byte(pathJson))
if err != nil {
glog.Warning("workspace roles sync failed", workspace, err)
return
}
}
}
func (ctl *ClusterRoleBindingCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Rbac().V1().ClusterRoleBindings().Lister()
ctl.informer = informerFactory.Rbac().V1().ClusterRoleBindings().Informer()
ctl.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
clusterRoleBinding := obj.(*rbac.ClusterRoleBinding)
ctl.handleTerminalCreate(clusterRoleBinding)
},
UpdateFunc: func(old, new interface{}) {
oldValue := old.(*rbac.ClusterRoleBinding)
newValue := new.(*rbac.ClusterRoleBinding)
if !subjectsCompile(oldValue.Subjects, newValue.Subjects) {
ctl.handleWorkspaceRoleChange(newValue)
ctl.handleTerminalUpdate(oldValue, newValue)
}
},
DeleteFunc: func(obj interface{}) {
clusterRoleBinding := obj.(*rbac.ClusterRoleBinding)
ctl.handleTerminalDelete(clusterRoleBinding)
},
})
}
func (ctl *ClusterRoleBindingCtl) handleTerminalCreate(clusterRoleBinding *rbac.ClusterRoleBinding) {
if clusterRoleBinding.RoleRef.Name == constants.ClusterAdmin {
for _, subject := range clusterRoleBinding.Subjects {
if subject.Kind == rbac.UserKind {
err := kubectl.CreateKubectlDeploy(subject.Name)
if err != nil {
glog.Error(fmt.Sprintf("create %s's terminal pod failed:%s", subject.Name, err))
}
}
}
}
}
func (ctl *ClusterRoleBindingCtl) handleTerminalUpdate(old *rbac.ClusterRoleBinding, new *rbac.ClusterRoleBinding) {
if new.RoleRef.Name == constants.ClusterAdmin {
for _, newSubject := range new.Subjects {
isAdded := true
for _, oldSubject := range old.Subjects {
if oldSubject == newSubject {
isAdded = false
break
}
}
if isAdded && newSubject.Kind == rbac.UserKind {
err := kubectl.CreateKubectlDeploy(newSubject.Name)
if err != nil {
glog.Error(fmt.Sprintf("create %s's terminal pod failed:%s", newSubject.Name, err))
}
}
}
for _, oldSubject := range old.Subjects {
isDeleted := true
for _, newSubject := range new.Subjects {
if newSubject == oldSubject {
isDeleted = false
break
}
}
if isDeleted && oldSubject.Kind == rbac.UserKind {
err := kubectl.DelKubectlDeploy(oldSubject.Name)
if err != nil {
glog.Error(fmt.Sprintf("delete %s's terminal pod failed:%s", oldSubject.Name, err))
}
}
}
}
}
func (ctl *ClusterRoleBindingCtl) handleTerminalDelete(clusterRoleBinding *rbac.ClusterRoleBinding) {
if clusterRoleBinding.RoleRef.Name == constants.ClusterAdmin {
for _, subject := range clusterRoleBinding.Subjects {
if subject.Kind == rbac.UserKind {
err := kubectl.DelKubectlDeploy(subject.Name)
if err != nil {
glog.Error(fmt.Sprintf("delete %s's terminal pod failed:%s", subject.Name, err))
}
}
}
}
}
func subjectsCompile(s1 []rbac.Subject, s2 []rbac.Subject) bool {
if len(s1) != len(s2) {
return false
}
for i, v := range s1 {
if v.Name != s2[i].Name || v.Kind != s2[i].Kind {
return false
}
}
return true
}
func (ctl *ClusterRoleBindingCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ClusterRoleBindingCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, errors.New("not implement")
}
func (ctl *ClusterRoleBindingCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,170 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
const systemPrefix = "system:"
func (ctl *ClusterRoleCtl) generateObject(item v1.ClusterRole) *ClusterRole {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
if strings.HasPrefix(name, systemPrefix) || item.Annotations == nil || len(item.Annotations[creator]) == 0 {
return nil
}
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
object := &ClusterRole{Name: name, CreateTime: createTime, Annotation: MapString{item.Annotations}, DisplayName: displayName}
return object
}
func (ctl *ClusterRoleCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ClusterRoleCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&ClusterRole{}) {
db.DropTable(&ClusterRole{})
}
db = db.CreateTable(&ClusterRole{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
if obj != nil {
if err := db.Create(obj).Error; err != nil {
glog.Error("cluster roles sync error", err)
}
}
}
ctl.informer.Run(stopChan)
}
func (ctl *ClusterRoleCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s failed, reason:%s", err, ctl.Name())
return 0
}
count := 0
for _, item := range list {
if !strings.HasPrefix(item.Name, systemPrefix) && item.Annotations != nil && len(item.Annotations[creator]) > 0 {
count++
}
}
return count
}
func (ctl *ClusterRoleCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Rbac().V1().ClusterRoles().Lister()
informer := informerFactory.Rbac().V1().ClusterRoles().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.ClusterRole)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
if err := db.Create(mysqlObject).Error; err != nil {
glog.Error("cluster roles sync error", err)
}
}
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.ClusterRole)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
if err := db.Save(mysqlObject).Error; err != nil {
glog.Error("cluster roles update error", err)
}
}
},
DeleteFunc: func(obj interface{}) {
object := obj.(*v1.ClusterRole)
if err := db.Delete(ClusterRole{}, "name=?", object.Name).Error; err != nil {
glog.Error("cluster roles delete error", err)
}
},
})
ctl.informer = informer
}
func (ctl *ClusterRoleCtl) CountWithConditions(conditions string) int {
var object ClusterRole
if strings.Contains(conditions, "namespace") {
conditions = ""
}
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *ClusterRoleCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var object ClusterRole
var list []ClusterRole
var total int
if len(order) == 0 {
order = "createTime desc"
}
db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *ClusterRoleCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,161 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"sync"
"github.com/golang/glog"
"github.com/jinzhu/gorm"
"github.com/pkg/errors"
"kubesphere.io/kubesphere/pkg/constants"
)
const (
checkPeriod = 30 * time.Minute
sleepPeriod = 15 * time.Second
)
func listWithConditions(db *gorm.DB, total *int, object, list interface{}, conditions string, paging *Paging, order string) {
if len(conditions) == 0 {
db.Model(object).Count(total)
} else {
db.Model(object).Where(conditions).Count(total)
}
if paging != nil {
if len(conditions) > 0 {
db.Where(conditions).Order(order).Limit(paging.Limit).Offset(paging.Offset).Find(list)
} else {
db.Order(order).Limit(paging.Limit).Offset(paging.Offset).Find(list)
}
} else {
if len(conditions) > 0 {
db.Where(conditions).Order(order).Find(list)
} else {
db.Order(order).Find(list)
}
}
}
func countWithConditions(db *gorm.DB, conditions string, object interface{}) int {
var count int
if len(conditions) == 0 {
db.Model(object).Count(&count)
} else {
db.Model(object).Where(conditions).Count(&count)
}
return count
}
func makeHttpRequest(method, url, data string) ([]byte, error) {
var req *http.Request
var err error
if method == "GET" {
req, err = http.NewRequest(method, url, nil)
} else {
req, err = http.NewRequest(method, url, strings.NewReader(data))
}
req.Header.Add("Authorization", constants.OpenPitrixProxyToken)
if err != nil {
glog.Error(err)
return nil, err
}
httpClient := &http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
err := fmt.Errorf("Request to %s failed, method: %s, reason: %s ", url, method, err)
glog.Error(err)
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if resp.StatusCode >= http.StatusBadRequest {
err = errors.New(string(body))
}
return body, err
}
func handleCrash(ctl Controller) {
close(ctl.chanAlive())
if err := recover(); err != nil {
glog.Errorf("panic occur in %s controller's listAndWatch function, reason: %s", ctl.Name(), err)
return
}
}
func hasSynced(ctl Controller) bool {
totalInDb := ctl.CountWithConditions("")
totalInK8s := ctl.total()
if totalInDb == totalInK8s {
return true
}
return false
}
func checkAndResync(ctl Controller, stopChan chan struct{}) {
defer close(stopChan)
lastTime := time.Now()
for {
select {
case <-ctl.chanStop():
return
default:
if time.Now().Sub(lastTime) < checkPeriod {
time.Sleep(sleepPeriod)
break
}
lastTime = time.Now()
if !hasSynced(ctl) {
glog.Errorf("the data in db and kubernetes is inconsistent, resync %s controller", ctl.Name())
close(stopChan)
stopChan = make(chan struct{})
go ctl.sync(stopChan)
}
}
}
}
func listAndWatch(ctl Controller, wg *sync.WaitGroup) {
defer handleCrash(ctl)
defer ctl.CloseDB()
defer wg.Done()
stopChan := make(chan struct{})
go ctl.sync(stopChan)
checkAndResync(ctl, stopChan)
}

View File

@@ -1,162 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *ConfigMapCtl) generateObject(item v1.ConfigMap) *ConfigMap {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
var entries []string
for entry := range item.Data {
entries = append(entries, entry)
}
object := &ConfigMap{
Name: item.Name,
Namespace: item.Namespace,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
DisplayName: displayName,
Entries: strings.Join(entries, ","),
}
return object
}
func (ctl *ConfigMapCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ConfigMapCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&ConfigMap{}) {
db.DropTable(&ConfigMap{})
}
db = db.CreateTable(&ConfigMap{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
if obj != nil {
db.Create(obj)
}
}
ctl.informer.Run(stopChan)
}
func (ctl *ConfigMapCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *ConfigMapCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().ConfigMaps().Lister()
informer := informerFactory.Core().V1().ConfigMaps().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.ConfigMap)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Create(mysqlObject)
}
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.ConfigMap)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Save(mysqlObject)
}
},
DeleteFunc: func(obj interface{}) {
var item ConfigMap
object := obj.(*v1.ConfigMap)
db.Where("name=?", object.Name).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *ConfigMapCtl) CountWithConditions(conditions string) int {
var object ConfigMap
if strings.Contains(conditions, "namespace") {
conditions = ""
}
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *ConfigMapCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var object ConfigMap
var list []ConfigMap
var total int
if len(order) == 0 {
order = "createTime desc"
}
db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *ConfigMapCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,64 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"k8s.io/client-go/informers"
)
func (ctl *ControllerRevisionCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ControllerRevisionCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ControllerRevisionCtl) total() int {
return 0
}
func (ctl *ControllerRevisionCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().ControllerRevisions().Lister()
informer := informerFactory.Apps().V1().ControllerRevisions().Informer()
ctl.informer = informer
}
func (ctl *ControllerRevisionCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ControllerRevisionCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, nil
}
func (ctl *ControllerRevisionCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,158 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"github.com/golang/glog"
"k8s.io/api/batch/v1beta1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *CronJobCtl) generateObject(item v1beta1.CronJob) *CronJob {
var status, displayName string
var lastScheduleTime *time.Time
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
status = Running
if *item.Spec.Suspend {
status = Pause
}
schedule := item.Spec.Schedule
if item.Status.LastScheduleTime != nil {
lastScheduleTime = &item.Status.LastScheduleTime.Time
}
active := len(item.Status.Active)
object := &CronJob{
Namespace: namespace,
Name: name,
DisplayName: displayName,
LastScheduleTime: lastScheduleTime,
Active: active,
Schedule: schedule,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.ObjectMeta.Labels},
}
return object
}
func (ctl *CronJobCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *CronJobCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&CronJob{}) {
db.DropTable(&CronJob{})
}
db = db.CreateTable(&CronJob{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *CronJobCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *CronJobCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Batch().V1beta1().CronJobs().Lister()
informer := informerFactory.Batch().V1beta1().CronJobs().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1beta1.CronJob)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1beta1.CronJob)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item CronJob
object := obj.(*v1beta1.CronJob)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *CronJobCtl) CountWithConditions(conditions string) int {
var object CronJob
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *CronJobCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []CronJob
var object CronJob
var total int
if len(order) == 0 {
order = "lastScheduleTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *CronJobCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,169 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"encoding/json"
"time"
"github.com/golang/glog"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *DaemonsetCtl) generateObject(item v1.DaemonSet) *Daemonset {
var app, status, displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.NumberAvailable
desirePodNum := item.Status.DesiredNumberScheduled
createTime := item.CreationTimestamp.Time
release := item.ObjectMeta.Labels["release"]
nodeSelector := item.Spec.Template.Spec.NodeSelector
nodeSelectorStr, _ := json.Marshal(nodeSelector)
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
}
if createTime.IsZero() {
createTime = time.Now()
}
if availablePodNum >= desirePodNum {
status = Running
} else {
status = Updating
}
object := &Daemonset{
Namespace: namespace,
Name: name,
DisplayName: displayName,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
CreateTime: createTime,
Status: status,
NodeSelector: string(nodeSelectorStr),
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
}
return object
}
func (ctl *DaemonsetCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *DaemonsetCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Daemonset{}) {
db.DropTable(&Daemonset{})
}
db = db.CreateTable(&Daemonset{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *DaemonsetCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *DaemonsetCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().DaemonSets().Lister()
informer := informerFactory.Apps().V1().DaemonSets().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.DaemonSet)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.DaemonSet)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Daemonset
object := obj.(*v1.DaemonSet)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *DaemonsetCtl) CountWithConditions(conditions string) int {
var object Daemonset
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *DaemonsetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Daemonset
var object Daemonset
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *DaemonsetCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,176 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"github.com/golang/glog"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
var app, status, displayName string
var updateTime time.Time
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.AvailableReplicas
desirePodNum := *item.Spec.Replicas
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
}
for _, condition := range item.Status.Conditions {
if updateTime.IsZero() {
updateTime = condition.LastUpdateTime.Time
} else {
if updateTime.Before(condition.LastUpdateTime.Time) {
updateTime = condition.LastUpdateTime.Time
}
}
}
if updateTime.IsZero() {
updateTime = time.Now()
}
if item.Annotations["state"] == "stop" {
status = Stopped
} else {
if availablePodNum >= desirePodNum {
status = Running
} else {
status = Updating
}
}
return &Deployment{
Namespace: namespace,
Name: name,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
UpdateTime: updateTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
DisplayName: displayName,
}
}
func (ctl *DeploymentCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *DeploymentCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Deployment{}) {
db.DropTable(&Deployment{})
}
db = db.CreateTable(&Deployment{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *DeploymentCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", ctl.Name(), err)
return 0
}
return len(list)
}
func (ctl *DeploymentCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().Deployments().Lister()
informer := informerFactory.Apps().V1().Deployments().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Deployment)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Deployment)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var deploy Deployment
object := obj.(*v1.Deployment)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&deploy)
db.Delete(deploy)
},
})
ctl.informer = informer
}
func (ctl *DeploymentCtl) CountWithConditions(conditions string) int {
var object Deployment
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *DeploymentCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Deployment
var object Deployment
var total int
if len(order) == 0 {
order = "updateTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *DeploymentCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,180 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"strings"
"time"
"encoding/json"
"github.com/golang/glog"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress {
var ip, tls, displayName string
name := item.Name
namespace := item.Namespace
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
var ipList []string
for _, lb := range item.Status.LoadBalancer.Ingress {
if len(lb.IP) > 0 {
ipList = append(ipList, lb.IP)
}
}
if len(ipList) > 0 {
ip = strings.Join(ipList, ",")
}
var ingRules []ingressRule
for _, rule := range item.Spec.Rules {
host := rule.Host
for _, path := range rule.HTTP.Paths {
var ingRule ingressRule
ingRule.Host = host
ingRule.Service = path.Backend.ServiceName
ingRule.Port = path.Backend.ServicePort.IntVal
ingRule.Path = path.Path
ingRules = append(ingRules, ingRule)
}
}
ruleStr, _ := json.Marshal(ingRules)
object := &Ingress{
Namespace: namespace,
Name: name,
DisplayName: displayName,
TlsTermination: tls,
Ip: ip,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
Rules: string(ruleStr),
Labels: MapString{item.Labels},
}
return object
}
func (ctl *IngressCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *IngressCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Ingress{}) {
db.DropTable(&Ingress{})
}
db = db.CreateTable(&Ingress{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *IngressCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *IngressCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Extensions().V1beta1().Ingresses().Lister()
informer := informerFactory.Extensions().V1beta1().Ingresses().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1beta1.Ingress)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1beta1.Ingress)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Ingress
object := obj.(*v1beta1.Ingress)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *IngressCtl) CountWithConditions(conditions string) int {
var object Ingress
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *IngressCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Ingress
var object Ingress
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *IngressCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,318 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"encoding/json"
"fmt"
"time"
"github.com/golang/glog"
"k8s.io/api/batch/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"reflect"
"strings"
"kubesphere.io/kubesphere/pkg/client"
)
var k8sClient *kubernetes.Clientset
const retryTimes = 3
func (ctl *JobCtl) generateObject(item v1.Job) *Job {
var status, displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
succeedPodNum := item.Status.Succeeded
desirePodNum := *item.Spec.Completions
createTime := item.CreationTimestamp.Time
updteTime := createTime
for _, condition := range item.Status.Conditions {
if condition.Type == "Failed" && condition.Status == "True" {
status = Failed
}
if condition.Type == "Complete" && condition.Status == "True" {
status = Completed
}
if updteTime.Before(condition.LastProbeTime.Time) {
updteTime = condition.LastProbeTime.Time
}
if updteTime.Before(condition.LastTransitionTime.Time) {
updteTime = condition.LastTransitionTime.Time
}
}
if desirePodNum > succeedPodNum && len(status) == 0 {
status = Running
}
object := &Job{
Namespace: namespace,
Name: name,
DisplayName: displayName,
Desire: desirePodNum,
Completed: succeedPodNum,
UpdateTime: updteTime,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
}
return object
}
func (ctl *JobCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *JobCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Job{}) {
db.DropTable(&Job{})
}
db = db.CreateTable(&Job{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *JobCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *JobCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Batch().V1().Jobs().Lister()
informer := informerFactory.Batch().V1().Jobs().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Job)
mysqlObject := ctl.generateObject(*object)
ctl.makeRevision(object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Job)
mysqlObject := ctl.generateObject(*object)
ctl.makeRevision(object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Job
object := obj.(*v1.Job)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *JobCtl) CountWithConditions(conditions string) int {
var object Job
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *JobCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Job
var object Job
var total int
if len(order) == 0 {
order = "updateTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *JobCtl) Lister() interface{} {
return ctl.lister
}
func getRevisions(job v1.Job) (JobRevisions, error) {
revisions := make(JobRevisions)
if _, exist := job.Annotations["revisions"]; exist {
revisionsStr := job.Annotations["revisions"]
err := json.Unmarshal([]byte(revisionsStr), &revisions)
if err != nil {
return nil, fmt.Errorf("failed to get job %s's revisions, reason: %s", job.Name, err)
}
}
return revisions, nil
}
func getCurrentRevision(item *v1.Job) JobRevision {
var revision JobRevision
for _, condition := range item.Status.Conditions {
if condition.Type == "Failed" && condition.Status == "True" {
revision.Status = Failed
revision.Reasons = append(revision.Reasons, condition.Reason)
revision.Messages = append(revision.Messages, condition.Message)
}
if condition.Type == "Complete" && condition.Status == "True" {
revision.Status = Completed
}
}
if len(revision.Status) == 0 {
revision.Status = Running
}
revision.DesirePodNum = *item.Spec.Completions
revision.Succeed = item.Status.Succeeded
revision.Failed = item.Status.Failed
revision.StartTime = item.CreationTimestamp.Time
revision.Uid = string(item.UID)
if item.Status.CompletionTime != nil {
revision.CompletionTime = item.Status.CompletionTime.Time
}
return revision
}
func deleteJob(namespace, job string) error {
deletePolicy := metav1.DeletePropagationBackground
err := k8sClient.BatchV1().Jobs(namespace).Delete(job, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
return err
}
func (ctl *JobCtl) makeRevision(job *v1.Job) {
revisionIndex := -1
revisions, err := getRevisions(*job)
if err != nil {
glog.Error(err)
return
}
uid := job.UID
for index, revision := range revisions {
if revision.Uid == string(uid) {
currentRevision := getCurrentRevision(job)
if reflect.DeepEqual(currentRevision, revision) {
return
} else {
revisionIndex = index
break
}
}
}
if revisionIndex == -1 {
revisionIndex = len(revisions) + 1
}
revisions[revisionIndex] = getCurrentRevision(job)
revisionsByte, err := json.Marshal(revisions)
if err != nil {
glog.Error(err)
}
if job.Annotations == nil {
job.Annotations = make(map[string]string)
}
job.Annotations["revisions"] = string(revisionsByte)
ctl.K8sClient.BatchV1().Jobs(job.Namespace).Update(job)
}
func JobReRun(namespace, jobName string) (string, error) {
k8sClient = client.NewK8sClient()
job, err := k8sClient.BatchV1().Jobs(namespace).Get(jobName, metav1.GetOptions{})
if err != nil {
return "", err
}
newJob := *job
newJob.ResourceVersion = ""
newJob.Status = v1.JobStatus{}
newJob.ObjectMeta.UID = ""
newJob.Annotations["revisions"] = strings.Replace(job.Annotations["revisions"], Running, Unfinished, -1)
delete(newJob.Spec.Selector.MatchLabels, "controller-uid")
delete(newJob.Spec.Template.ObjectMeta.Labels, "controller-uid")
err = deleteJob(namespace, jobName)
if err != nil {
glog.Errorf("failed to rerun job %s, reason: %s", jobName, err)
return "", fmt.Errorf("failed to rerun job %s", jobName)
}
for i := 0; i < retryTimes; i++ {
_, err = k8sClient.BatchV1().Jobs(namespace).Create(&newJob)
if err != nil {
time.Sleep(time.Second)
continue
}
break
}
if err != nil {
glog.Errorf("failed to rerun job %s, reason: %s", jobName, err)
return "", fmt.Errorf("failed to rerun job %s", jobName)
}
return "succeed", nil
}

View File

@@ -1,535 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"encoding/json"
"fmt"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/resource"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/kubernetes/pkg/util/slice"
"k8s.io/client-go/informers"
"k8s.io/kubernetes/pkg/apis/core"
utilversion "k8s.io/kubernetes/pkg/util/version"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/options"
)
const (
provider = "kubernetes"
admin = "admin"
operator = "operator"
viewer = "viewer"
kubectlNamespace = constants.KubeSphereControlNamespace
kubectlConfigKey = "config"
openPitrixRuntimeAnnotateKey = "openpitrix_runtime"
creatorAnnotateKey = "creator"
initTimeAnnotateKey = "kubesphere.io/init-time"
workspaceLabelKey = "kubesphere.io/workspace"
)
var adminRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}
var editorRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch", "kubesphere.io", "account.kubesphere.io"}, Resources: []string{"*"}}}
var viewerRules = []rbac.PolicyRule{{Verbs: []string{"list", "get", "watch"}, APIGroups: []string{"", "apps", "extensions", "batch", "kubesphere.io", "account.kubesphere.io"}, Resources: []string{"*"}}}
type runTime struct {
RuntimeId string `json:"runtime_id"`
RuntimeUrl string `json:"runtime_url"`
Name string `json:"name"`
Provider string `json:"provider"`
Zone string `json:"zone"`
RuntimeCredential string `json:"runtime_credential"`
}
type DeleteRunTime struct {
RuntimeId []string `json:"runtime_id"`
}
func (ctl *NamespaceCtl) getKubeConfig(user string) (string, error) {
k8sClient := client.NewK8sClient()
configmap, err := k8sClient.CoreV1().ConfigMaps(kubectlNamespace).Get(user, metaV1.GetOptions{})
if err != nil {
glog.Errorln(err)
return "", err
}
return configmap.Data[kubectlConfigKey], nil
}
func (ctl *NamespaceCtl) deleteOpRuntime(item v1.Namespace) {
var runtimeId string
if item.Annotations == nil {
runtimeId = ""
} else {
runtimeId = item.Annotations[openPitrixRuntimeAnnotateKey]
}
if len(runtimeId) == 0 {
return
}
url := options.ServerOptions.GetOpAddress() + "/v1/runtimes"
var deleteRuntime = DeleteRunTime{RuntimeId: []string{runtimeId}}
body, err := json.Marshal(deleteRuntime)
if err != nil {
glog.Error("runtime release failed:", item.Name, runtimeId, err)
return
}
glog.Info("runtime release succeeded:", item.Name, runtimeId)
// todo: if delete failed, what's to be done?
makeHttpRequest("DELETE", url, string(body))
}
func (ctl *NamespaceCtl) createOpRuntime(namespace string) ([]byte, error) {
zone := namespace
name := namespace
kubeConfig, err := ctl.getKubeConfig("admin")
if err != nil {
glog.Error(err)
return nil, err
}
url := options.ServerOptions.GetOpAddress() + "/v1/runtimes"
option := runTime{Name: name, Provider: provider, RuntimeCredential: kubeConfig, Zone: zone}
body, err := json.Marshal(option)
if err != nil {
glog.Error(err)
return nil, err
}
return makeHttpRequest("POST", url, string(body))
}
func (ctl *NamespaceCtl) updateSystemRoleBindings(namespace *v1.Namespace) error {
workspace := ""
if namespace.Labels != nil {
workspace = namespace.Labels[workspaceLabelKey]
}
adminBinding, err := ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Get(admin, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
adminBinding = new(rbac.RoleBinding)
adminBinding.Name = admin
adminBinding.Namespace = namespace.Name
adminBinding.RoleRef = rbac.RoleRef{Kind: "Role", Name: admin}
} else {
return err
}
}
adminBinding.Subjects = make([]rbac.Subject, 0)
if workspace != "" {
workspaceAdmin, err := ctl.K8sClient.RbacV1().ClusterRoleBindings().Get(fmt.Sprintf("system:%s:%s", workspace, constants.WorkspaceAdmin), metaV1.GetOptions{})
if err != nil {
return err
}
adminBinding.Subjects = append(adminBinding.Subjects, workspaceAdmin.Subjects...)
}
if adminBinding.ResourceVersion == "" {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Create(adminBinding)
} else {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Update(adminBinding)
}
if err != nil {
return err
}
viewerBinding, err := ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Get(viewer, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
viewerBinding = new(rbac.RoleBinding)
viewerBinding.Name = viewer
viewerBinding.Namespace = namespace.Name
viewerBinding.RoleRef = rbac.RoleRef{Kind: "Role", Name: viewer}
} else {
return err
}
}
viewerBinding.Subjects = make([]rbac.Subject, 0)
if workspace != "" {
workspaceViewer, err := ctl.K8sClient.RbacV1().ClusterRoleBindings().Get(fmt.Sprintf("system:%s:%s", workspace, constants.WorkspaceViewer), metaV1.GetOptions{})
if err != nil {
return err
}
viewerBinding.Subjects = append(viewerBinding.Subjects, workspaceViewer.Subjects...)
}
if viewerBinding.ResourceVersion == "" {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Create(viewerBinding)
} else {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Update(viewerBinding)
}
if err != nil {
return err
}
return nil
}
func (ctl *NamespaceCtl) createDefaultRoleBinding(namespace *v1.Namespace) error {
creator := ""
if namespace.Annotations != nil {
creator = namespace.Annotations[creatorAnnotateKey]
}
// create once
if creator != "" {
creatorBindingName := fmt.Sprintf("%s-admin", creator)
creatorBinding, err := ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Get(creatorBindingName, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
creatorBinding = new(rbac.RoleBinding)
creatorBinding.Name = creatorBindingName
creatorBinding.Namespace = namespace.Name
creatorBinding.RoleRef = rbac.RoleRef{Kind: "Role", Name: admin}
} else {
return err
}
}
creatorBinding.Subjects = []rbac.Subject{{Kind: rbac.UserKind, Name: creator}}
if creatorBinding.ResourceVersion == "" {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Create(creatorBinding)
} else {
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Update(creatorBinding)
}
if err != nil {
return err
}
}
return nil
}
func (ctl *NamespaceCtl) CreateDefaultRoleAndRoleBinding(namespace *v1.Namespace) error {
adminRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: admin, Namespace: namespace.Name, Annotations: map[string]string{creatorAnnotateKey: "system"}}, Rules: adminRules}
operatorRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: operator, Namespace: namespace.Name, Annotations: map[string]string{creatorAnnotateKey: "system"}}, Rules: editorRules}
viewerRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: viewer, Namespace: namespace.Name, Annotations: map[string]string{creatorAnnotateKey: "system"}}, Rules: viewerRules}
_, err := ctl.K8sClient.RbacV1().Roles(namespace.Name).Create(adminRole)
if err != nil && !errors.IsAlreadyExists(err) {
return err
} else if err == nil {
if err := ctl.createDefaultRoleBinding(namespace); err != nil {
glog.Warning("default role binding create failed", namespace.Name)
}
}
_, err = ctl.K8sClient.RbacV1().Roles(namespace.Name).Create(operatorRole)
if err != nil && !errors.IsAlreadyExists(err) {
return err
}
_, err = ctl.K8sClient.RbacV1().Roles(namespace.Name).Create(viewerRole)
if err != nil && !errors.IsAlreadyExists(err) {
return err
}
return nil
}
func (ctl *NamespaceCtl) createRoleAndRuntime(namespace *v1.Namespace) {
runtime := ""
initTime := ""
if namespace.Annotations != nil {
runtime = namespace.Annotations[openPitrixRuntimeAnnotateKey]
initTime = namespace.Annotations[initTimeAnnotateKey]
}
componentsNamespaces := []string{constants.KubeSystemNamespace, constants.OpenPitrixNamespace, constants.IstioNamespace, constants.KubeSphereNamespace}
if runtime == "" && !slice.ContainsString(componentsNamespaces, namespace.Name, nil) {
_, runtimeCreateError := ctl.createOpRuntime(namespace.Name)
if runtimeCreateError != nil {
glog.Error("runtime create error:", runtimeCreateError)
}
}
if initTime == "" {
err := ctl.CreateDefaultRoleAndRoleBinding(namespace)
if err == nil {
err = ctl.updateSystemRoleBindings(namespace)
if err != nil {
glog.Error("role binding update error:", err)
}
} else {
glog.Error("default role create error:", err)
}
if err == nil {
pathJson := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, initTimeAnnotateKey, time.Now().UTC().Format("2006-01-02T15:04:05Z"))
_, err = ctl.K8sClient.CoreV1().Namespaces().Patch(namespace.Name, "application/strategic-merge-patch+json", []byte(pathJson))
if err != nil {
glog.Error("annotations patch error init failed:", namespace.Name, err)
}
}
}
}
func (ctl *NamespaceCtl) createCephSecretAfterNewNs(item v1.Namespace) {
// Kubernetes version must < 1.11.0
verInfo, err := ctl.K8sClient.ServerVersion()
if err != nil {
glog.Error("consult k8s server error: ", err)
return
}
if !utilversion.MustParseSemantic(verInfo.String()).LessThan(utilversion.MustParseSemantic("v1.11.0")) {
glog.Infof("disable Ceph secret controller due to k8s version %s >= v1.11.0", verInfo.String())
return
}
// Create Ceph secret in the new namespace
newNsName := item.Name
scList, _ := ctl.K8sClient.StorageV1().StorageClasses().List(metaV1.ListOptions{})
if scList == nil {
return
}
for _, sc := range scList.Items {
if sc.Provisioner == rbdPluginName {
glog.Infof("would create Ceph user secret in storage class %s at namespace %s", sc.GetName(), newNsName)
if secretName, ok := sc.Parameters[rbdUserSecretNameKey]; ok {
secret, err := ctl.K8sClient.CoreV1().Secrets(core.NamespaceSystem).Get(secretName, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
glog.Errorf("cannot find secret in namespace %s, error: %s", core.NamespaceSystem, err.Error())
continue
}
glog.Errorf("failed to find secret in namespace %s, error: %s", core.NamespaceSystem, err.Error())
continue
}
glog.Infof("succeed to find secret %s in namespace %s", secret.GetName(), secret.GetNamespace())
newSecret := &v1.Secret{
TypeMeta: metaV1.TypeMeta{
Kind: secret.Kind,
APIVersion: secret.APIVersion,
},
ObjectMeta: metaV1.ObjectMeta{
Name: secret.GetName(),
Namespace: newNsName,
Labels: secret.GetLabels(),
Annotations: secret.GetAnnotations(),
DeletionGracePeriodSeconds: secret.GetDeletionGracePeriodSeconds(),
ClusterName: secret.GetClusterName(),
},
Data: secret.Data,
StringData: secret.StringData,
Type: secret.Type,
}
glog.Infof("creating secret %s in namespace %s...", newSecret.GetName(), newSecret.GetNamespace())
_, err = ctl.K8sClient.CoreV1().Secrets(newSecret.GetNamespace()).Create(newSecret)
if err != nil {
glog.Errorf("failed to create secret in namespace %s, error: %v", newSecret.GetNamespace(), err)
continue
}
} else {
glog.Errorf("failed to find user secret name in storage class %s", sc.GetName())
}
}
}
}
func (ctl *NamespaceCtl) generateObject(item *v1.Namespace) *Namespace {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
createTime := item.CreationTimestamp.Time
status := fmt.Sprintf("%v", item.Status.Phase)
if createTime.IsZero() {
createTime = time.Now()
}
object := &Namespace{
Name: name,
DisplayName: displayName,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
}
return object
}
func (ctl *NamespaceCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *NamespaceCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Namespace{}) {
db.DropTable(&Namespace{})
}
db = db.CreateTable(&Namespace{})
ctl.initListerAndInformer()
//list, err := ctl.lister.List(labels.Everything())
//if err != nil {
// glog.Error(err)
// return
//}
//for _, item := range list {
// obj := ctl.generateObject(item)
// db.Create(obj)
// ctl.createRoleAndRuntime(item)
//}
ctl.informer.Run(stopChan)
}
func (ctl *NamespaceCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *NamespaceCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().Namespaces().Lister()
informer := informerFactory.Core().V1().Namespaces().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Namespace)
mysqlObject := ctl.generateObject(object)
db.Create(mysqlObject)
ctl.createRoleAndRuntime(object)
ctl.createCephSecretAfterNewNs(*object)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Namespace)
mysqlObject := ctl.generateObject(object)
db.Save(mysqlObject)
ctl.createRoleAndRuntime(object)
},
DeleteFunc: func(obj interface{}) {
var item Namespace
object := obj.(*v1.Namespace)
db.Where("name=?", object.Name).Find(&item)
db.Delete(item)
ctl.deleteOpRuntime(*object)
},
})
ctl.informer = informer
}
func (ctl *NamespaceCtl) CountWithConditions(conditions string) int {
var object Namespace
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *NamespaceCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Namespace
var object Namespace
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
if paging != nil {
for index := range list {
usage, err := ctl.GetNamespaceQuota(list[index].Name)
if err == nil {
list[index].Usage = usage
}
}
}
return total, list, nil
}
func getUsage(namespace, resource string) int {
ctl := ResourceControllers.Controllers[resource]
return ctl.CountWithConditions(fmt.Sprintf("namespace = '%s' ", namespace))
}
func (ctl *NamespaceCtl) GetNamespaceQuota(namespace string) (v1.ResourceList, error) {
usage := make(v1.ResourceList)
resourceList := []string{Daemonsets, Deployments, Ingresses, Roles, Services, Statefulsets, PersistentVolumeClaim, Pods, Jobs, Cronjobs}
for _, resourceName := range resourceList {
used := getUsage(namespace, resourceName)
var quantity resource.Quantity
quantity.Set(int64(used))
usage[v1.ResourceName(resourceName)] = quantity
}
podCtl := ResourceControllers.Controllers[Pods]
var quantity resource.Quantity
used := podCtl.CountWithConditions(fmt.Sprintf("status=\"%s\" And namespace=\"%s\"", "Running", namespace))
quantity.Set(int64(used))
usage["runningPods"] = quantity
return usage, nil
}
func (ctl *NamespaceCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,188 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
const NodeRoleLabel = "node-role.kubernetes.io/"
func (ctl *NodeCtl) generateObject(item v1.Node) *Node {
var status, ip, displayName, msgStr string
var msg, role []string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
createTime := item.ObjectMeta.CreationTimestamp.Time
annotation := item.Annotations
// in case of multiple roles
for label, _ := range item.Labels {
if strings.HasPrefix(label, NodeRoleLabel) {
if parts := strings.Split(label, "/"); len(parts) == 2 {
role = append(role, parts[1])
}
}
}
for _, condition := range item.Status.Conditions {
if condition.Type == "Ready" {
if condition.Status == "True" {
status = Running
} else {
status = Error
}
} else {
if condition.Status == "True" {
msg = append(msg, condition.Reason)
}
}
}
if len(msg) > 0 {
msgStr = strings.Join(msg, ",")
if status == Running {
status = Warning
}
}
for _, address := range item.Status.Addresses {
if address.Type == "InternalIP" {
ip = address.Address
}
}
object := &Node{
Name: name,
DisplayName: displayName,
Ip: ip,
Status: status,
CreateTime: createTime,
Annotation: MapString{annotation},
Taints: Taints{item.Spec.Taints},
Msg: msgStr,
Role: strings.Join(role, ","),
Labels: MapString{item.Labels}}
return object
}
func (ctl *NodeCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *NodeCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Node{}) {
db.DropTable(&Node{})
}
db = db.CreateTable(&Node{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *NodeCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s failed, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *NodeCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().Nodes().Lister()
informer := informerFactory.Core().V1().Nodes().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Node)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Node)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Node
object := obj.(*v1.Node)
db.Where("name=? ", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *NodeCtl) CountWithConditions(conditions string) int {
var object Node
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *NodeCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Node
var object Node
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *NodeCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,291 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"encoding/json"
"fmt"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
const inUse = "kubesphere.io/in_use_pods"
func (ctl *PodCtl) addAnnotationToPvc(item v1.Pod) {
volumes := item.Spec.Volumes
for _, volume := range volumes {
pvc := volume.PersistentVolumeClaim
if pvc != nil {
name := pvc.ClaimName
Pvc, _ := ctl.K8sClient.CoreV1().PersistentVolumeClaims(item.Namespace).Get(name, metaV1.GetOptions{})
if Pvc.Annotations == nil {
Pvc.Annotations = make(map[string]string)
}
annotation := Pvc.Annotations
if len(annotation[inUse]) == 0 {
pods := []string{item.Name}
str, _ := json.Marshal(pods)
annotation[inUse] = string(str)
} else {
var pods []string
json.Unmarshal([]byte(annotation[inUse]), &pods)
for _, pod := range pods {
if pod == item.Name {
return
}
}
pods = append(pods, item.Name)
str, _ := json.Marshal(pods)
annotation[inUse] = string(str)
}
Pvc.Annotations = annotation
ctl.K8sClient.CoreV1().PersistentVolumeClaims(item.Namespace).Update(Pvc)
}
}
}
func (ctl *PodCtl) delAnnotationFromPvc(item v1.Pod) {
volumes := item.Spec.Volumes
for _, volume := range volumes {
pvc := volume.PersistentVolumeClaim
if pvc != nil {
name := pvc.ClaimName
Pvc, _ := ctl.K8sClient.CoreV1().PersistentVolumeClaims(item.Namespace).Get(name, metaV1.GetOptions{})
if Pvc.Annotations == nil {
Pvc.Annotations = make(map[string]string)
}
annotation := Pvc.Annotations
var pods []string
json.Unmarshal([]byte(annotation[inUse]), pods)
for index, pod := range pods {
if pod == item.Name {
pods = append(pods[:index], pods[index+1:]...)
}
}
str, _ := json.Marshal(pods)
annotation[inUse] = string(str)
ctl.K8sClient.CoreV1().PersistentVolumeClaims(item.Namespace).Update(Pvc)
}
}
}
func getStatusAndRestartCount(pod v1.Pod) (string, int) {
status := string(pod.Status.Phase)
restarts := 0
if pod.Status.Reason != "" {
status = pod.Status.Reason
}
initializing := false
for i := range pod.Status.InitContainerStatuses {
container := pod.Status.InitContainerStatuses[i]
restarts += int(container.RestartCount)
switch {
case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
continue
case container.State.Terminated != nil:
// initialization is failed
if len(container.State.Terminated.Reason) == 0 {
if container.State.Terminated.Signal != 0 {
status = fmt.Sprintf("Init:Signal:%d", container.State.Terminated.Signal)
} else {
status = fmt.Sprintf("Init:ExitCode:%d", container.State.Terminated.ExitCode)
}
} else {
status = "Init:" + container.State.Terminated.Reason
}
initializing = true
case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing":
status = "Init:" + container.State.Waiting.Reason
initializing = true
default:
status = fmt.Sprintf("Init:%d/%d", i, len(pod.Spec.InitContainers))
initializing = true
}
break
}
if !initializing {
restarts = 0
hasRunning := false
for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
container := pod.Status.ContainerStatuses[i]
restarts += int(container.RestartCount)
if container.State.Waiting != nil && container.State.Waiting.Reason != "" {
status = container.State.Waiting.Reason
} else if container.State.Terminated != nil && container.State.Terminated.Reason != "" {
status = container.State.Terminated.Reason
} else if container.State.Terminated != nil && container.State.Terminated.Reason == "" {
if container.State.Terminated.Signal != 0 {
status = fmt.Sprintf("Signal:%d", container.State.Terminated.Signal)
} else {
status = fmt.Sprintf("ExitCode:%d", container.State.Terminated.ExitCode)
}
} else if container.Ready && container.State.Running != nil {
hasRunning = true
}
}
// change pod status back to "Running" if there is at least one container still reporting as "Running" status
if status == "Completed" && hasRunning {
status = "Running"
}
}
if pod.DeletionTimestamp != nil && pod.Status.Reason == "NodeLost" {
status = "Unknown"
} else if pod.DeletionTimestamp != nil {
status = "Terminating"
}
return status, restarts
}
func (ctl *PodCtl) generateObject(item v1.Pod) *Pod {
var ownerKind, ownerName string
// For ReplicaSet,ReplicaController,DaemonSet,StatefulSet,Job,CronJob, k8s will automatically
// set ownerReference for pods, in case of setting ownerReference manually.
if item.OwnerReferences != nil && len(item.OwnerReferences) > 0 {
ownerKind = item.OwnerReferences[0].Kind
ownerName = item.OwnerReferences[0].Name
}
object := &Pod{
Namespace: item.Namespace,
Name: item.Name,
Node: item.Spec.NodeName,
Status: item.Status,
CreateTime: item.CreationTimestamp.Time,
OwnerKind: ownerKind,
OwnerName: ownerName,
Spec: item.Spec,
Metadata: item.ObjectMeta,
Kind: item.TypeMeta.Kind,
APIVersion: item.TypeMeta.APIVersion,
}
return object
}
func (ctl *PodCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *PodCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Pod{}) {
db.DropTable(&Pod{})
}
db = db.CreateTable(&Pod{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *PodCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *PodCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().Pods().Lister()
informer := informerFactory.Core().V1().Pods().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Pod)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
ctl.addAnnotationToPvc(*object)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Pod)
mysqlObject := ctl.generateObject(*object)
ctl.addAnnotationToPvc(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Pod
object := obj.(*v1.Pod)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
ctl.delAnnotationFromPvc(*object)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *PodCtl) CountWithConditions(conditions string) int {
var object Pod
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *PodCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Pod
var object Pod
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *PodCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,191 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
createTime := item.CreationTimestamp.Time
status := fmt.Sprintf("%s", item.Status.Phase)
if item.DeletionTimestamp != nil {
status = "Terminating"
}
var capacity, storageClass, accessModeStr string
if createTime.IsZero() {
createTime = time.Now()
}
if storage, exist := item.Status.Capacity["storage"]; exist {
capacity = storage.String()
}
if len(item.Annotations["volume.beta.kubernetes.io/storage-class"]) > 0 {
storageClass = item.Annotations["volume.beta.kubernetes.io/storage-class"]
}
if item.Spec.StorageClassName != nil {
storageClass = *item.Spec.StorageClassName
}
var accessModeList []string
for _, accessMode := range item.Status.AccessModes {
accessModeList = append(accessModeList, string(accessMode))
}
accessModeStr = strings.Join(accessModeList, ",")
object := &Pvc{
Namespace: namespace,
Name: name,
DisplayName: displayName,
Status: status,
Capacity: capacity,
AccessMode: accessModeStr,
StorageClassName: storageClass,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
}
return object
}
func (ctl *PvcCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *PvcCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Pvc{}) {
db.DropTable(&Pvc{})
}
db = db.CreateTable(&Pvc{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *PvcCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *PvcCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().PersistentVolumeClaims().Lister()
informer := informerFactory.Core().V1().PersistentVolumeClaims().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.PersistentVolumeClaim)
mysqlObject := ctl.generateObject(object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.PersistentVolumeClaim)
mysqlObject := ctl.generateObject(object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Pvc
object := obj.(*v1.PersistentVolumeClaim)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *PvcCtl) CountWithConditions(conditions string) int {
var object Pvc
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *PvcCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Pvc
var object Pvc
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index := range list {
inUsePods := list[index].Annotation.Values[inUse]
var pods []string
json.Unmarshal([]byte(inUsePods), &pods)
if len(pods) > 0 {
list[index].InUse = true
} else {
list[index].InUse = false
}
}
return total, list, nil
}
func (ctl *PvcCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,64 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"k8s.io/client-go/informers"
)
func (ctl *ReplicaSetCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ReplicaSetCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ReplicaSetCtl) total() int {
return 0
}
func (ctl *ReplicaSetCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().ReplicaSets().Lister()
informer := informerFactory.Apps().V1().ReplicaSets().Informer()
ctl.informer = informer
}
func (ctl *ReplicaSetCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ReplicaSetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, nil
}
func (ctl *ReplicaSetCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,57 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"github.com/pkg/errors"
"k8s.io/client-go/informers"
)
func (ctl *RoleBindingCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *RoleBindingCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *RoleBindingCtl) total() int {
return 0
}
func (ctl *RoleBindingCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Rbac().V1().RoleBindings().Lister()
ctl.informer = informerFactory.Rbac().V1().RoleBindings().Informer()
}
func (ctl *RoleBindingCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *RoleBindingCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, errors.New("not implement")
}
func (ctl *RoleBindingCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,164 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *RoleCtl) generateObject(item v1.Role) *Role {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) == 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
if strings.HasPrefix(name, systemPrefix) || item.Annotations == nil || len(item.Annotations[creator]) == 0 {
return nil
}
namespace := item.Namespace
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
object := &Role{
Namespace: namespace,
Name: name,
DisplayName: displayName,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
}
return object
}
func (ctl *RoleCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *RoleCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Role{}) {
db.DropTable(&Role{})
}
db = db.CreateTable(&Role{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
if obj != nil {
db.Create(obj)
}
}
ctl.informer.Run(stopChan)
}
func (ctl *RoleCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s failed, reason:%s", err, ctl.Name())
return 0
}
count := 0
for _, item := range list {
if !strings.HasPrefix(item.Name, systemPrefix) && item.Annotations != nil && len(item.Annotations[creator]) > 0 {
count++
}
}
return count
}
func (ctl *RoleCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Rbac().V1().Roles().Lister()
informer := informerFactory.Rbac().V1().Roles().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Role)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Create(mysqlObject)
}
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Role)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Save(mysqlObject)
}
},
DeleteFunc: func(obj interface{}) {
var item Role
object := obj.(*v1.Role)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *RoleCtl) CountWithConditions(conditions string) int {
var object Role
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *RoleCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Role
var object Role
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *RoleCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,156 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"errors"
"fmt"
"time"
"github.com/golang/glog"
"github.com/jinzhu/gorm"
"k8s.io/client-go/kubernetes"
"os"
"sync"
"syscall"
"kubesphere.io/kubesphere/pkg/client"
)
type resourceControllers struct {
Controllers map[string]Controller
k8sClient *kubernetes.Clientset
}
var ResourceControllers resourceControllers
func (rec *resourceControllers) runController(name string, stopChan chan struct{}, wg *sync.WaitGroup) {
var ctl Controller
attr := CommonAttribute{DB: client.NewDBClient(), K8sClient: rec.k8sClient, stopChan: stopChan,
aliveChan: make(chan struct{}), Name: name}
switch name {
case Deployments:
ctl = &DeploymentCtl{CommonAttribute: attr}
case Statefulsets:
ctl = &StatefulsetCtl{CommonAttribute: attr}
case Daemonsets:
ctl = &DaemonsetCtl{CommonAttribute: attr}
case Ingresses:
ctl = &IngressCtl{CommonAttribute: attr}
case PersistentVolumeClaim:
ctl = &PvcCtl{CommonAttribute: attr}
case Roles:
ctl = &RoleCtl{CommonAttribute: attr}
case ClusterRoles:
ctl = &ClusterRoleCtl{CommonAttribute: attr}
case Services:
ctl = &ServiceCtl{CommonAttribute: attr}
case Pods:
ctl = &PodCtl{CommonAttribute: attr}
case Namespaces:
ctl = &NamespaceCtl{CommonAttribute: attr}
case StorageClasses:
ctl = &StorageClassCtl{CommonAttribute: attr}
case Jobs:
ctl = &JobCtl{CommonAttribute: attr}
case Cronjobs:
ctl = &CronJobCtl{CommonAttribute: attr}
case Nodes:
ctl = &NodeCtl{CommonAttribute: attr}
case Replicasets:
ctl = &ReplicaSetCtl{CommonAttribute: attr}
case ControllerRevisions:
ctl = &ControllerRevisionCtl{CommonAttribute: attr}
case ConfigMaps:
ctl = &ConfigMapCtl{CommonAttribute: attr}
case Secrets:
ctl = &SecretCtl{CommonAttribute: attr}
case ClusterRoleBindings:
ctl = &ClusterRoleBindingCtl{CommonAttribute: attr}
case RoleBindings:
ctl = &RoleBindingCtl{CommonAttribute: attr}
default:
return
}
rec.Controllers[name] = ctl
wg.Add(1)
go listAndWatch(ctl, wg)
}
func dbHealthCheck(db *gorm.DB) {
defer db.Close()
for {
count := 0
var err error
for k := 0; k < 5; k++ {
err = db.DB().Ping()
if err != nil {
count++
}
time.Sleep(5 * time.Second)
}
if count > 3 {
syscall.Kill(os.Getpid(), syscall.SIGTERM)
}
}
}
func Run(stopChan chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
k8sClient := client.NewK8sClient()
ResourceControllers = resourceControllers{k8sClient: k8sClient, Controllers: make(map[string]Controller)}
for _, item := range []string{Deployments, Statefulsets, Daemonsets, PersistentVolumeClaim, Pods, Services,
Ingresses, Roles, RoleBindings, ClusterRoles, ClusterRoleBindings, Namespaces, StorageClasses, Jobs, Cronjobs, Nodes, Replicasets,
ControllerRevisions, ConfigMaps, Secrets} {
ResourceControllers.runController(item, stopChan, wg)
}
go dbHealthCheck(client.NewDBClient())
for {
for ctlName, controller := range ResourceControllers.Controllers {
select {
case <-stopChan:
return
case _, isClose := <-controller.chanAlive():
if !isClose {
glog.Errorf("controller %s have stopped, restart it", ctlName)
ResourceControllers.runController(ctlName, stopChan, wg)
}
default:
time.Sleep(3 * time.Second)
}
}
}
}
func GetLister(controller string) (interface{}, error) {
if ctl, ok := ResourceControllers.Controllers[controller]; ok {
if ctl.Lister() != nil {
return ctl.Lister(), nil
}
}
return nil, errors.New(fmt.Sprintf("lister of %s not alive", controller))
}

View File

@@ -1,157 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *SecretCtl) generateObject(item v1.Secret) *Secret {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
object := &Secret{
Name: item.Name,
Namespace: item.Namespace,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
DisplayName: displayName,
Entries: len(item.Data),
Type: string(item.Type),
}
return object
}
func (ctl *SecretCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *SecretCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Secret{}) {
db.DropTable(&Secret{})
}
db = db.CreateTable(&Secret{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
if obj != nil {
db.Create(obj)
}
}
ctl.informer.Run(stopChan)
}
func (ctl *SecretCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *SecretCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().Secrets().Lister()
informer := informerFactory.Core().V1().Secrets().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Secret)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Create(mysqlObject)
}
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Secret)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Save(mysqlObject)
}
},
DeleteFunc: func(obj interface{}) {
var item Secret
object := obj.(*v1.Secret)
db.Where("name=?", object.Name).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *SecretCtl) CountWithConditions(conditions string) int {
var object Secret
if strings.Contains(conditions, "namespace") {
conditions = ""
}
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *SecretCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var object Secret
var list []Secret
var total int
if len(order) == 0 {
order = "createTime desc"
}
db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *SecretCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,245 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"fmt"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func loadBalancerStatusStringer(item v1.Service) string {
ingress := item.Status.LoadBalancer.Ingress
result := sets.NewString()
for i := range ingress {
if ingress[i].IP != "" {
result.Insert(ingress[i].IP)
} else if ingress[i].Hostname != "" {
result.Insert(ingress[i].Hostname)
}
}
r := strings.Join(result.List(), ",")
return r
}
func getExternalIp(item v1.Service) string {
switch item.Spec.Type {
case "ClusterIP", "NodePort":
if len(item.Spec.ExternalIPs) > 0 {
return strings.Join(item.Spec.ExternalIPs, ",")
}
case "ExternalName":
return item.Spec.ExternalName
case "LoadBalancer":
lbIps := loadBalancerStatusStringer(item)
if len(item.Spec.ExternalIPs) > 0 {
results := []string{}
if len(lbIps) > 0 {
results = append(results, strings.Split(lbIps, ",")...)
}
results = append(results, item.Spec.ExternalIPs...)
return strings.Join(results, ",")
}
if len(lbIps) > 0 {
return lbIps
}
return "<pending>"
}
return ""
}
func generateSvcObject(item v1.Service) *Service {
var app string
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
createTime := item.CreationTimestamp.Time
externalIp := getExternalIp(item)
serviceType := item.Spec.Type
vip := item.Spec.ClusterIP
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
}
ports := ""
var nodePorts []string
if createTime.IsZero() {
createTime = time.Now()
}
if len(item.Spec.ClusterIP) == 0 || item.Spec.ClusterIP == "None" {
if len(item.Spec.Selector) != 0 {
serviceType = "Headless(Selector)"
}
if item.Spec.Type == v1.ServiceTypeExternalName {
serviceType = "Headless(ExternalName)"
}
} else {
serviceType = "Virtual IP"
}
if len(item.Spec.ExternalIPs) > 0 {
externalIp = strings.Join(item.Spec.ExternalIPs, ",")
}
for _, portItem := range item.Spec.Ports {
port := portItem.Port
targetPort := portItem.TargetPort.String()
protocol := portItem.Protocol
ports += fmt.Sprintf("%d:%s/%s,", port, targetPort, protocol)
if portItem.NodePort != 0 {
nodePorts = append(nodePorts, fmt.Sprintf("%d:%d/%s", port, portItem.NodePort, protocol))
}
}
if len(ports) == 0 {
ports = "-"
} else {
ports = ports[0 : len(ports)-1]
}
object := &Service{
Namespace: namespace,
Name: name,
DisplayName: displayName,
ServiceType: string(serviceType),
ExternalIp: externalIp,
VirtualIp: vip,
CreateTime: createTime,
Ports: ports,
NodePorts: strings.Join(nodePorts, ","),
Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
App: app,
}
return object
}
func (ctl *ServiceCtl) generateObject(item v1.Service) *Service {
return generateSvcObject(item)
}
func (ctl *ServiceCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ServiceCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Service{}) {
db.DropTable(&Service{})
}
db = db.CreateTable(&Service{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *ServiceCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *ServiceCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().Services().Lister()
informer := informerFactory.Core().V1().Services().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Service)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Service)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Service
object := obj.(*v1.Service)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *ServiceCtl) CountWithConditions(conditions string) int {
var object Service
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *ServiceCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Service
var object Service
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *ServiceCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,172 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"github.com/golang/glog"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *StatefulsetCtl) generateObject(item v1.StatefulSet) *Statefulset {
var app string
var status string
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.ReadyReplicas
desirePodNum := *item.Spec.Replicas
createTime := item.CreationTimestamp.Time
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if createTime.IsZero() {
createTime = time.Now()
}
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
}
if item.Annotations["state"] == "stop" {
status = Stopped
} else {
if availablePodNum >= desirePodNum {
status = Running
} else {
status = Updating
}
}
statefulSetObject := &Statefulset{
Namespace: namespace,
Name: name,
DisplayName: displayName,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
}
return statefulSetObject
}
func (ctl *StatefulsetCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *StatefulsetCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Statefulset{}) {
db.DropTable(&Statefulset{})
}
db = db.CreateTable(&Statefulset{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *StatefulsetCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *StatefulsetCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().StatefulSets().Lister()
informer := informerFactory.Apps().V1().StatefulSets().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.StatefulSet)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.StatefulSet)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Statefulset
object := obj.(*v1.StatefulSet)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *StatefulsetCtl) CountWithConditions(conditions string) int {
var object Statefulset
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *StatefulsetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Statefulset
var object Statefulset
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *StatefulsetCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,261 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"fmt"
"time"
utilversion "k8s.io/kubernetes/pkg/util/version"
"github.com/golang/glog"
coreV1 "k8s.io/api/core/v1"
"k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/api/errors"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
"k8s.io/kubernetes/pkg/apis/core"
)
const (
rbdPluginName = "kubernetes.io/rbd"
rbdUserSecretNameKey = "userSecretName"
)
func (ctl *StorageClassCtl) generateObject(item v1.StorageClass) *StorageClass {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
createTime := item.CreationTimestamp.Time
isDefault := false
provisioner := item.Provisioner
if item.Annotations["storageclass.beta.kubernetes.io/is-default-class"] == "true" {
isDefault = true
}
if createTime.IsZero() {
createTime = time.Now()
}
object := &StorageClass{
Name: name,
DisplayName: displayName,
CreateTime: createTime,
IsDefault: isDefault,
Annotation: MapString{item.Annotations},
Provisioner: provisioner,
}
return object
}
func (ctl *StorageClassCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *StorageClassCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&StorageClass{}) {
db.DropTable(&StorageClass{})
}
db = db.CreateTable(&StorageClass{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *StorageClassCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *StorageClassCtl) createCephSecretAfterNewSc(item v1.StorageClass) {
// Kubernetes version must < 1.11.0
verInfo, err := ctl.K8sClient.ServerVersion()
if err != nil {
glog.Error("consult k8s server error: ", err)
return
}
if !utilversion.MustParseSemantic(verInfo.String()).LessThan(utilversion.MustParseSemantic("v1.11.0")) {
glog.Infof("disable Ceph secret controller due to k8s version %s >= v1.11.0", verInfo.String())
return
}
// Find Ceph secret in the new storage class
if item.Provisioner != rbdPluginName {
return
}
var secret *coreV1.Secret
if secretName, ok := item.Parameters[rbdUserSecretNameKey]; ok {
secret, err = ctl.K8sClient.CoreV1().Secrets(core.NamespaceSystem).Get(secretName, metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
glog.Errorf("cannot find secret %s in namespace %s", secretName, core.NamespaceSystem)
return
}
glog.Error("failed to find secret, error: ", err)
return
}
glog.Infof("succeed to find secret %s in namespace %s", secret.GetName(), secret.GetNamespace())
} else {
glog.Errorf("failed to find user secret name in storage class %s", item.GetName())
return
}
// Create or update Ceph secret in each namespace
nsList, err := ctl.K8sClient.CoreV1().Namespaces().List(metaV1.ListOptions{})
if err != nil {
glog.Error("failed to list namespace, error: ", err)
return
}
for _, ns := range nsList.Items {
if ns.GetName() == core.NamespaceSystem {
glog.Infof("skip creating Ceph secret in namespace %s", core.NamespaceSystem)
continue
}
newSecret := &coreV1.Secret{
TypeMeta: metaV1.TypeMeta{
Kind: secret.Kind,
APIVersion: secret.APIVersion,
},
ObjectMeta: metaV1.ObjectMeta{
Name: secret.GetName(),
Namespace: ns.GetName(),
Labels: secret.GetLabels(),
Annotations: secret.GetAnnotations(),
DeletionGracePeriodSeconds: secret.GetDeletionGracePeriodSeconds(),
ClusterName: secret.GetClusterName(),
},
Data: secret.Data,
StringData: secret.StringData,
Type: secret.Type,
}
_, err := ctl.K8sClient.CoreV1().Secrets(newSecret.GetNamespace()).Get(newSecret.GetName(), metaV1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
// Create secret
_, err := ctl.K8sClient.CoreV1().Secrets(newSecret.GetNamespace()).Create(newSecret)
if err != nil {
glog.Errorf("failed to create secret in namespace %s, error: %v", newSecret.GetNamespace(), err)
} else {
glog.Infof("succeed to create secret %s in namespace %s", newSecret.GetName(),
newSecret.GetNamespace())
}
} else {
glog.Errorf("failed to find secret in namespace %s, error: %v", newSecret.GetNamespace(), err)
}
} else {
// Update secret
_, err = ctl.K8sClient.CoreV1().Secrets(newSecret.GetNamespace()).Update(newSecret)
if err != nil {
glog.Errorf("failed to update secret in namespace %s, error: %v", newSecret.GetNamespace(), err)
continue
} else {
glog.Infof("succeed to update secret %s in namespace %s", newSecret.GetName(), newSecret.GetNamespace())
}
}
}
}
func (ctl *StorageClassCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Storage().V1().StorageClasses().Lister()
informer := informerFactory.Storage().V1().StorageClasses().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.StorageClass)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
ctl.createCephSecretAfterNewSc(*object)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.StorageClass)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item StorageClass
object := obj.(*v1.StorageClass)
db.Where("name=?", object.Name).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *StorageClassCtl) CountWithConditions(conditions string) int {
var object StorageClass
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *StorageClassCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []StorageClass
var object StorageClass
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, storageClass := range list {
name := storageClass.Name
pvcCtl := ResourceControllers.Controllers[PersistentVolumeClaim]
list[index].Count = pvcCtl.CountWithConditions(fmt.Sprintf("storage_class=\"%s\"", name))
}
return total, list, nil
}
func (ctl *StorageClassCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -1,571 +0,0 @@
/*
Copyright 2018 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 controllers
import (
"time"
"github.com/golang/glog"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
"database/sql/driver"
"encoding/json"
"errors"
"github.com/jinzhu/gorm"
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
appV1 "k8s.io/client-go/listers/apps/v1"
batchv1 "k8s.io/client-go/listers/batch/v1"
batchv1beta1 "k8s.io/client-go/listers/batch/v1beta1"
coreV1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/listers/extensions/v1beta1"
rbacV1 "k8s.io/client-go/listers/rbac/v1"
storageV1 "k8s.io/client-go/listers/storage/v1"
"k8s.io/client-go/tools/cache"
)
const (
resyncCircle = 600
Stopped = "stopped"
PvcPending = "pending"
Running = "running"
Updating = "updating"
Failed = "failed"
Unfinished = "unfinished"
Completed = "completed"
Pause = "pause"
Warning = "warning"
Error = "error"
DisplayName = "displayName"
creator = "creator"
Pods = "pods"
Deployments = "deployments"
Daemonsets = "daemonsets"
Statefulsets = "statefulsets"
Namespaces = "namespaces"
Ingresses = "ingresses"
PersistentVolumeClaim = "persistent-volume-claims"
Roles = "roles"
RoleBindings = "role-bindings"
ClusterRoles = "cluster-roles"
ClusterRoleBindings = "cluster-role-bindings"
Services = "services"
StorageClasses = "storage-classes"
Applications = "applications"
Jobs = "jobs"
Cronjobs = "cronjobs"
Nodes = "nodes"
Replicasets = "replicasets"
ControllerRevisions = "controllerrevisions"
ConfigMaps = "configmaps"
Secrets = "secrets"
)
type MapString struct {
Values map[string]string `json:"values" gorm:"type:TEXT"`
}
func (annotation *MapString) Scan(val interface{}) error {
switch val := val.(type) {
case string:
return json.Unmarshal([]byte(val), annotation)
case []byte:
return json.Unmarshal(val, annotation)
default:
return errors.New("not support")
}
return nil
}
func (annotation MapString) Value() (driver.Value, error) {
bytes, err := json.Marshal(annotation)
return string(bytes), err
}
type Taints struct {
Values []v1.Taint `json:"values" gorm:"type:TEXT"`
}
func (taints *Taints) Scan(val interface{}) error {
switch val := val.(type) {
case string:
return json.Unmarshal([]byte(val), taints)
case []byte:
return json.Unmarshal(val, taints)
default:
return errors.New("not support")
}
return nil
}
func (taints Taints) Value() (driver.Value, error) {
bytes, err := json.Marshal(taints)
return string(bytes), err
}
type Deployment struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
App string `json:"app,omitempty"`
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Status string `json:"status"`
Labels MapString `json:"labels"`
Annotation MapString `json:"annotations"`
UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"`
}
type Statefulset struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Daemonset struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Status string `json:"status"`
NodeSelector string `json:"nodeSelector, omitempty"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Service struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
ServiceType string `gorm:"column:type" json:"type,omitempty"`
App string `json:"app,omitempty"`
VirtualIp string `gorm:"column:virtualIp" json:"virtualIp,omitempty"`
ExternalIp string `gorm:"column:externalIp" json:"externalIp,omitempty"`
Ports string `json:"ports,omitempty"`
NodePorts string `gorm:"column:nodePorts" json:"nodePorts,omitempty"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Pvc struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
Status string `json:"status,omitempty"`
Capacity string `json:"capacity,omitempty"`
AccessMode string `gorm:"column:accessMode" json:"accessMode,omitempty"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
StorageClassName string `gorm:"column:storage_class" json:"storage_class,omitempty"`
InUse bool `gorm:"column:inUse" json:"inUse"`
}
type ingressRule struct {
Host string `json:"host"`
Path string `json:"path"`
Service string `json:"service"`
Port int32 `json:"port"`
}
type Ingress struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
Ip string `json:"ip,omitempty"`
Rules string `gorm:"type:text" json:"rules, omitempty"`
TlsTermination string `gorm:"column:tlsTermination" json:"tlsTermination,omitempty"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Pod struct {
// search and sort field, not seen in response
Name string `gorm:"primary_key" json:"-"`
Namespace string `gorm:"primary_key" json:"-"`
Node string `json:"-"`
OwnerKind string `gorm:"column:ownerKind" json:"-"`
OwnerName string `gorm:"column:ownerName" json:"-"`
CreateTime time.Time `gorm:"column:createTime" json:"-"`
// Kubernetes Standard Pod Specification
Kind string `json:"kind,omitempty"`
APIVersion string `gorm:"column:apiVersion" json:"apiVersion,omitempty"`
Spec v1.PodSpec `sql:"-" json:"spec,omitempty"`
Metadata v12.ObjectMeta `sql:"-" json:"metadata,omitempty"`
Status v1.PodStatus `sql:"-" json:"status,omitempty"`
// shadow field, used only for database
MetadataString string `gorm:"column:metadata;type:text" json:"-"`
SpecString string `gorm:"column:podSpec;type:text" json:"-"`
StatusString string `gorm:"column:status;type:text" json:"-"`
}
func (pod *Pod) AfterFind(scope *gorm.Scope) (err error) {
if err = json.Unmarshal([]byte(pod.SpecString), &pod.Spec); err != nil {
glog.Errorln(err)
}
if err = json.Unmarshal([]byte(pod.MetadataString), &pod.Metadata); err != nil {
glog.Errorln(err)
}
if err = json.Unmarshal([]byte(pod.StatusString), &pod.Status); err != nil {
glog.Errorln(err)
}
return nil
}
func (pod *Pod) BeforeSave(scope *gorm.Scope) (err error) {
if bytes, err := json.Marshal(pod.Spec); err == nil {
pod.SpecString = string(bytes)
} else {
glog.Errorln(err)
}
if bytes, err := json.Marshal(pod.Metadata); err == nil {
pod.MetadataString = string(bytes)
} else {
glog.Errorln(err)
}
if bytes, err := json.Marshal(pod.Status); err == nil {
pod.StatusString = string(bytes)
} else {
glog.Errorln(err)
}
return nil
}
type Container struct {
Name string `json:"name"`
Ready bool `json:"ready,omitempty"`
Image string `json:"image"`
Resources v1.ResourceRequirements `json:"resources"`
Ports []v1.ContainerPort `json:"ports"`
}
type Containers []Container
func (containers *Containers) Scan(val interface{}) error {
switch val := val.(type) {
case string:
return json.Unmarshal([]byte(val), containers)
case []byte:
return json.Unmarshal(val, containers)
default:
return errors.New("not support")
}
return nil
}
func (containers Containers) Value() (driver.Value, error) {
bytes, err := json.Marshal(containers)
return string(bytes), err
}
type Role struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type ClusterRole struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Namespace struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Creator string `json:"creator,omitempty"`
Status string `json:"status"`
Descrition string `json:"description,omitempty"`
Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Usage v1.ResourceList `gorm:"-" json:"usage,omitempty"`
}
type StorageClass struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Creator string `json:"creator,omitempty"`
Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
IsDefault bool `json:"default"`
Count int `json:"count"`
Provisioner string `json:"provisioner"`
}
type JobRevisions map[int]JobRevision
type JobRevision struct {
Status string `json:"status"`
Reasons []string `json:"reasons"`
Messages []string `json:"messages"`
Succeed int32 `json:"succeed"`
DesirePodNum int32 `json:"desire"`
Failed int32 `json:"failed"`
Uid string `json:"uid"`
StartTime time.Time `json:"start-time"`
CompletionTime time.Time `json:"completion-time"`
}
type Job struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
Completed int32 `json:"completed"`
Desire int32 `json:"desire"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"`
}
type CronJob struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
Active int `json:"active"`
Schedule string `json:"schedule"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
LastScheduleTime *time.Time `gorm:"column:lastScheduleTime" json:"lastScheduleTime,omitempty"`
}
type Node struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Ip string `json:"ip"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
Taints Taints `json:"taints"`
Msg string `json:"msg"`
Role string `json:"role"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type ConfigMap struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Annotation MapString `json:"annotations"`
Entries string `gorm:"type:text" json:"entries"`
}
type Secret struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Annotation MapString `json:"annotations"`
Entries int `json:"entries"`
Type string `json:"type"`
}
type Paging struct {
Limit, Offset, Page int
}
type Controller interface {
chanStop() chan struct{}
chanAlive() chan struct{}
CountWithConditions(condition string) int
total() int
initListerAndInformer()
sync(stopChan chan struct{})
Name() string
CloseDB()
Lister() interface{}
ListWithConditions(condition string, paging *Paging, order string) (int, interface{}, error)
}
type CommonAttribute struct {
K8sClient *kubernetes.Clientset
Name string
DB *gorm.DB
stopChan chan struct{}
aliveChan chan struct{}
}
func (ca *CommonAttribute) chanStop() chan struct{} {
return ca.stopChan
}
func (ca *CommonAttribute) chanAlive() chan struct{} {
return ca.aliveChan
}
func (ca *CommonAttribute) CloseDB() {
ca.DB.Close()
}
type DeploymentCtl struct {
CommonAttribute
lister appV1.DeploymentLister
informer cache.SharedIndexInformer
}
type StatefulsetCtl struct {
CommonAttribute
lister appV1.StatefulSetLister
informer cache.SharedIndexInformer
}
type DaemonsetCtl struct {
CommonAttribute
lister appV1.DaemonSetLister
informer cache.SharedIndexInformer
}
type ServiceCtl struct {
CommonAttribute
lister coreV1.ServiceLister
informer cache.SharedIndexInformer
}
type PvcCtl struct {
CommonAttribute
lister coreV1.PersistentVolumeClaimLister
informer cache.SharedIndexInformer
}
type PodCtl struct {
CommonAttribute
lister coreV1.PodLister
informer cache.SharedIndexInformer
}
type IngressCtl struct {
lister v1beta1.IngressLister
informer cache.SharedIndexInformer
CommonAttribute
}
type NamespaceCtl struct {
CommonAttribute
lister coreV1.NamespaceLister
informer cache.SharedIndexInformer
}
type StorageClassCtl struct {
lister storageV1.StorageClassLister
informer cache.SharedIndexInformer
CommonAttribute
}
type RoleCtl struct {
lister rbacV1.RoleLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ClusterRoleCtl struct {
lister rbacV1.ClusterRoleLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ClusterRoleBindingCtl struct {
lister rbacV1.ClusterRoleBindingLister
informer cache.SharedIndexInformer
CommonAttribute
}
type RoleBindingCtl struct {
lister rbacV1.RoleBindingLister
informer cache.SharedIndexInformer
CommonAttribute
}
type JobCtl struct {
lister batchv1.JobLister
informer cache.SharedIndexInformer
CommonAttribute
}
type CronJobCtl struct {
lister batchv1beta1.CronJobLister
informer cache.SharedIndexInformer
CommonAttribute
}
type NodeCtl struct {
lister coreV1.NodeLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ReplicaSetCtl struct {
lister appV1.ReplicaSetLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ControllerRevisionCtl struct {
lister appV1.ControllerRevisionLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ConfigMapCtl struct {
lister coreV1.ConfigMapLister
informer cache.SharedIndexInformer
CommonAttribute
}
type SecretCtl struct {
lister coreV1.SecretLister
informer cache.SharedIndexInformer
CommonAttribute
}

View File

@@ -1,741 +0,0 @@
package iam
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/golang/glog"
"k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
v12 "k8s.io/client-go/listers/rbac/v1"
"k8s.io/kubernetes/pkg/util/slice"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/controllers"
ksErr "kubesphere.io/kubesphere/pkg/util/errors"
)
const ClusterRoleKind = "ClusterRole"
// Get user list based on workspace role
func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
lister, err := controllers.GetLister(controllers.ClusterRoleBindings)
if err != nil {
return nil, err
}
clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister)
workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName))
if err != nil {
return nil, err
}
names := make([]string, 0)
for _, subject := range workspaceRoleBinding.Subjects {
if subject.Kind == v1.UserKind {
names = append(names, subject.Name)
}
}
users, err := GetUsers(names)
if err != nil {
return nil, err
}
for i := 0; i < len(users); i++ {
users[i].WorkspaceRole = roleName
}
return users, nil
}
func GetUsers(names []string) ([]User, error) {
var users []User
if names == nil || len(names) == 0 {
return make([]User, 0), nil
}
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
if err != nil {
return nil, err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return nil, err
}
if result.StatusCode > 200 {
return nil, ksErr.Wrap(data)
}
err = json.Unmarshal(data, &users)
if err != nil {
return nil, err
}
return users, nil
}
func GetUser(name string) (*User, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
if err != nil {
return nil, err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return nil, err
}
if result.StatusCode > 200 {
return nil, ksErr.Wrap(data)
}
var user User
err = json.Unmarshal(data, &user)
if err != nil {
return nil, err
}
return &user, nil
}
// Get rules
func WorkspaceRoleRules(workspace string, roleName string) (*v1.ClusterRole, []Rule, error) {
clusterRoleName := fmt.Sprintf("system:%s:%s", workspace, roleName)
workspaceRole, err := GetClusterRole(clusterRoleName)
if err != nil {
return nil, nil, err
}
for i := 0; i < len(workspaceRole.Rules); i++ {
workspaceRole.Rules[i].ResourceNames = nil
}
rules := make([]Rule, 0)
for i := 0; i < len(WorkspaceRoleRuleMapping); i++ {
rule := Rule{Name: WorkspaceRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < len(WorkspaceRoleRuleMapping[i].Actions); j++ {
if rulesMatchesAction(workspaceRole.Rules, WorkspaceRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, WorkspaceRoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
workspaceRole.Name = roleName
return workspaceRole, rules, nil
}
func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespace bool, namespaces []string, err error) {
clusterRoles, err := GetClusterRoles(username)
if err != nil {
return false, nil, err
}
clusterRules := make([]v1.PolicyRule, 0)
for _, role := range clusterRoles {
clusterRules = append(clusterRules, role.Rules...)
}
if requiredRule.Size() == 0 {
if RulesMatchesRequired(clusterRules, v1.PolicyRule{
Verbs: []string{"get"},
APIGroups: []string{"kubesphere.io"},
Resources: []string{"workspaces/namespaces"},
}) {
return true, nil, nil
}
} else {
if RulesMatchesRequired(clusterRules, requiredRule) {
return true, nil, nil
}
}
roles, err := GetRoles("", username)
if err != nil {
return false, nil, err
}
rulesMapping := make(map[string][]v1.PolicyRule, 0)
for _, role := range roles {
rules := rulesMapping[role.Namespace]
if rules == nil {
rules = make([]v1.PolicyRule, 0)
}
rules = append(rules, role.Rules...)
rulesMapping[role.Namespace] = rules
}
namespaces = make([]string, 0)
for namespace, rules := range rulesMapping {
if requiredRule.Size() == 0 || RulesMatchesRequired(rules, requiredRule) {
namespaces = append(namespaces, namespace)
}
}
return false, namespaces, nil
}
func GetRole(namespace string, name string) (*v1.Role, error) {
lister, err := controllers.GetLister(controllers.Roles)
if err != nil {
return nil, err
}
roleLister := lister.(v12.RoleLister)
role, err := roleLister.Roles(namespace).Get(name)
if err != nil {
return nil, err
}
return role.DeepCopy(), nil
}
func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) {
lister, err := controllers.GetLister(controllers.ClusterRoleBindings)
if err != nil {
return nil, err
}
clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister)
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
if err != nil {
return nil, err
}
users := make([]string, 0)
for _, s := range clusterRoleBinding.Subjects {
if s.Kind == v1.UserKind && !slice.ContainsString(users, s.Name, nil) {
users = append(users, s.Name)
}
}
return users, nil
}
func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) {
lister, err := controllers.GetLister(controllers.ClusterRoleBindings)
if err != nil {
return nil, err
}
clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister)
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil {
return nil, err
}
items := make([]v1.ClusterRoleBinding, 0)
for _, clusterRoleBinding := range clusterRoleBindings {
if clusterRoleBinding.RoleRef.Name == name {
items = append(items, *clusterRoleBinding)
}
}
return items, nil
}
func GetRoleBindings(namespace string, name string) ([]v1.RoleBinding, error) {
lister, err := controllers.GetLister(controllers.RoleBindings)
if err != nil {
return nil, err
}
roleBindingLister := lister.(v12.RoleBindingLister)
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
items := make([]v1.RoleBinding, 0)
for _, roleBinding := range roleBindings {
if roleBinding.RoleRef.Name == name {
items = append(items, *roleBinding)
}
}
return items, nil
}
func GetClusterRole(name string) (*v1.ClusterRole, error) {
lister, err := controllers.GetLister(controllers.ClusterRoles)
if err != nil {
return nil, err
}
clusterRoleLister := lister.(v12.ClusterRoleLister)
role, err := clusterRoleLister.Get(name)
if err != nil {
return nil, err
}
return role.DeepCopy(), nil
}
func GetRoles(namespace string, username string) ([]v1.Role, error) {
lister, err := controllers.GetLister(controllers.RoleBindings)
if err != nil {
return nil, err
}
roleBindingLister := lister.(v12.RoleBindingLister)
lister, err = controllers.GetLister(controllers.Roles)
if err != nil {
return nil, err
}
roleLister := lister.(v12.RoleLister)
lister, err = controllers.GetLister(controllers.ClusterRoles)
if err != nil {
return nil, err
}
clusterRoleLister := lister.(v12.ClusterRoleLister)
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
roles := make([]v1.Role, 0)
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && subject.Name == username {
if roleBinding.RoleRef.Kind == ClusterRoleKind {
clusterRole, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
if err == nil {
var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules}
role.Namespace = roleBinding.Namespace
roles = append(roles, role)
break
} else if apierrors.IsNotFound(err) {
glog.Infoln(err.Error())
break
} else {
return nil, err
}
} else {
if subject.Kind == v1.UserKind && subject.Name == username {
role, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name)
if err == nil {
roles = append(roles, *role)
break
} else if apierrors.IsNotFound(err) {
glog.Infoln(err.Error())
break
} else {
return nil, err
}
}
}
}
}
}
return roles, nil
}
// Get cluster roles by username
func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
lister, err := controllers.GetLister(controllers.ClusterRoleBindings)
if err != nil {
return nil, err
}
clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister)
lister, err = controllers.GetLister(controllers.ClusterRoles)
if err != nil {
return nil, err
}
clusterRoleLister := lister.(v12.ClusterRoleLister)
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil {
return nil, err
}
roles := make([]v1.ClusterRole, 0)
for _, roleBinding := range clusterRoleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && subject.Name == username {
if roleBinding.RoleRef.Kind == ClusterRoleKind {
role, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
if err == nil {
role = role.DeepCopy()
if role.Annotations == nil {
role.Annotations = make(map[string]string, 0)
}
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = roleBinding.Name
if roleBinding.Annotations != nil &&
roleBinding.Annotations["rbac.authorization.k8s.io/clusterrole"] == roleBinding.RoleRef.Name {
role.Annotations["rbac.authorization.k8s.io/clusterrole"] = "true"
}
roles = append(roles, *role)
break
} else if apierrors.IsNotFound(err) {
glog.Warning(err)
break
} else {
return nil, err
}
}
}
}
}
return roles, nil
}
func GetUserRules(username string) (map[string][]Rule, error) {
items := make(map[string][]Rule, 0)
userRoles, err := GetRoles("", username)
if err != nil {
return nil, err
}
rulesMapping := make(map[string][]v1.PolicyRule, 0)
for _, role := range userRoles {
rules := rulesMapping[role.Namespace]
if rules == nil {
rules = make([]v1.PolicyRule, 0)
}
rules = append(rules, role.Rules...)
rulesMapping[role.Namespace] = rules
}
for namespace, policyRules := range rulesMapping {
rules := convertToRules(policyRules)
if len(rules) > 0 {
items[namespace] = rules
}
}
return items, nil
}
func convertToRules(policyRules []v1.PolicyRule) []Rule {
rules := make([]Rule, 0)
for i := 0; i < (len(RoleRuleMapping)); i++ {
rule := Rule{Name: RoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(RoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(policyRules, RoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules
}
func GetUserClusterRules(username string) ([]Rule, error) {
rules := make([]Rule, 0)
clusterRoles, err := GetClusterRoles(username)
if err != nil {
return nil, err
}
clusterRules := make([]v1.PolicyRule, 0)
for _, role := range clusterRoles {
clusterRules = append(clusterRules, role.Rules...)
}
for i := 0; i < (len(ClusterRoleRuleMapping)); i++ {
rule := Rule{Name: ClusterRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(ClusterRoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(clusterRules, ClusterRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func GetClusterRoleRules(name string) ([]Rule, error) {
clusterRole, err := GetClusterRole(name)
if err != nil {
return nil, err
}
rules := make([]Rule, 0)
for i := 0; i < len(ClusterRoleRuleMapping); i++ {
rule := Rule{Name: ClusterRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(ClusterRoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(clusterRole.Rules, ClusterRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func GetRoleRules(namespace string, name string) ([]Rule, error) {
role, err := GetRole(namespace, name)
if err != nil {
return nil, err
}
rules := make([]Rule, 0)
for i := 0; i < len(RoleRuleMapping); i++ {
rule := Rule{Name: RoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < len(RoleRuleMapping[i].Actions); j++ {
if rulesMatchesAction(role.Rules, RoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
return rules, nil
}
func rulesMatchesAction(rules []v1.PolicyRule, action Action) bool {
for _, rule := range action.Rules {
if !RulesMatchesRequired(rules, rule) {
return false
}
}
return true
}
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
for _, rule := range rules {
if ruleMatchesRequired(rule, required) {
return true
}
}
return false
}
func ruleMatchesRequired(rule v1.PolicyRule, required v1.PolicyRule) bool {
if len(required.NonResourceURLs) == 0 {
for _, apiGroup := range required.APIGroups {
for _, resource := range required.Resources {
resources := strings.Split(resource, "/")
resource = resources[0]
var subsource string
if len(resources) > 1 {
subsource = resources[1]
}
if len(required.ResourceNames) == 0 {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, "", verb) {
return false
}
}
} else {
for _, resourceName := range required.ResourceNames {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, resourceName, verb) {
return false
}
}
}
}
}
}
} else {
for _, apiGroup := range required.APIGroups {
for _, nonResourceURL := range required.NonResourceURLs {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, nonResourceURL, "", "", "", verb) {
return false
}
}
}
}
}
return true
}
func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
if resource == "" {
return false
}
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, v1.ResourceAll) {
return false
}
if len(rule.ResourceNames) > 0 && !hasString(rule.ResourceNames, resourceName) {
return false
}
combinedResource := resource
if subresource != "" {
combinedResource = combinedResource + "/" + subresource
}
for _, res := range rule.Resources {
// match "*"
if res == v1.ResourceAll || res == combinedResource {
return true
}
// match "*/subresource"
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") {
return true
}
// match "resource/*"
if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") {
return true
}
}
return false
}
func ruleMatchesRequest(rule v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, v1.VerbAll) {
return false
}
if nonResourceURL == "" {
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
} else {
return ruleMatchesNonResource(rule, nonResourceURL)
}
}
func ruleMatchesNonResource(rule v1.PolicyRule, nonResourceURL string) bool {
if nonResourceURL == "" {
return false
}
for _, spec := range rule.NonResourceURLs {
if pathMatches(nonResourceURL, spec) {
return true
}
}
return false
}
func pathMatches(path, spec string) bool {
// Allow wildcard match
if spec == "*" {
return true
}
// Allow exact match
if spec == path {
return true
}
// Allow a trailing * subpath match
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
return true
}
return false
}
func hasString(slice []string, value string) bool {
for _, s := range slice {
if s == value {
return true
}
}
return false
}

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