Merge pull request #288 from wansir/advanced-2.0-dev

add ks-iam and ks-apigateway
This commit is contained in:
zryfish
2019-03-11 23:43:16 +08:00
committed by GitHub
715 changed files with 108638 additions and 23446 deletions

View File

@@ -17,9 +17,11 @@ before_install:
before_script: before_script:
- dep ensure -v - dep ensure -v
- docker --version - docker --version
- git clone --single-branch -b v0.11.4 -q https://github.com/mholt/caddy $GOPATH/src/github.com/mholt/caddy
script: script:
- make all && make test - make test
- bash hack/docker_build.sh
deploy: deploy:
skip_cleanup: true skip_cleanup: true

442
Gopkg.lock generated
View File

@@ -2,57 +2,82 @@
[[projects]] [[projects]]
digest = "1:4d6f036ea3fe636bcb2e89850bcdc62a771354e157cd51b8b22a2de8562bf663"
name = "cloud.google.com/go" name = "cloud.google.com/go"
packages = ["compute/metadata"] packages = ["compute/metadata"]
pruneopts = "UT"
revision = "c9474f2f8deb81759839474b6bd1726bbfe1c1c4" revision = "c9474f2f8deb81759839474b6bd1726bbfe1c1c4"
version = "v0.36.0" version = "v0.36.0"
[[projects]] [[projects]]
digest = "1:f9ae348e1f793dcf9ed930ed47136a67343dbd6809c5c91391322267f4476892"
name = "github.com/Microsoft/go-winio" name = "github.com/Microsoft/go-winio"
packages = ["."] packages = ["."]
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f" pruneopts = "UT"
version = "v0.4.7" revision = "1a8911d1ed007260465c3bfbbc785ac6915a0bb8"
version = "v0.4.12"
[[projects]] [[projects]]
digest = "1:a2682518d905d662d984ef9959984ef87cecb777d379bfa9d9fe40e78069b3e4"
name = "github.com/PuerkitoBio/purell" name = "github.com/PuerkitoBio/purell"
packages = ["."] packages = ["."]
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4" pruneopts = "UT"
version = "v1.1.0" revision = "44968752391892e1b0d0b821ee79e9a85fa13049"
version = "v1.1.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:c739832d67eb1e9cc478a19cc1a1ccd78df0397bf8a32978b759152e205f644b"
name = "github.com/PuerkitoBio/urlesc" name = "github.com/PuerkitoBio/urlesc"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "de5bf2ad457846296e2031421a34e2568e304e35" revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]] [[projects]]
digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8"
name = "github.com/Sirupsen/logrus" name = "github.com/Sirupsen/logrus"
packages = ["."] packages = ["."]
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" pruneopts = "UT"
version = "v1.0.5" revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5"
version = "v1.3.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
name = "github.com/beorn7/perks" name = "github.com/beorn7/perks"
packages = ["quantile"] packages = ["quantile"]
pruneopts = "UT"
revision = "3a771d992973f24aa725d07868b467d1ddfceafb" revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
[[projects]] [[projects]]
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
name = "github.com/davecgh/go-spew" name = "github.com/davecgh/go-spew"
packages = ["spew"] packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76" pruneopts = "UT"
version = "v1.1.0" revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
version = "v1.1.1"
[[projects]]
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
pruneopts = "UT"
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
version = "v3.2.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:4c7d169280debf9f36b84a0f682094889cccc5dc0db8657f9cffc93b21975a57"
name = "github.com/docker/distribution" name = "github.com/docker/distribution"
packages = [ packages = [
"digestset", "digestset",
"reference" "reference",
] ]
revision = "749f6afb4572201e3c37325d0ffedb6f32be8950" pruneopts = "UT"
revision = "6d62eb1d4a3515399431b713fde3ce5a9b40e8d5"
[[projects]] [[projects]]
digest = "1:ec821dda59d7dd340498d74f798aa218b2c782bba54a690e866dc4f520d900d5"
name = "github.com/docker/docker" name = "github.com/docker/docker"
packages = [ packages = [
"api", "api",
@@ -74,338 +99,466 @@
"pkg/ioutils", "pkg/ioutils",
"pkg/longpath", "pkg/longpath",
"pkg/system", "pkg/system",
"pkg/tlsconfig" "pkg/tlsconfig",
] ]
pruneopts = "UT"
revision = "90d35abf7b3535c1c319c872900fbd76374e521c" revision = "90d35abf7b3535c1c319c872900fbd76374e521c"
version = "v17.05.0-ce-rc3" version = "v17.05.0-ce-rc3"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:02f8f4889e53a6adbc7bf3f2b9007ce8aecb0b79686fc9f99265246c88063f10"
name = "github.com/docker/go-connections" name = "github.com/docker/go-connections"
packages = [ packages = [
"nat", "nat",
"sockets", "sockets",
"tlsconfig" "tlsconfig",
] ]
revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55" pruneopts = "UT"
revision = "97c2040d34dfae1d1b1275fa3a78dbdd2f41cf7e"
[[projects]] [[projects]]
digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18"
name = "github.com/docker/go-units" name = "github.com/docker/go-units"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c" revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
version = "v0.3.3" version = "v0.3.3"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:4841e14252a2cecf11840bd05230412ad469709bbacfc12467e2ce5ad07f339b"
name = "github.com/docker/libtrust" name = "github.com/docker/libtrust"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20" revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
[[projects]] [[projects]]
digest = "1:8ee7b41ace3ba875c17e38ba7780e7cf0d29882338637861e9f13f04f60ecc5c"
name = "github.com/emicklei/go-restful" name = "github.com/emicklei/go-restful"
packages = [ packages = [
".", ".",
"log" "log",
] ]
revision = "3658237ded108b4134956c1b3050349d93e7b895" pruneopts = "UT"
version = "v2.7.1" revision = "85d198d05a92d31823b852b4a5928114912e8949"
version = "v2.9.0"
[[projects]] [[projects]]
digest = "1:8ba45daa43acfd9364068b118a6884cb82bc1ef0569dc05260f3b464907e07d9"
name = "github.com/emicklei/go-restful-openapi" name = "github.com/emicklei/go-restful-openapi"
packages = ["."] packages = ["."]
revision = "51bf251d405ad1e23511fef0a2dbe40bc70ce2c6" pruneopts = "UT"
version = "v0.11.0" revision = "b7062368c258c9e8f8cbe9dd2e6aebfa1b747be6"
version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda"
name = "github.com/ghodss/yaml" name = "github.com/ghodss/yaml"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
branch = "master" digest = "1:2a792dde3ae5dc95000d4dee312523504ea875b097a2b119a2f55d1d1d32ed61"
name = "github.com/go-logr/logr" name = "github.com/go-ldap/ldap"
packages = ["."] packages = ["."]
revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e" pruneopts = "UT"
revision = "729c20c2694d870bcd631f0dadaecd088bd7ccbc"
version = "v3.0.2"
[[projects]] [[projects]]
name = "github.com/go-logr/zapr" digest = "1:edd2fa4578eb086265db78a9201d15e76b298dfd0d5c379da83e9c61712cf6df"
name = "github.com/go-logr/logr"
packages = ["."] packages = ["."]
revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab" pruneopts = "UT"
revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e"
version = "v0.1.0" version = "v0.1.0"
[[projects]] [[projects]]
branch = "master" digest = "1:d81dfed1aa731d8e4a45d87154ec15ef18da2aa80fa9a2f95bec38577a244a99"
name = "github.com/go-logr/zapr"
packages = ["."]
pruneopts = "UT"
revision = "03f06a783fbb7dfaf3f629c7825480e43a7105e6"
version = "v0.1.1"
[[projects]]
digest = "1:953a2628e4c5c72856b53f5470ed5e071c55eccf943d798d42908102af2a610f"
name = "github.com/go-openapi/jsonpointer" name = "github.com/go-openapi/jsonpointer"
packages = ["."] packages = ["."]
revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2" pruneopts = "UT"
revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004"
version = "v0.18.0"
[[projects]] [[projects]]
branch = "master" digest = "1:81210e0af657a0fb3638932ec68e645236bceefa4c839823db0c4d918f080895"
name = "github.com/go-openapi/jsonreference" name = "github.com/go-openapi/jsonreference"
packages = ["."] packages = ["."]
revision = "3fb327e6747da3043567ee86abd02bb6376b6be2" pruneopts = "UT"
revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3"
version = "v0.18.0"
[[projects]] [[projects]]
branch = "master" digest = "1:08656ef9c5a45ddccb7f206ca2d67e12e9fcda4122a83dc0544b5c967267cefa"
name = "github.com/go-openapi/spec" name = "github.com/go-openapi/spec"
packages = ["."] packages = ["."]
revision = "bce47c9386f9ecd6b86f450478a80103c3fe1402" pruneopts = "UT"
revision = "5b6cdde3200976e3ecceb2868706ee39b6aff3e4"
version = "v0.18.0"
[[projects]] [[projects]]
branch = "master" digest = "1:0005186c6608dd542239ac8e4f4f1e2e7c24d493e999113c46b93332f0362fc0"
name = "github.com/go-openapi/swag" name = "github.com/go-openapi/swag"
packages = ["."] packages = ["."]
revision = "2b0bd4f193d011c203529df626a65d63cb8a79e8" pruneopts = "UT"
revision = "1d29f06aebd59ccdf11ae04aa0334ded96e2d909"
version = "v0.18.0"
[[projects]] [[projects]]
digest = "1:33082c63746b464db3d1c2c07a1396d860484d97fe857ef9e8668a9b406db09f"
name = "github.com/go-redis/redis"
packages = [
".",
"internal",
"internal/consistenthash",
"internal/hashtag",
"internal/pool",
"internal/proto",
"internal/util",
]
pruneopts = "UT"
revision = "d22fde8721cc915a55aeb6b00944a76a92bfeb6e"
version = "v6.15.2"
[[projects]]
digest = "1:ec6f9bf5e274c833c911923c9193867f3f18788c461f76f05f62bb1510e0ae65"
name = "github.com/go-sql-driver/mysql" name = "github.com/go-sql-driver/mysql"
packages = ["."] packages = ["."]
revision = "d523deb1b23d913de5bdada721a6071e71283618" pruneopts = "UT"
version = "v1.4.0" revision = "72cd26f257d44c1114970e19afddcd812016007e"
version = "v1.4.1"
[[projects]] [[projects]]
digest = "1:4d02824a56d268f74a6b6fdd944b20b58a77c3d70e81008b3ee0c4f1a6777340"
name = "github.com/gogo/protobuf" name = "github.com/gogo/protobuf"
packages = [ packages = [
"proto", "proto",
"sortkeys" "sortkeys",
] ]
revision = "1adfc126b41513cc696b209667c8656ea7aac67c" pruneopts = "UT"
version = "v1.0.0" revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c"
version = "v1.2.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467"
name = "github.com/golang/glog" name = "github.com/golang/glog"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:b7cb6054d3dff43b38ad2e92492f220f57ae6087ee797dca298139776749ace8"
name = "github.com/golang/groupcache" name = "github.com/golang/groupcache"
packages = ["lru"] packages = ["lru"]
pruneopts = "UT"
revision = "5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b" revision = "5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b"
[[projects]] [[projects]]
digest = "1:239c4c7fd2159585454003d9be7207167970194216193a8a210b8d29576f19c9"
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
packages = [ packages = [
"proto", "proto",
"ptypes", "ptypes",
"ptypes/any", "ptypes/any",
"ptypes/duration", "ptypes/duration",
"ptypes/timestamp" "ptypes/timestamp",
] ]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" pruneopts = "UT"
version = "v1.1.0" revision = "c823c79ea1570fb5ff454033735a8e68575d1d0f"
version = "v1.3.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:0bfbe13936953a98ae3cfe8ed6670d396ad81edf069a806d2f6515d7bb6950df"
name = "github.com/google/btree" name = "github.com/google/btree"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb"
name = "github.com/google/gofuzz" name = "github.com/google/gofuzz"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]] [[projects]]
digest = "1:582b704bebaa06b48c29b0cec224a6058a09c86883aaddabde889cd1a5f73e1b"
name = "github.com/google/uuid" name = "github.com/google/uuid"
packages = ["."] packages = ["."]
revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8" pruneopts = "UT"
version = "v1.1.0" revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
version = "v1.1.1"
[[projects]] [[projects]]
digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21"
name = "github.com/googleapis/gnostic" name = "github.com/googleapis/gnostic"
packages = [ packages = [
"OpenAPIv2", "OpenAPIv2",
"compiler", "compiler",
"extensions" "extensions",
] ]
pruneopts = "UT"
revision = "7c663266750e7d82587642f65e60bc4083f1f84e" revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
version = "v0.2.0" version = "v0.2.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:b4395b2a4566c24459af3d04009b39cc21762fc77ec7bf7a1aa905c91e8f018d"
name = "github.com/gregjones/httpcache" name = "github.com/gregjones/httpcache"
packages = [ packages = [
".", ".",
"diskcache" "diskcache",
] ]
pruneopts = "UT"
revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f" revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f"
[[projects]] [[projects]]
branch = "master" digest = "1:d15ee511aa0f56baacc1eb4c6b922fa1c03b38413b6be18166b996d82a0156ea"
name = "github.com/hashicorp/golang-lru" name = "github.com/hashicorp/golang-lru"
packages = [ packages = [
".", ".",
"simplelru" "simplelru",
] ]
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" pruneopts = "UT"
revision = "7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c"
version = "v0.5.1"
[[projects]] [[projects]]
digest = "1:a0cefd27d12712af4b5018dc7046f245e1e3b5760e2e848c30b171b570708f9b"
name = "github.com/imdario/mergo" name = "github.com/imdario/mergo"
packages = ["."] packages = ["."]
revision = "9316a62528ac99aaecb4e47eadd6dc8aa6533d58" pruneopts = "UT"
version = "v0.3.5" revision = "7c29201646fa3de8506f701213473dd407f19646"
version = "v0.3.7"
[[projects]] [[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap" name = "github.com/inconshreveable/mousetrap"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0" version = "v1.0"
[[projects]] [[projects]]
digest = "1:d4e6e8584d0a94ce567d237e19192dae44d57d2767ac7e1d7fbf5626d176381a"
name = "github.com/jinzhu/gorm" name = "github.com/jinzhu/gorm"
packages = ["."] packages = ["."]
revision = "6ed508ec6a4ecb3531899a69cbc746ccf65a4166" pruneopts = "UT"
version = "v1.9.1" revision = "472c70caa40267cb89fd8facb07fe6454b578626"
version = "v1.9.2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:fd97437fbb6b7dce04132cf06775bd258cce305c44add58eb55ca86c6c325160"
name = "github.com/jinzhu/inflection" name = "github.com/jinzhu/inflection"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "04140366298a54a039076d798123ffa108fff46c" revision = "04140366298a54a039076d798123ffa108fff46c"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:f5a2051c55d05548d2d4fd23d244027b59fbd943217df8aa3b5e170ac2fd6e1b"
name = "github.com/json-iterator/go" name = "github.com/json-iterator/go"
packages = ["."] packages = ["."]
revision = "5bc93205020f6311d7e4a34f82c5616a18ec35e5" pruneopts = "UT"
revision = "0ff49de124c6f76f8494e194af75bde0f1a49a29"
[[projects]]
digest = "1:31e761d97c76151dde79e9d28964a812c46efc5baee4085b86f68f0c654450de"
name = "github.com/konsorten/go-windows-terminal-sequences"
packages = ["."]
pruneopts = "UT"
revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e"
version = "v1.0.2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:84a5a2b67486d5d67060ac393aa255d05d24ed5ee41daecd5635ec22657b6492"
name = "github.com/mailru/easyjson" name = "github.com/mailru/easyjson"
packages = [ packages = [
"buffer", "buffer",
"jlexer", "jlexer",
"jwriter" "jwriter",
] ]
revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485" pruneopts = "UT"
revision = "6243d8e04c3f819e79757e8bc3faa15c3cb27003"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:fc2b04b0069d6b10bdef96d278fe20c345794009685ed3c8c7f1a6dc023eefec"
name = "github.com/mattbaird/jsonpatch" name = "github.com/mattbaird/jsonpatch"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f" revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f"
[[projects]] [[projects]]
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
name = "github.com/matttproud/golang_protobuf_extensions" name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"] packages = ["pbutil"]
pruneopts = "UT"
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1" version = "v1.0.1"
[[projects]] [[projects]]
digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79"
name = "github.com/mitchellh/go-homedir" name = "github.com/mitchellh/go-homedir"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "af06845cf3004701891bf4fdb884bfe4920b3727" revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
version = "v1.1.0" version = "v1.1.0"
[[projects]] [[projects]]
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
name = "github.com/modern-go/concurrent" name = "github.com/modern-go/concurrent"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
version = "1.0.3" version = "1.0.3"
[[projects]] [[projects]]
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
name = "github.com/modern-go/reflect2" name = "github.com/modern-go/reflect2"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
version = "1.0.1" version = "1.0.1"
[[projects]] [[projects]]
digest = "1:ee4d4af67d93cc7644157882329023ce9a7bcfce956a079069a9405521c7cc8d"
name = "github.com/opencontainers/go-digest" name = "github.com/opencontainers/go-digest"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf" revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
version = "v1.0.0-rc1" version = "v1.0.0-rc1"
[[projects]] [[projects]]
digest = "1:e5d0bd87abc2781d14e274807a470acd180f0499f8bf5bb18606e9ec22ad9de9"
name = "github.com/pborman/uuid" name = "github.com/pborman/uuid"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
version = "v1.2" version = "v1.2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2"
name = "github.com/petar/GoLLRB" name = "github.com/petar/GoLLRB"
packages = ["llrb"] packages = ["llrb"]
pruneopts = "UT"
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
[[projects]] [[projects]]
digest = "1:0e7775ebbcf00d8dd28ac663614af924411c868dca3d5aa762af0fae3808d852"
name = "github.com/peterbourgon/diskv" name = "github.com/peterbourgon/diskv"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
version = "v2.0.1" version = "v2.0.1"
[[projects]] [[projects]]
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
name = "github.com/pkg/errors" name = "github.com/pkg/errors"
packages = ["."] packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d" pruneopts = "UT"
version = "v0.8.0" revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
version = "v0.8.1"
[[projects]] [[projects]]
digest = "1:93a746f1060a8acbcf69344862b2ceced80f854170e1caae089b2834c5fbf7f4"
name = "github.com/prometheus/client_golang" name = "github.com/prometheus/client_golang"
packages = [ packages = [
"prometheus", "prometheus",
"prometheus/internal", "prometheus/internal",
"prometheus/promhttp" "prometheus/promhttp",
] ]
pruneopts = "UT"
revision = "505eaef017263e299324067d40ca2c48f6a2cf50" revision = "505eaef017263e299324067d40ca2c48f6a2cf50"
version = "v0.9.2" version = "v0.9.2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
name = "github.com/prometheus/client_model" name = "github.com/prometheus/client_model"
packages = ["go"] packages = ["go"]
pruneopts = "UT"
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8" revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
[[projects]] [[projects]]
digest = "1:35cf6bdf68db765988baa9c4f10cc5d7dda1126a54bd62e252dbcd0b1fc8da90"
name = "github.com/prometheus/common" name = "github.com/prometheus/common"
packages = [ packages = [
"expfmt", "expfmt",
"internal/bitbucket.org/ww/goautoneg", "internal/bitbucket.org/ww/goautoneg",
"model" "model",
] ]
pruneopts = "UT"
revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250" revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
version = "v0.2.0" version = "v0.2.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:01cd0cd47758f04c5604daa3be4637e2afa1e0c15af7e08289e95360369e4f48"
name = "github.com/prometheus/procfs" name = "github.com/prometheus/procfs"
packages = [ packages = [
".", ".",
"internal/util", "internal/util",
"iostats", "iostats",
"nfs", "nfs",
"xfs" "xfs",
] ]
revision = "bbced9601137e764853b2fad7ec3e2dc4c504e02" pruneopts = "UT"
revision = "d0f344d83b0c80a1bc03b547a2374a9ec6711144"
[[projects]] [[projects]]
digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
name = "github.com/spf13/cobra" name = "github.com/spf13/cobra"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
version = "v0.0.3" version = "v0.0.3"
[[projects]] [[projects]]
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
name = "github.com/spf13/pflag" name = "github.com/spf13/pflag"
packages = ["."] packages = ["."]
revision = "583c0c0531f06d5278b7d917446061adc344b5cd" pruneopts = "UT"
version = "v1.0.1" revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
version = "v1.0.3"
[[projects]] [[projects]]
digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d"
name = "go.uber.org/atomic" name = "go.uber.org/atomic"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
version = "v1.3.2" version = "v1.3.2"
[[projects]] [[projects]]
digest = "1:60bf2a5e347af463c42ed31a493d817f8a72f102543060ed992754e689805d1a"
name = "go.uber.org/multierr" name = "go.uber.org/multierr"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
version = "v1.1.0" version = "v1.1.0"
[[projects]] [[projects]]
digest = "1:c52caf7bd44f92e54627a31b85baf06a68333a196b3d8d241480a774733dcf8b"
name = "go.uber.org/zap" name = "go.uber.org/zap"
packages = [ packages = [
".", ".",
@@ -413,19 +566,23 @@
"internal/bufferpool", "internal/bufferpool",
"internal/color", "internal/color",
"internal/exit", "internal/exit",
"zapcore" "zapcore",
] ]
pruneopts = "UT"
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982" revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
version = "v1.9.1" version = "v1.9.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:058e9504b9a79bfe86092974d05bb3298d2aa0c312d266d43148de289a5065d9"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = ["ssh/terminal"] packages = ["ssh/terminal"]
revision = "7f39a6fea4fe9364fb61e1def6a268a51b4f3a06" pruneopts = "UT"
revision = "c2843e01d9a2bc60bb26ad24e09734fdc2d9ec58"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:348e38852dac5030f8ce455e1b8d7a5727bbe0af43c0664efd89ec32414093c0"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = [ packages = [
"context", "context",
@@ -435,32 +592,38 @@
"http2/hpack", "http2/hpack",
"idna", "idna",
"internal/socks", "internal/socks",
"proxy" "proxy",
] ]
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196" pruneopts = "UT"
revision = "56fb01167e7d1e1d17dd87993d34c963f4356e87"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:5e9f22cf754ab20a5dff0ae04b12516b112c5b81cd44dccccde148865084d730"
name = "golang.org/x/oauth2" name = "golang.org/x/oauth2"
packages = [ packages = [
".", ".",
"google", "google",
"internal", "internal",
"jws", "jws",
"jwt" "jwt",
] ]
revision = "9b3c75971fc92dd27c6436a37c05c831498658f1" pruneopts = "UT"
revision = "e64efc72b421e893cbf63f17ba2221e7d6d0b0f3"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:85cd5224b89829559e8327ba2e52e0df72638d33cf3082b066ea9dea34391e2f"
name = "golang.org/x/sys" name = "golang.org/x/sys"
packages = [ packages = [
"unix", "unix",
"windows" "windows",
] ]
revision = "fc8bd948cf46f9c7af0f07d34151ce25fe90e477" pruneopts = "UT"
revision = "10058d7d4faa7dd5ef860cbd31af00903076e7b8"
[[projects]] [[projects]]
digest = "1:0c56024909189aee3364b7f21a95a27459f718aa7c199a5c111c36cfffd9eaef"
name = "golang.org/x/text" name = "golang.org/x/text"
packages = [ packages = [
"collate", "collate",
@@ -477,24 +640,30 @@
"unicode/cldr", "unicode/cldr",
"unicode/norm", "unicode/norm",
"unicode/rangetable", "unicode/rangetable",
"width" "width",
] ]
pruneopts = "UT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0" version = "v0.3.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90"
name = "golang.org/x/time" name = "golang.org/x/time"
packages = ["rate"] packages = ["rate"]
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650" pruneopts = "UT"
revision = "9d24e82272b4f38b78bc8cff74fa936d31ccd8ef"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:6bb2e1cbcf253307a88a531a75aa4d38fecb8d56a0dc9e837e288fe3189954f6"
name = "golang.org/x/tools" name = "golang.org/x/tools"
packages = ["container/intsets"] packages = ["container/intsets"]
revision = "44bee7e801e4a70b5fc9a91ff23830ab4df55d5e" pruneopts = "UT"
revision = "00c44ba9c14f88ffdd4fb5bfae57fe8dd6d6afb1"
[[projects]] [[projects]]
digest = "1:7bc25c2efff76b31f146caf630c617be9b666c6164f0632050466fbec0500125"
name = "google.golang.org/appengine" name = "google.golang.org/appengine"
packages = [ packages = [
".", ".",
@@ -507,24 +676,38 @@
"internal/modules", "internal/modules",
"internal/remote_api", "internal/remote_api",
"internal/urlfetch", "internal/urlfetch",
"urlfetch" "urlfetch",
] ]
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612" pruneopts = "UT"
version = "v1.1.0" revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1"
version = "v1.4.0"
[[projects]] [[projects]]
digest = "1:af07c44dc04418be522bfd4e21ca9130d58169ea084e3a883e23772003a381c4"
name = "gopkg.in/asn1-ber.v1"
packages = ["."]
pruneopts = "UT"
revision = "f715ec2f112d1e4195b827ad68cf44017a3ef2b1"
version = "v1.3"
[[projects]]
digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a"
name = "gopkg.in/inf.v0" name = "gopkg.in/inf.v0"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
version = "v0.9.1" version = "v0.9.1"
[[projects]] [[projects]]
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
name = "gopkg.in/yaml.v2" name = "gopkg.in/yaml.v2"
packages = ["."] packages = ["."]
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" pruneopts = "UT"
version = "v2.2.1" revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
version = "v2.2.2"
[[projects]] [[projects]]
digest = "1:26a67eb988225c6a0600c1af0b35e795ac4d23a9c40a7aa178fa2adc0670f1f7"
name = "k8s.io/api" name = "k8s.io/api"
packages = [ packages = [
"admission/v1beta1", "admission/v1beta1",
@@ -558,12 +741,14 @@
"settings/v1alpha1", "settings/v1alpha1",
"storage/v1", "storage/v1",
"storage/v1alpha1", "storage/v1alpha1",
"storage/v1beta1" "storage/v1beta1",
] ]
pruneopts = "UT"
revision = "b503174bad5991eb66f18247f52e41c3258f6348" revision = "b503174bad5991eb66f18247f52e41c3258f6348"
version = "kubernetes-1.12.3" version = "kubernetes-1.12.3"
[[projects]] [[projects]]
digest = "1:3c38a27df3152aa083018cb7a8d7b5bd5af5e808733ebbc6ae5b5fe10f8b0f84"
name = "k8s.io/apimachinery" name = "k8s.io/apimachinery"
packages = [ packages = [
"pkg/api/errors", "pkg/api/errors",
@@ -609,12 +794,27 @@
"pkg/version", "pkg/version",
"pkg/watch", "pkg/watch",
"third_party/forked/golang/json", "third_party/forked/golang/json",
"third_party/forked/golang/reflect" "third_party/forked/golang/reflect",
] ]
pruneopts = "UT"
revision = "eddba98df674a16931d2d4ba75edc3a389bf633a" revision = "eddba98df674a16931d2d4ba75edc3a389bf633a"
version = "kubernetes-1.12.3" version = "kubernetes-1.12.3"
[[projects]] [[projects]]
branch = "release-1.10"
digest = "1:89837c4f0a1aa35aa5993bd0ee002ed0073e505c08bcb716c9941059e1df3da6"
name = "k8s.io/apiserver"
packages = [
"pkg/apis/audit",
"pkg/authentication/user",
"pkg/authorization/authorizer",
"pkg/endpoints/request",
]
pruneopts = "UT"
revision = "30d6a91f580b7a2a240dccebc1a35bff2a6940f6"
[[projects]]
digest = "1:7b85a80c96c7294b896204fca216c35d10e63fd0a021b23c5b5fe00f68932420"
name = "k8s.io/client-go" name = "k8s.io/client-go"
packages = [ packages = [
"discovery", "discovery",
@@ -754,36 +954,30 @@
"util/integer", "util/integer",
"util/jsonpath", "util/jsonpath",
"util/retry", "util/retry",
"util/workqueue" "util/workqueue",
] ]
pruneopts = "UT"
revision = "d082d5923d3cc0bfbb066ee5fbdea3d0ca79acf8" revision = "d082d5923d3cc0bfbb066ee5fbdea3d0ca79acf8"
version = "kubernetes-1.12.3" version = "kubernetes-1.12.3"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "k8s.io/component-base" digest = "1:20ca56a1299fe3787b1cf86c3a0388fbc11d08604783b32a258eca7a947a7fdb"
packages = ["logs"]
revision = "1925c57e3358154fd54383773de0c0c7710a9196"
[[projects]]
name = "k8s.io/klog"
packages = ["."]
revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0"
version = "v0.2.0"
[[projects]]
branch = "master"
name = "k8s.io/kube-openapi" name = "k8s.io/kube-openapi"
packages = ["pkg/util/proto"] packages = ["pkg/util/proto"]
revision = "d50a959ae76a85c7c262a9767ef29f37093c2b8a" pruneopts = "UT"
revision = "15615b16d372105f0c69ff47dfe7402926a65aaa"
[[projects]] [[projects]]
digest = "1:ceff1906e568c23d7a337fdda89900d6155aaf93db7cb6da73488ffb649641e1"
name = "k8s.io/kubernetes" name = "k8s.io/kubernetes"
packages = ["pkg/util/slice"] packages = ["pkg/util/slice"]
revision = "721bfa751924da8d1680787490c54b9179b1fed0" pruneopts = "UT"
version = "v1.13.3" revision = "c27b913fddd1a6c480c229191a087698aa92f0b1"
version = "v1.13.4"
[[projects]] [[projects]]
digest = "1:3c56f356b5cb581860246ca0c08c7a35aa21b2c071b20c428a53b2c3c13c87fd"
name = "sigs.k8s.io/controller-runtime" name = "sigs.k8s.io/controller-runtime"
packages = [ packages = [
"pkg/cache", "pkg/cache",
@@ -803,14 +997,68 @@
"pkg/webhook/admission", "pkg/webhook/admission",
"pkg/webhook/admission/types", "pkg/webhook/admission/types",
"pkg/webhook/internal/metrics", "pkg/webhook/internal/metrics",
"pkg/webhook/types" "pkg/webhook/types",
] ]
pruneopts = "UT"
revision = "f6f0bc9611363b43664d08fb097ab13243ef621d" revision = "f6f0bc9611363b43664d08fb097ab13243ef621d"
version = "v0.1.9" version = "v0.1.9"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "af7a1befccf91a9979c7710cf95e61ccb7dc4131fd0cc22e585e2e3b8034f92f" input-imports = [
"github.com/dgrijalva/jwt-go",
"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-ldap/ldap",
"github.com/go-openapi/spec",
"github.com/go-redis/redis",
"github.com/go-sql-driver/mysql",
"github.com/golang/glog",
"github.com/jinzhu/gorm",
"github.com/json-iterator/go",
"github.com/mitchellh/go-homedir",
"github.com/spf13/cobra",
"github.com/spf13/pflag",
"golang.org/x/tools/container/intsets",
"gopkg.in/yaml.v2",
"k8s.io/api/apps/v1",
"k8s.io/api/apps/v1beta2",
"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/runtime",
"k8s.io/apimachinery/pkg/runtime/schema",
"k8s.io/apimachinery/pkg/types",
"k8s.io/apimachinery/pkg/util/runtime",
"k8s.io/apimachinery/pkg/util/wait",
"k8s.io/apiserver/pkg/authorization/authorizer",
"k8s.io/apiserver/pkg/endpoints/request",
"k8s.io/client-go/informers",
"k8s.io/client-go/informers/core/v1",
"k8s.io/client-go/informers/rbac/v1",
"k8s.io/client-go/kubernetes",
"k8s.io/client-go/kubernetes/scheme",
"k8s.io/client-go/plugin/pkg/client/auth/gcp",
"k8s.io/client-go/rest",
"k8s.io/client-go/tools/cache",
"k8s.io/client-go/tools/clientcmd",
"k8s.io/client-go/util/workqueue",
"k8s.io/kubernetes/pkg/util/slice",
"sigs.k8s.io/controller-runtime/pkg/client/config",
"sigs.k8s.io/controller-runtime/pkg/manager",
"sigs.k8s.io/controller-runtime/pkg/runtime/log",
"sigs.k8s.io/controller-runtime/pkg/runtime/signals",
]
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@@ -24,6 +24,8 @@
# go-tests = true # go-tests = true
# unused-packages = true # unused-packages = true
ignored = ["github.com/mholt/caddy","github.com/mholt/caddy/caddyfile","github.com/mholt/caddy/caddyhttp/httpserver","github.com/mholt/caddy/caddyhttp/staticfiles","github.com/mholt/caddy/caddytls","github.com/mholt/caddy/telemetry"]
[[constraint]] [[constraint]]
name = "github.com/docker/docker" name = "github.com/docker/docker"
version = "v17.05.0-ce" version = "v17.05.0-ce"

View File

@@ -0,0 +1,28 @@
# 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.
# 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.3 as ks-apigateway-builder
COPY / /go/src/kubesphere.io/kubesphere
RUN git clone --single-branch -b v0.11.4 -q https://github.com/mholt/caddy /go/src/github.com/mholt/caddy
WORKDIR /go/src/github.com/mholt/caddy
RUN sed -i "/\/\/ This is where other plugins get plugged in (imported)/a\\\t\
_ \"kubesphere.io/kubesphere/pkg/apigateway/caddy-plugin/authenticate\"\n\t\
_ \"kubesphere.io/kubesphere/pkg/apigateway/caddy-plugin/authentication\"\n\t\
_ \"kubesphere.io/kubesphere/pkg/apigateway/caddy-plugin/swagger\""\
caddy/caddymain/run.go && \
sed -i "/\/\/ github.com\/BTBurke\/caddy-jwt/a\\\t\"authenticate\",\n\t\"authentication\",\n\t\"swagger\","\
caddyhttp/httpserver/plugin.go && \
go install ./caddy && \
go run /go/src/kubesphere.io/kubesphere/tools/cmd/doc-gen/main.go --output=/go/src/kubesphere.io/kubesphere/install/swagger-ui/api.json
FROM alpine:3.7
RUN apk add --update ca-certificates && update-ca-certificates
COPY --from=ks-apigateway-builder /go/bin/* /usr/local/bin/
COPY --from=ks-apigateway-builder /go/src/kubesphere.io/kubesphere/install/swagger-ui /var/static/swagger-ui
CMD ["sh"]

View File

@@ -0,0 +1,18 @@
# 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.
# 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.3 as ks-apiserver-builder
COPY / /go/src/kubesphere.io/kubesphere
WORKDIR /go/src/kubesphere.io/kubesphere
RUN go build -o ks-apiserver cmd/ks-apiserver/apiserver.go
FROM alpine:3.7
RUN apk add --update ca-certificates && update-ca-certificates
COPY --from=ks-apiserver-builder /go/src/kubesphere.io/kubesphere/ks-apiserver /usr/local/bin/
CMD ["sh"]

18
build/ks-iam/Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
# 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.
# 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.3 as ks-iam-builder
COPY / /go/src/kubesphere.io/kubesphere
WORKDIR /go/src/kubesphere.io/kubesphere
RUN go build -o ks-iam cmd/ks-iam/main.go
FROM alpine:3.7
RUN apk add --update ca-certificates && update-ca-certificates
COPY --from=ks-iam-builder /go/src/kubesphere.io/kubesphere/ks-iam /usr/local/bin/
CMD ["sh"]

View File

@@ -1,12 +1,28 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main package main
import ( import (
"fmt"
"kubesphere.io/kubesphere/cmd/ks-apiserver/app" "kubesphere.io/kubesphere/cmd/ks-apiserver/app"
"os" "log"
// Install apis // Install apis
_ "kubesphere.io/kubesphere/pkg/apis/metrics/install" _ "kubesphere.io/kubesphere/pkg/apis/metrics/install"
_ "kubesphere.io/kubesphere/pkg/apis/monitoring/install"
_ "kubesphere.io/kubesphere/pkg/apis/operations/install" _ "kubesphere.io/kubesphere/pkg/apis/operations/install"
_ "kubesphere.io/kubesphere/pkg/apis/resources/install" _ "kubesphere.io/kubesphere/pkg/apis/resources/install"
) )
@@ -16,7 +32,6 @@ func main() {
cmd := app.NewAPIServerCommand() cmd := app.NewAPIServerCommand()
if err := cmd.Execute(); err != nil { if err := cmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err) log.Fatalln(err)
os.Exit(1)
} }
} }

View File

@@ -1,67 +0,0 @@
package options
import (
"fmt"
"github.com/spf13/pflag"
"os"
)
type ServerRunOptions struct {
// server bind address
BindAddress string
// insecure port number
InsecurePort int
// secure port number
SecurePort int
// OpenPitrix api gateway service url
OpenPitrixAddress string
// database connection string in MySQL like
// user:password@tcp(host)/dbname?charset=utf8&parseTime=True
DatabaseConnectionString string
// tls cert file
TlsCertFile string
// tls private key file
TlsPrivateKey string
// host openapi doc
ApiDoc bool
// kubeconfig file path
KubeConfig string
}
func NewServerRunOptions() *ServerRunOptions {
// create default server run options
s := ServerRunOptions{
BindAddress: "0.0.0.0",
InsecurePort: 9090,
SecurePort: 0,
OpenPitrixAddress: "openpitrix-api-gateway.openpitrix-system.svc",
DatabaseConnectionString: "",
TlsCertFile: "",
TlsPrivateKey: "",
ApiDoc: true,
}
return &s
}
func (s *ServerRunOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.BindAddress, "bind-address", "0.0.0.0", "server bind address")
fs.IntVar(&s.InsecurePort, "insecure-port", 9090, "insecure port number")
fs.IntVar(&s.SecurePort, "secure-port", 0, "secure port number")
fs.StringVar(&s.OpenPitrixAddress, "openpitrix", "openpitrix-api-gateway.openpitrix-system.svc", "openpitrix api gateway address")
fs.StringVar(&s.DatabaseConnectionString, "database-connection", "", "database connection string")
fs.StringVar(&s.TlsCertFile, "tls-cert-file", "", "tls cert file")
fs.StringVar(&s.TlsPrivateKey, "tls-private-key", "", "tls private key")
fs.BoolVar(&s.ApiDoc, "api-doc", true, "host OpenAPI doc")
fs.StringVar(&s.KubeConfig, "kubeconfig", fmt.Sprintf("%s/.kube/config", os.Getenv("HOME")), "path to kubeconfig file")
}

View File

@@ -1,21 +1,38 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app package app
import ( import (
goflag "flag"
"fmt" "fmt"
"github.com/emicklei/go-restful-openapi" "github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"kubesphere.io/kubesphere/cmd/ks-apiserver/app/options"
"kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/filter" "kubesphere.io/kubesphere/pkg/filter"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/options"
"kubesphere.io/kubesphere/pkg/signals" "kubesphere.io/kubesphere/pkg/signals"
"log" "log"
"net/http" "net/http"
) )
func NewAPIServerCommand() *cobra.Command { func NewAPIServerCommand() *cobra.Command {
s := options.NewServerRunOptions() s := options.SharedOptions
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "ks-apiserver", Use: "ks-apiserver",
@@ -23,15 +40,13 @@ func NewAPIServerCommand() *cobra.Command {
for the api objects. The API Server services REST operations and provides the frontend to the for the api objects. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`, cluster's shared state through which all other components interact.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
//s.AddFlags(cmd.Flags())
return Run(s) return Run(s)
}, },
} }
s.AddFlags(cmd.Flags()) cmd.Flags().AddFlagSet(s.CommandLine)
cmd.Flags().AddGoFlagSet(goflag.CommandLine)
glog.CopyStandardLogTo("INFO")
return cmd return cmd
} }
@@ -39,26 +54,11 @@ func Run(s *options.ServerRunOptions) error {
var err error var err error
stopChan := signals.SetupSignalHandler() waitForResourceSync()
informers.SharedInformerFactory().Start(stopChan)
informers.SharedInformerFactory().WaitForCacheSync(stopChan)
log.Println("resources sync success")
container := runtime.Container container := runtime.Container
container.Filter(filter.Logging) container.Filter(filter.Logging)
if len(s.KubeConfig) > 0 {
client.KubeConfigFile = s.KubeConfig
}
if s.ApiDoc {
config := restfulspec.Config{
WebServices: container.RegisteredWebServices(),
APIPath: "/apidoc.json",
}
container.Add(restfulspec.NewOpenAPIService(config))
}
log.Printf("Server listening on %d.", s.InsecurePort) log.Printf("Server listening on %d.", s.InsecurePort)
if s.InsecurePort != 0 { if s.InsecurePort != 0 {
@@ -71,3 +71,36 @@ func Run(s *options.ServerRunOptions) error {
return err return err
} }
func waitForResourceSync() {
stopChan := signals.SetupSignalHandler()
informerFactory := informers.SharedInformerFactory()
informerFactory.Rbac().V1().Roles().Lister()
informerFactory.Rbac().V1().RoleBindings().Lister()
informerFactory.Rbac().V1().ClusterRoles().Lister()
informerFactory.Rbac().V1().ClusterRoleBindings().Lister()
informerFactory.Storage().V1().StorageClasses().Lister()
informerFactory.Core().V1().Namespaces().Lister()
informerFactory.Core().V1().Nodes().Lister()
informerFactory.Core().V1().ResourceQuotas().Lister()
informerFactory.Core().V1().Pods().Lister()
informerFactory.Core().V1().Services().Lister()
informerFactory.Core().V1().PersistentVolumeClaims().Lister()
informerFactory.Core().V1().Secrets().Lister()
informerFactory.Core().V1().ConfigMaps().Lister()
informerFactory.Apps().V1().ControllerRevisions().Lister()
informerFactory.Apps().V1().StatefulSets().Lister()
informerFactory.Apps().V1().Deployments().Lister()
informerFactory.Apps().V1().DaemonSets().Lister()
informerFactory.Batch().V1().Jobs().Lister()
informerFactory.Batch().V1beta1().CronJobs()
informerFactory.Start(stopChan)
informerFactory.WaitForCacheSync(stopChan)
log.Println("resources sync success")
}

View File

@@ -15,12 +15,20 @@
limitations under the License. limitations under the License.
*/ */
package v1alpha2 package main
import ( import (
"kubesphere.io/kubesphere/pkg/monitoring/v1alpha2/monitoring" "kubesphere.io/kubesphere/cmd/ks-iam/app"
"log"
// Install apis
_ "kubesphere.io/kubesphere/pkg/apis/iam/install"
) )
func init() { func main() {
addToWebServiceFuncs = append(addToWebServiceFuncs, monitoring.Route)
cmd := app.NewAPIServerCommand()
if err := cmd.Execute(); err != nil {
log.Fatalln(err)
}
} }

95
cmd/ks-iam/app/server.go Normal file
View File

@@ -0,0 +1,95 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app
import (
goflag "flag"
"fmt"
"github.com/golang/glog"
"github.com/spf13/cobra"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/filter"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/options"
"kubesphere.io/kubesphere/pkg/signals"
"log"
"net/http"
)
func NewAPIServerCommand() *cobra.Command {
s := options.SharedOptions
cmd := &cobra.Command{
Use: "ks-iam",
Long: `The KubeSphere API server validates and configures data
for the api objects. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`,
RunE: func(cmd *cobra.Command, args []string) error {
return Run(s)
},
}
cmd.Flags().AddFlagSet(s.CommandLine)
cmd.Flags().AddGoFlagSet(goflag.CommandLine)
glog.CopyStandardLogTo("INFO")
return cmd
}
func Run(s *options.ServerRunOptions) error {
var err error
err = iam.DatabaseInit()
if err != nil {
return err
}
waitForResourceSync()
container := runtime.Container
container.Filter(filter.Logging)
log.Printf("Server listening on %d.", s.InsecurePort)
if s.InsecurePort != 0 {
err = http.ListenAndServe(fmt.Sprintf("%s:%d", s.BindAddress, s.InsecurePort), container)
}
if s.SecurePort != 0 && len(s.TlsCertFile) > 0 && len(s.TlsPrivateKey) > 0 {
err = http.ListenAndServeTLS(fmt.Sprintf("%s:%d", s.BindAddress, s.SecurePort), s.TlsCertFile, s.TlsPrivateKey, container)
}
return err
}
func waitForResourceSync() {
stopChan := signals.SetupSignalHandler()
informerFactory := informers.SharedInformerFactory()
informerFactory.Rbac().V1().Roles().Lister()
informerFactory.Rbac().V1().RoleBindings().Lister()
informerFactory.Rbac().V1().ClusterRoles().Lister()
informerFactory.Rbac().V1().ClusterRoleBindings().Lister()
informerFactory.Core().V1().Namespaces().Lister()
informerFactory.Start(stopChan)
informerFactory.WaitForCacheSync(stopChan)
log.Println("resources sync success")
}

4
hack/docker_build.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
docker build -f build/ks-apigateway/Dockerfile -t kubespheredev/ks-apigateway:latest .
docker build -f build/ks-apiserver/Dockerfile -t kubespheredev/ks-apiserver:latest .

View File

@@ -3,4 +3,5 @@
# Push image to dockerhub, need to support multiple push # Push image to dockerhub, need to support multiple push
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
docker push kubespheredev/ks-apigateway:latest
docker push kubespheredev/ks-apiserver:latest docker push kubespheredev/ks-apiserver:latest

View File

@@ -0,0 +1,172 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package authenticate
import (
"errors"
"fmt"
"net/http"
"strconv"
"strings"
"github.com/dgrijalva/jwt-go"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
type Auth struct {
Rule Rule
Next httpserver.Handler
}
type Rule struct {
Secret []byte
Path string
ExceptedPath []string
}
type User struct {
Username string `json:"username"`
UID string `json:"uid"`
Groups *[]string `json:"groups,omitempty"`
Extra *map[string]interface{} `json:"extra,omitempty"`
}
func (h Auth) ServeHTTP(resp http.ResponseWriter, req *http.Request) (int, error) {
for _, path := range h.Rule.ExceptedPath {
if httpserver.Path(req.URL.Path).Matches(path) {
return h.Next.ServeHTTP(resp, req)
}
}
if httpserver.Path(req.URL.Path).Matches(h.Rule.Path) {
uToken, err := h.ExtractToken(req)
if err != nil {
return h.HandleUnauthorized(resp, err), nil
}
token, err := h.Validate(uToken)
if err != nil {
return h.HandleUnauthorized(resp, err), nil
}
req, err = h.InjectContext(req, token)
if err != nil {
return h.HandleUnauthorized(resp, err), nil
}
}
return h.Next.ServeHTTP(resp, req)
}
func (h Auth) InjectContext(req *http.Request, token *jwt.Token) (*http.Request, error) {
payLoad, ok := token.Claims.(jwt.MapClaims)
if !ok {
return nil, errors.New("invalid payload")
}
for header := range req.Header {
if strings.HasPrefix(header, "X-Token-") {
req.Header.Del(header)
}
}
username, ok := payLoad["username"].(string)
if ok && username != "" {
req.Header.Set("X-Token-Username", username)
}
uid := payLoad["uid"]
if uid != nil {
switch uid.(type) {
case int:
req.Header.Set("X-Token-UID", strconv.Itoa(uid.(int)))
break
case string:
req.Header.Set("X-Token-UID", uid.(string))
break
}
}
groups, ok := payLoad["groups"].([]string)
if ok && len(groups) > 0 {
req.Header.Set("X-Token-Groups", strings.Join(groups, ","))
}
return req, nil
}
func (h Auth) Validate(uToken string) (*jwt.Token, error) {
if len(uToken) == 0 {
return nil, fmt.Errorf("token length is zero")
}
token, err := jwt.Parse(uToken, h.ProvideKey)
if err != nil {
return nil, err
}
return token, nil
}
func (h Auth) HandleUnauthorized(w http.ResponseWriter, err error) int {
message := fmt.Sprintf("Unauthorized,%v", err)
w.Header().Add("WWW-Authenticate", message)
return http.StatusUnauthorized
}
func (h Auth) ExtractToken(r *http.Request) (string, error) {
jwtHeader := strings.Split(r.Header.Get("Authorization"), " ")
if jwtHeader[0] == "Bearer" && len(jwtHeader) == 2 {
return jwtHeader[1], nil
}
jwtCookie, err := r.Cookie("token")
if err == nil {
return jwtCookie.Value, nil
}
jwtQuery := r.URL.Query().Get("token")
if jwtQuery != "" {
return jwtQuery, nil
}
return "", fmt.Errorf("no token found")
}
func (h Auth) ProvideKey(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok {
return h.Rule.Secret, nil
} else {
return nil, fmt.Errorf("expect token signed with HMAC but got %v", token.Header["alg"])
}
}

View File

@@ -0,0 +1,110 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package authenticate
import (
"fmt"
"strings"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
func init() {
caddy.RegisterPlugin("authenticate", caddy.Plugin{
ServerType: "http",
Action: Setup,
})
}
func Setup(c *caddy.Controller) error {
rule, err := parse(c)
if err != nil {
return err
}
c.OnStartup(func() error {
fmt.Println("Authenticate middleware is initiated")
return nil
})
httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
return &Auth{Next: next, Rule: rule}
})
return nil
}
func parse(c *caddy.Controller) (Rule, error) {
rule := Rule{ExceptedPath: make([]string, 0)}
if c.Next() {
args := c.RemainingArgs()
switch len(args) {
case 0:
for c.NextBlock() {
switch c.Val() {
case "path":
if !c.NextArg() {
return rule, c.ArgErr()
}
rule.Path = c.Val()
if c.NextArg() {
return rule, c.ArgErr()
}
case "secret":
if !c.NextArg() {
return rule, c.ArgErr()
}
rule.Secret = []byte(c.Val())
if c.NextArg() {
return rule, c.ArgErr()
}
case "except":
if !c.NextArg() {
return rule, c.ArgErr()
}
rule.ExceptedPath = strings.Split(c.Val(), ",")
for i := 0; i < len(rule.ExceptedPath); i++ {
rule.ExceptedPath[i] = strings.TrimSpace(rule.ExceptedPath[i])
}
if c.NextArg() {
return rule, c.ArgErr()
}
}
}
default:
return rule, c.ArgErr()
}
}
if c.Next() {
return rule, c.ArgErr()
}
return rule, nil
}

View File

@@ -0,0 +1,300 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package authentication
import (
"errors"
"fmt"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/endpoints/request"
"net/http"
"strings"
"github.com/mholt/caddy/caddyhttp/httpserver"
"k8s.io/api/rbac/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/util/slice"
"kubesphere.io/kubesphere/pkg/informers"
sliceutils "kubesphere.io/kubesphere/pkg/utils"
)
type Authentication struct {
Rule Rule
Next httpserver.Handler
}
type Rule struct {
Path string
ExceptedPath []string
}
func (c Authentication) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
if httpserver.Path(r.URL.Path).Matches(c.Rule.Path) {
for _, path := range c.Rule.ExceptedPath {
if httpserver.Path(r.URL.Path).Matches(path) {
return c.Next.ServeHTTP(w, r)
}
}
attrs, err := getAuthorizerAttributes(r.Context())
if err != nil {
return http.StatusInternalServerError, err
}
permitted, err := permissionValidate(attrs)
if err != nil {
return http.StatusInternalServerError, err
}
if !permitted {
err = k8serr.NewForbidden(schema.GroupResource{Group: attrs.GetAPIGroup(), Resource: attrs.GetResource()}, attrs.GetName(), fmt.Errorf("permission undefined"))
return handleForbidden(w, err), nil
}
}
return c.Next.ServeHTTP(w, r)
}
func handleForbidden(w http.ResponseWriter, err error) int {
message := fmt.Sprintf("Forbidden,%s", err.Error())
w.Header().Add("WWW-Authenticate", message)
return http.StatusForbidden
}
func permissionValidate(attrs authorizer.Attributes) (bool, error) {
permitted, err := clusterRoleValidate(attrs)
if err != nil {
return false, err
}
if permitted {
return true, nil
}
if attrs.GetNamespace() != "" {
permitted, err = roleValidate(attrs)
if err != nil {
return false, err
}
if permitted {
return true, nil
}
}
return false, nil
}
func roleValidate(attrs authorizer.Attributes) (bool, error) {
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
roleLister := informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
roleBindings, err := roleBindingLister.RoleBindings(attrs.GetNamespace()).List(labels.Everything())
if err != nil {
return false, err
}
fullSource := attrs.GetResource()
if attrs.GetSubresource() != "" {
fullSource = fullSource + "/" + attrs.GetSubresource()
}
for _, roleBinding := range roleBindings {
for _, subj := range roleBinding.Subjects {
if (subj.Kind == v1.UserKind && subj.Name == attrs.GetUser().GetName()) ||
(subj.Kind == v1.GroupKind && slice.ContainsString(attrs.GetUser().GetGroups(), subj.Name, nil)) {
role, err := roleLister.Roles(attrs.GetNamespace()).Get(roleBinding.RoleRef.Name)
if err != nil {
return false, err
}
for _, rule := range role.Rules {
if ruleMatchesRequest(rule, attrs.GetAPIGroup(), "", attrs.GetResource(), attrs.GetSubresource(), attrs.GetName(), attrs.GetVerb()) {
return true, nil
}
}
}
}
}
return false, nil
}
func clusterRoleValidate(attrs authorizer.Attributes) (bool, error) {
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
if err != nil {
return false, err
}
for _, clusterRoleBinding := range clusterRoleBindings {
for _, subject := range clusterRoleBinding.Subjects {
if (subject.Kind == v1.UserKind && subject.Name == attrs.GetUser().GetName()) ||
(subject.Kind == v1.GroupKind && sliceutils.HasString(attrs.GetUser().GetGroups(), subject.Name)) {
clusterRole, err := clusterRoleLister.Get(clusterRoleBinding.RoleRef.Name)
if err != nil {
return false, err
}
for _, rule := range clusterRole.Rules {
if attrs.IsResourceRequest() {
if ruleMatchesRequest(rule, attrs.GetAPIGroup(), "", attrs.GetResource(), attrs.GetSubresource(), attrs.GetName(), attrs.GetVerb()) {
return true, nil
}
} else {
if ruleMatchesRequest(rule, "", attrs.GetPath(), "", "", "", attrs.GetVerb()) {
return true, nil
}
}
}
}
}
}
return false, nil
}
func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
if resource == "" {
return false
}
if !sliceutils.HasString(rule.APIGroups, apiGroup) && !sliceutils.HasString(rule.APIGroups, v1.ResourceAll) {
return false
}
if len(rule.ResourceNames) > 0 && !sliceutils.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 !sliceutils.HasString(rule.Verbs, verb) && !sliceutils.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 {
if spec == "*" {
return true
}
if spec == path {
return true
}
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
return true
}
return false
}
func getAuthorizerAttributes(ctx request.Context) (authorizer.Attributes, error) {
attribs := authorizer.AttributesRecord{}
user, ok := request.UserFrom(ctx)
if ok {
attribs.User = user
}
requestInfo, found := request.RequestInfoFrom(ctx)
if !found {
return nil, errors.New("no RequestInfo found in the context")
}
// Start with common attributes that apply to resource and non-resource requests
attribs.ResourceRequest = requestInfo.IsResourceRequest
attribs.Path = requestInfo.Path
attribs.Verb = requestInfo.Verb
attribs.APIGroup = requestInfo.APIGroup
attribs.APIVersion = requestInfo.APIVersion
attribs.Resource = requestInfo.Resource
attribs.Subresource = requestInfo.Subresource
attribs.Namespace = requestInfo.Namespace
attribs.Name = requestInfo.Name
return &attribs, nil
}

View File

@@ -0,0 +1,119 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package authentication
import (
"fmt"
"strings"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/signals"
)
func init() {
caddy.RegisterPlugin("authentication", caddy.Plugin{
ServerType: "http",
Action: Setup,
})
}
// Setup is called by Caddy to parse the config block
func Setup(c *caddy.Controller) error {
rule, err := parse(c)
if err != nil {
return err
}
if err != nil {
return err
}
c.OnStartup(func() error {
stopChan := signals.SetupSignalHandler()
informers.SharedInformerFactory().Start(stopChan)
informers.SharedInformerFactory().WaitForCacheSync(stopChan)
fmt.Println("Authentication middleware is initiated")
return nil
})
httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
return &Authentication{Next: next, Rule: rule}
})
return nil
}
func parse(c *caddy.Controller) (Rule, error) {
rule := Rule{ExceptedPath: make([]string, 0)}
if c.Next() {
args := c.RemainingArgs()
switch len(args) {
case 0:
for c.NextBlock() {
switch c.Val() {
case "path":
if !c.NextArg() {
return rule, c.ArgErr()
}
rule.Path = c.Val()
if c.NextArg() {
return rule, c.ArgErr()
}
break
case "except":
if !c.NextArg() {
return rule, c.ArgErr()
}
rule.ExceptedPath = strings.Split(c.Val(), ",")
for i := 0; i < len(rule.ExceptedPath); i++ {
rule.ExceptedPath[i] = strings.TrimSpace(rule.ExceptedPath[i])
}
if c.NextArg() {
return rule, c.ArgErr()
}
break
}
}
case 1:
rule.Path = args[0]
if c.NextBlock() {
return rule, c.ArgErr()
}
default:
return rule, c.ArgErr()
}
}
if c.Next() {
return rule, c.ArgErr()
}
return rule, nil
}

View File

@@ -0,0 +1,100 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package authenticate
import (
"fmt"
"net/http"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
func init() {
caddy.RegisterPlugin("swagger", caddy.Plugin{
ServerType: "http",
Action: Setup,
})
}
func Setup(c *caddy.Controller) error {
handler, err := parse(c)
if err != nil {
return err
}
c.OnStartup(func() error {
fmt.Println("Swagger middleware is initiated")
return nil
})
httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
return &Swagger{Next: next, Handler: handler}
})
return nil
}
func parse(c *caddy.Controller) (Handler, error) {
handler := Handler{URL: "/swagger-ui", FilePath: "/var/static/swagger-ui"}
if c.Next() {
args := c.RemainingArgs()
switch len(args) {
case 0:
for c.NextBlock() {
switch c.Val() {
case "url":
if !c.NextArg() {
return handler, c.ArgErr()
}
handler.URL = c.Val()
if c.NextArg() {
return handler, c.ArgErr()
}
case "filePath":
if !c.NextArg() {
return handler, c.ArgErr()
}
handler.FilePath = c.Val()
if c.NextArg() {
return handler, c.ArgErr()
}
default:
return handler, c.ArgErr()
}
}
default:
return handler, c.ArgErr()
}
}
if c.Next() {
return handler, c.ArgErr()
}
handler.Handler = http.StripPrefix(handler.URL, http.FileServer(http.Dir(handler.FilePath)))
return handler, nil
}

View File

@@ -0,0 +1,45 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package authenticate
import (
"net/http"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
type Swagger struct {
Handler Handler
Next httpserver.Handler
}
type Handler struct {
URL string
FilePath string
Handler http.Handler
}
func (h Swagger) ServeHTTP(resp http.ResponseWriter, req *http.Request) (int, error) {
if httpserver.Path(req.URL.Path).Matches(h.Handler.URL) {
h.Handler.Handler.ServeHTTP(resp, req)
return http.StatusOK, nil
}
return h.Next.ServeHTTP(resp, req)
}

View File

@@ -15,17 +15,19 @@
limitations under the License. limitations under the License.
*/ */
package monitoring package install
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
"kubesphere.io/kubesphere/pkg/monitoring/v1alpha2" iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
) )
const apiGroup = "monitoring.kubesphere.io" func init() {
Install(runtime.Container)
func AddToContainer(container *restful.Container) error { }
container.Add(v1alpha2.WebService(apiGroup))
return nil func Install(container *restful.Container) {
urlruntime.Must(iamv1alpha2.AddToContainer(container))
} }

View File

@@ -0,0 +1,214 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha2
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/iam"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
)
const GroupName = "iam.kubesphere.io"
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
var (
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
AddToContainer = WebServiceBuilder.AddToContainer
)
func addWebService(c *restful.Container) error {
tags := []string{"IAM"}
ws := runtime.NewWebService(GroupVersion)
ws.Route(ws.POST("/authenticate").
To(iam.TokenReviewHandler).
Doc("Token review").
Reads(iam.TokenReview{}).
Writes(iam.TokenReview{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.POST("/login").
To(iam.LoginHandler).
Doc("User login").
Reads(iam.LoginRequest{}).
Writes(models.Token{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/users/{name}").
To(iam.UserDetail).
Doc("User detail").
Writes(models.User{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.POST("/users").
To(iam.CreateUser).
Reads(models.User{}).
Writes(errors.Error{}).
Doc("Create user").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.DELETE("/users/{name}").
To(iam.DeleteUser).
Doc("Delete user").
Writes(errors.Error{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.PUT("/users/{name}").
To(iam.UpdateUser).
Reads(models.User{}).
Writes(errors.Error{}).
Doc("Update user").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/users/{name}/log").
To(iam.UserLoginLog).
Doc("User login log").
Writes([]map[string]string{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/users").
To(iam.UserList).
Doc("User list").
Writes(models.PageableResponse{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/groups").
To(iam.RootGroupList).
Writes([]models.Group{}).
Doc("User group list").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/groups/{path}").
To(iam.GroupDetail).
Doc("User group detail").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/groups/{path}/users").
To(iam.GroupUsers).
Doc("Group user list").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.POST("/groups").
To(iam.CreateGroup).
Reads(models.Group{}).
Doc("Create user group").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.DELETE("/groups/{path}").
To(iam.DeleteGroup).
Doc("Delete user group").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.PUT("/groups/{path}").
To(iam.UpdateGroup).
Doc("Update user group").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/users/{username}/roles").
To(iam.UserRoles).
Doc("Get user role list").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/users").
To(iam.RoleUsers).
Doc("Get user list by role").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/rules").
To(iam.RoleRules).
Doc("Get role detail").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/users").
To(iam.NamespaceUsers).
Doc("Get user list by namespace").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/clusterroles/{clusterrole}/users").
To(iam.ClusterRoleUsers).
Doc("Get user list by cluster role").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/clusterroles/{clusterrole}/rules").
To(iam.ClusterRoleRules).
Doc("Get cluster role detail").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/rulesmapping/clusterroles").
To(iam.ClusterRulesMappingHandler).
Doc("Get cluster role policy rules mapping").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/rulesmapping/roles").
To(iam.RulesMappingHandler).
Doc("Get role policy rules mapping").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces/{workspace}/rules").
To(iam.WorkspaceRulesHandler).
Doc("Get workspace level policy rules").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces/{workspace}/members").
To(iam.WorkspaceMemberList).
Doc("Get workspace member list").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/rules").
To(iam.NamespacesRulesHandler).
Doc("Get namespace level policy rules").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/devops/{devops}/rules").
To(iam.DevopsRulesHandler).
Doc("Get devops project level policy rules").
Metadata(restfulspec.KeyOpenAPITags, tags))
tags = []string{"Workspace"}
ws.Route(ws.GET("/workspaces").
To(iam.UserWorkspaceListHandler).
Doc("Get workspace list").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]models.Workspace{}))
ws.Route(ws.POST("/workspaces").
To(iam.WorkspaceCreateHandler).
Doc("Create workspace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(models.Workspace{}))
ws.Route(ws.DELETE("/workspaces/{name}").
To(iam.DeleteWorkspaceHandler).
Doc("Delete workspace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(errors.Error{}))
ws.Route(ws.GET("/workspaces/{name}").
To(iam.WorkspaceDetailHandler).
Doc("Get workspace detail").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(models.Workspace{}))
ws.Route(ws.PUT("/workspaces/{name}").
To(iam.WorkspaceEditHandler).
Doc("Update workspace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(models.Workspace{}))
ws.Route(ws.GET("/workspaces/{name}/members/{member}").
To(iam.WorkspaceMemberDetail).
Doc("Get workspace member detail").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces/{name}/roles").
To(iam.WorkspaceRoles).
Doc("Get workspace roles").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.POST("/workspaces/{name}/members").
To(iam.WorkspaceMemberInvite).
Doc("Add user to workspace").
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.DELETE("/workspaces/{name}/members").
To(iam.WorkspaceMemberRemove).
Doc("Delete user from workspace").
Metadata(restfulspec.KeyOpenAPITags, tags))
c.Add(ws)
return nil
}

View File

@@ -1,18 +0,0 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package metrics

View File

@@ -19,6 +19,7 @@ package v1alpha2
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/metrics" "kubesphere.io/kubesphere/pkg/apiserver/metrics"
"kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/apiserver/runtime"
@@ -36,8 +37,20 @@ var (
func addWebService(c *restful.Container) error { func addWebService(c *restful.Container) error {
webservice := runtime.NewWebService(GroupVersion) webservice := runtime.NewWebService(GroupVersion)
webservice.Route(webservice.GET("/storageclasses/{storageclass}").To(metrics.GetScMetrics)) tags := []string{"metrics"}
webservice.Route(webservice.GET("/metrics/storageclass").To(metrics.GetScMetricsList))
webservice.Route(webservice.GET("/storageclasses/{storageclass}").
To(metrics.GetScMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("").
Param(webservice.PathParameter("storageclass", "storageclass's name")).
Writes(metrics.ScMetricsItem{}))
webservice.Route(webservice.GET("/storageclasses").
To(metrics.GetScMetricsList).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("").
Writes([]metrics.ScMetricsItem{}))
c.Add(webservice) c.Add(webservice)

View File

@@ -15,22 +15,19 @@
limitations under the License. limitations under the License.
*/ */
package v1alpha2 package install
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
monitoringv1alpha2 "kubesphere.io/kubesphere/pkg/apis/monitoring/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
) )
const apiVersion = "v1alpha2" func init() {
Install(runtime.Container)
var addToWebServiceFuncs []func(ws *restful.WebService)
func WebService(apiGroup string) *restful.WebService {
ws := new(restful.WebService)
ws.Path("/apis/" + apiGroup + "/" + apiVersion).
Produces(restful.MIME_JSON).Consumes(restful.MIME_JSON)
for _, f := range addToWebServiceFuncs {
f(ws)
} }
return ws
func Install(container *restful.Container) {
urlruntime.Must(monitoringv1alpha2.AddToContainer(container))
} }

View File

@@ -0,0 +1,207 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha2
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/monitoring"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
)
const GroupName = "monitoring.kubesphere.io"
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
var (
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
AddToContainer = WebServiceBuilder.AddToContainer
)
func addWebService(c *restful.Container) error {
ws := runtime.NewWebService(GroupVersion)
tags := []string{"Monitoring"}
ws.Route(ws.GET("/clusters").To(monitoring.MonitorCluster).
Doc("monitor cluster level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("cluster_cpu_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/nodes").To(monitoring.MonitorNode).
Doc("monitor nodes level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("node_cpu_utilisation")).
Param(ws.QueryParameter("nodes_filter", "node re2 expression filter").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/nodes/{node}").To(monitoring.MonitorNode).
Doc("monitor specific node level metrics").
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("node_cpu_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces").To(monitoring.MonitorNamespace).
Doc("monitor namespaces level metrics").
Param(ws.QueryParameter("namespaces_filter", "namespaces re2 expression filter").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("namespace_memory_utilisation")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}").To(monitoring.MonitorNamespace).
Doc("monitor specific namespace level metrics").
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("namespace_memory_utilisation")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/pods").To(monitoring.MonitorPod).
Doc("monitor pods level metrics").
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}").To(monitoring.MonitorPod).
Doc("monitor specific pod level metrics").
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/nodes/{node}/pods").To(monitoring.MonitorPod).
Doc("monitor pods level metrics by nodeid").
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("i-k89a62il")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("openpitrix.*")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/nodes/{node}/pods/{pod}").To(monitoring.MonitorPod).
Doc("monitor specific pod level metrics by nodeid").
Param(ws.PathParameter("node", "specific node").Required(true).DefaultValue("i-k89a62il")).
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/nodes/{node}/pods/{pod}/containers").To(monitoring.MonitorContainer).
Doc("monitor specific pod level metrics by nodeid").
Param(ws.PathParameter("node", "specific node").Required(true)).
Param(ws.PathParameter("pod", "specific pod").Required(true)).
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("pod_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers").To(monitoring.MonitorContainer).
Doc("monitor containers level metrics").
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
Param(ws.QueryParameter("containers_filter", "container re2 expression filter").Required(false).DefaultValue("")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}/containers/{container}").To(monitoring.MonitorContainer).
Doc("monitor specific container level metrics").
Param(ws.PathParameter("namespace", "specific namespace").Required(true).DefaultValue("monitoring")).
Param(ws.PathParameter("pod", "specific pod").Required(true).DefaultValue("")).
Param(ws.PathParameter("container", "specific container").Required(true).DefaultValue("")).
Param(ws.QueryParameter("metrics_name", "metrics name cpu memory...").Required(true).DefaultValue("container_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{workload_kind}").To(monitoring.MonitorWorkload).
Doc("monitor specific workload level metrics").
Param(ws.PathParameter("namespace", "namespace").Required(true).DefaultValue("kube-system")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
Param(ws.PathParameter("workload_kind", "workload kind").Required(false).DefaultValue("daemonset")).
Param(ws.QueryParameter("workload_name", "workload name").Required(true).DefaultValue("")).
Param(ws.QueryParameter("pods_filter", "pod re2 expression filter").Required(false).DefaultValue("openpitrix.*")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "max metric items in a page").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/workloads").To(monitoring.MonitorWorkload).
Doc("monitor all workload level metrics").
Param(ws.PathParameter("namespace", "namespace").Required(true).DefaultValue("kube-system")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").Required(false)).
Param(ws.QueryParameter("workloads_filter", "pod re2 expression filter").Required(false).DefaultValue("")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags))
// list all namespace in this workspace by selected metrics
ws.Route(ws.GET("/workspaces/{workspace}").To(monitoring.MonitorOneWorkspace).
Doc("monitor workspaces level metrics").
Param(ws.PathParameter("workspace", "workspace name").Required(true)).
Param(ws.QueryParameter("namespaces_filter", "namespaces filter").Required(false).DefaultValue("k.*")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("namespace_memory_utilisation_wo_cache")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/workspaces").To(monitoring.MonitorAllWorkspaces).
Doc("monitor workspaces level metrics").
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("workspace_memory_utilisation")).
Param(ws.QueryParameter("workspaces_filter", "workspaces re2 expression filter").Required(false).DefaultValue(".*")).
Param(ws.QueryParameter("sort_metric", "sort metric").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").Required(false)).
Param(ws.QueryParameter("page", "page number").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "metrics name cpu memory...in re2 regex").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/components").To(monitoring.MonitorComponentStatus).
Doc("monitor k8s components status").
Metadata(restfulspec.KeyOpenAPITags, tags))
c.Add(ws)
return nil
}

View File

@@ -1,18 +0,0 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package operations

View File

@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/operations" "kubesphere.io/kubesphere/pkg/apiserver/operations"
"kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/errors"
) )
const GroupName = "operations.kubesphere.io" const GroupName = "operations.kubesphere.io"
@@ -36,20 +37,24 @@ var (
func addWebService(c *restful.Container) error { func addWebService(c *restful.Container) error {
tags := []string{"Operations"}
webservice := runtime.NewWebService(GroupVersion) webservice := runtime.NewWebService(GroupVersion)
webservice.Route(webservice.POST("/nodes/{node}/drainage").To(operations.DrainNode)) webservice.Route(webservice.POST("/nodes/{node}/drainage").
To(operations.DrainNode).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("").
Param(webservice.PathParameter("node", "node name")).
Writes(errors.Error{}))
webservice.Route(webservice.POST("/namespaces/{namespace}/jobs/{job}"). webservice.Route(webservice.POST("/namespaces/{namespace}/jobs/{job}").
To(operations.RerunJob). To(operations.RerunJob).
Metadata(restfulspec.KeyOpenAPITags, []string{"jobs"}). Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Handle job operation"). Doc("Handle job operation").
Param(webservice.PathParameter("job", "job name"). Param(webservice.PathParameter("job", "job name")).
DataType("string")). Param(webservice.PathParameter("namespace", "job's namespace")).
Param(webservice.PathParameter("namespace", "job's namespace"). Param(webservice.QueryParameter("a", "action")).
DataType("string")).
Param(webservice.QueryParameter("a", "action").
DataType("string")).
Writes("")) Writes(""))
c.Add(webservice) c.Add(webservice)

View File

@@ -1,18 +0,0 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package metrics

View File

@@ -20,9 +20,20 @@ package v1alpha2
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi" "github.com/emicklei/go-restful-openapi"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/components"
"kubesphere.io/kubesphere/pkg/apiserver/quotas"
"kubesphere.io/kubesphere/pkg/apiserver/registries"
"kubesphere.io/kubesphere/pkg/apiserver/resources" "kubesphere.io/kubesphere/pkg/apiserver/resources"
"kubesphere.io/kubesphere/pkg/apiserver/revisions"
"kubesphere.io/kubesphere/pkg/apiserver/routers"
"kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/apiserver/workloadstatuses"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/params"
) )
const GroupName = "resources.kubesphere.io" const GroupName = "resources.kubesphere.io"
@@ -38,18 +49,182 @@ func addWebService(c *restful.Container) error {
webservice := runtime.NewWebService(GroupVersion) webservice := runtime.NewWebService(GroupVersion)
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").To(resources.NamespaceResourceHandler)) tags := []string{"Namespace resources"}
webservice.Route(webservice.GET("/{resources}").To(resources.ClusterResourceHandler)) webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").
To(resources.NamespaceResourceHandler).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Namespace level resource query").
Param(webservice.PathParameter("namespace", "which namespace")).
Param(webservice.PathParameter("resources", "namespace level resource type")).
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
Required(false).
DataFormat("key=%s,key~%s")).
Param(webservice.QueryParameter(params.PagingParam, "page").
Required(false).
DataFormat("limit=%d,page=%d").
DefaultValue("limit=10,page=1")).
Writes(models.PageableResponse{}))
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").To(resources.GetPvcListBySc)) tags = []string{"Cluster resources"}
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").To(resources.GetPodListByPvc))
tags := []string{"users"} webservice.Route(webservice.GET("/{resources}").
webservice.Route(webservice.GET("/users/{username}/kubectl").Doc("get user's kubectl pod").Param(webservice.PathParameter("username", To(resources.ClusterResourceHandler).
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubectl)) Writes(models.PageableResponse{}).
webservice.Route(webservice.GET("/users/{username}/kubeconfig").Doc("get users' kubeconfig").Param(webservice.PathParameter("username", Metadata(restfulspec.KeyOpenAPITags, tags).
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubeconfig)) Doc("Cluster level resource query").
Param(webservice.PathParameter("resources", "cluster level resource type"))).
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
Required(false).
DataFormat("key=value,key~value").
DefaultValue("")).
Param(webservice.QueryParameter(params.PagingParam, "page").
Required(false).
DataFormat("limit=%d,page=%d").
DefaultValue("limit=10,page=1"))
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").
To(resources.GetPvcListBySc).
Doc("get user's kubectl pod").
Param(webservice.PathParameter("username", "username")).
Metadata(restfulspec.KeyOpenAPITags, tags))
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").
To(resources.GetPodListByPvc))
tags = []string{"User resources"}
webservice.Route(webservice.GET("/users/{username}/kubectl").
To(resources.GetKubectl).
Doc("get user's kubectl pod").
Param(webservice.PathParameter("username", "username")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(models.PodInfo{}))
webservice.Route(webservice.GET("/users/{username}/kubeconfig").
To(resources.GetKubeconfig).
Doc("get users' kubeconfig").
Param(webservice.PathParameter("username", "username")).
Metadata(restfulspec.KeyOpenAPITags, tags))
tags = []string{"Components"}
webservice.Route(webservice.GET("/components").
To(components.GetComponents).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("").
Writes(map[string]models.Component{}))
webservice.Route(webservice.GET("/components/{component}").
To(components.GetComponentStatus).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("").
Param(webservice.PathParameter("component", "component name")).
Writes(models.Component{}))
webservice.Route(webservice.GET("/health").
To(components.GetSystemHealthStatus).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("").
Writes(map[string]int{}))
tags = []string{"Quotas"}
webservice.Route(webservice.GET("/quotas").
To(quotas.GetClusterQuotas).
Doc("get whole cluster's resource usage").
Writes(models.ResourceQuota{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
webservice.Route(webservice.GET("/namespaces/{namespace}/quotas").
Doc("get specified namespace's resource quota and usage").
Param(webservice.PathParameter("namespace", "namespace's name")).
Writes(models.ResourceQuota{}).
Metadata(restfulspec.KeyOpenAPITags, tags).
To(quotas.GetNamespaceQuotas))
tags = []string{"Registries"}
webservice.Route(webservice.POST("registries/verify").
To(registries.RegistryVerify).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("docker registry verify").
Writes(errors.Error{}))
tags = []string{"Revision"}
webservice.Route(webservice.GET("/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}").
To(revisions.GetDaemonSetRevision).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Handle daemonset operation").
Param(webservice.PathParameter("daemonset", "daemonset's name")).
Param(webservice.PathParameter("namespace", "daemonset's namespace")).
Param(webservice.PathParameter("revision", "daemonset's revision")).
Writes(appsv1.DaemonSet{}))
webservice.Route(webservice.GET("/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}").
To(revisions.GetDeployRevision).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Handle deployment operation").
Param(webservice.PathParameter("deployment", "deployment's name")).
Param(webservice.PathParameter("namespace", "deployment's namespace")).
Param(webservice.PathParameter("revision", "deployment's revision")).
Writes(appsv1.ReplicaSet{}))
webservice.Route(webservice.GET("/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}").
To(revisions.GetStatefulSetRevision).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Handle statefulset operation").
Param(webservice.PathParameter("statefulset", "statefulset's name")).
Param(webservice.PathParameter("namespace", "statefulset's namespace")).
Param(webservice.PathParameter("revision", "statefulset's revision")).
Writes(appsv1.StatefulSet{}))
tags = []string{"Router"}
webservice.Route(webservice.GET("/routers").
To(routers.GetAllRouters).
Doc("Get all routers").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(corev1.Service{}))
webservice.Route(webservice.GET("/users/{username}/routers").
To(routers.GetAllRoutersOfUser).
Doc("Get routers for user").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(webservice.PathParameter("username", "")).
Writes(corev1.Service{}))
webservice.Route(webservice.GET("/namespaces/{namespace}/router").
To(routers.GetRouter).
Doc("Get router of a specified project").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(webservice.PathParameter("namespace", "name of the project")))
webservice.Route(webservice.DELETE("/namespaces/{namespace}/router").
To(routers.DeleteRouter).
Doc("Get router of a specified project").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(webservice.PathParameter("namespace", "name of the project")))
webservice.Route(webservice.POST("/namespaces/{namespace}/router").
To(routers.CreateRouter).
Doc("Create a router for a specified project").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(webservice.PathParameter("namespace", "name of the project")))
webservice.Route(webservice.PUT("/namespaces/{namespace}/router").
To(routers.UpdateRouter).
Doc("Update a router for a specified project").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(webservice.PathParameter("namespace", "name of the project")))
tags = []string{"WorkloadStatus"}
webservice.Route(webservice.GET("/workloadstatuses").
Doc("get abnormal workloads' count of whole cluster").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(workloadstatuses.GetClusterResourceStatus))
webservice.Route(webservice.GET("/namespaces/{namespace}/workloadstatuses").
Doc("get abnormal workloads' count of specified namespace").
Param(webservice.PathParameter("namespace", "the name of namespace")).
Metadata(restfulspec.KeyOpenAPITags, tags).
To(workloadstatuses.GetNamespacesResourceStatus))
c.Add(webservice) c.Add(webservice)

View File

@@ -22,18 +22,14 @@ import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/components" "kubesphere.io/kubesphere/pkg/models/components"
"net/http"
) )
func V1Alpha2(ws *restful.WebService) { func GetSystemHealthStatus(request *restful.Request, response *restful.Response) {
ws.Route(ws.GET("/components").To(getComponents)) result, err := components.GetSystemHealthStatus()
ws.Route(ws.GET("/components/{component}").To(getComponentStatus))
ws.Route(ws.GET("/health").To(getSystemHealthStatus))
}
func getSystemHealthStatus(request *restful.Request, response *restful.Response) { if err != nil {
result, err := components.GetAllComponentsStatus() response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
if errors.HandlerError(err, response) {
return return
} }
@@ -41,12 +37,13 @@ func getSystemHealthStatus(request *restful.Request, response *restful.Response)
} }
// get a specific component status // get a specific component status
func getComponentStatus(request *restful.Request, response *restful.Response) { func GetComponentStatus(request *restful.Request, response *restful.Response) {
component := request.PathParameter("component") component := request.PathParameter("component")
result, err := components.GetComponentStatus(component) result, err := components.GetComponentStatus(component)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
@@ -54,11 +51,12 @@ func getComponentStatus(request *restful.Request, response *restful.Response) {
} }
// get all componentsHandler // get all componentsHandler
func getComponents(request *restful.Request, response *restful.Response) { func GetComponents(request *restful.Request, response *restful.Response) {
result, err := components.GetAllComponentsStatus() result, err := components.GetAllComponentsStatus()
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -1,52 +0,0 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package hpa
import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/autoscaling/v1"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/hpa"
)
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.GET("/namespaces/{namespace}/horizontalpodautoscalers/{horizontalpodautoscaler}").
To(getHpa).
Metadata(restfulspec.KeyOpenAPITags, []string{"hpa"}).
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) {
name := req.PathParameter("horizontalpodautoscaler")
namespace := req.PathParameter("namespace")
result, err := hpa.GetHPA(namespace, name)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(result)
}

190
pkg/apiserver/iam/am.go Normal file
View File

@@ -0,0 +1,190 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam
import (
"github.com/emicklei/go-restful"
"k8s.io/api/rbac/v1"
"net/http"
"sort"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
)
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"`
}
func RoleRules(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
roleName := req.PathParameter("role")
role, err := iam.GetRole(namespace, roleName)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
rules, err := iam.GetRoleSimpleRules([]*v1.Role{role}, namespace)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(rules[namespace])
}
func RoleUsers(req *restful.Request, resp *restful.Response) {
roleName := req.PathParameter("role")
namespace := req.PathParameter("namespace")
users, err := iam.RoleUsers(namespace, roleName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(users)
}
func NamespaceUsers(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
users, err := iam.NamespaceUsers(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
sort.Slice(users, func(i, j int) bool {
return users[i].Username < users[j].Username
})
resp.WriteAsJson(users)
}
func UserRoles(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("username")
roles, err := iam.GetRoles(username, "")
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
roleList := roleList{}
roleList.Roles = roles
roleList.ClusterRoles = clusterRoles
resp.WriteAsJson(roleList)
}
func NamespaceRulesHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
username := req.HeaderParameter(constants.UserNameHeader)
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
roles, err := iam.GetRoles(username, namespace)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
for _, clusterRole := range clusterRoles {
role := new(v1.Role)
role.Name = clusterRole.Name
role.Labels = clusterRole.Labels
role.Namespace = namespace
role.Annotations = clusterRole.Annotations
role.Kind = "Role"
role.Rules = clusterRole.Rules
roles = append(roles, role)
}
rules, err := iam.GetRoleSimpleRules(roles, namespace)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(rules[namespace])
}
func RulesMappingHandler(req *restful.Request, resp *restful.Response) {
rules := policy.RoleRuleMapping
resp.WriteAsJson(rules)
}
func ClusterRulesMappingHandler(req *restful.Request, resp *restful.Response) {
rules := policy.ClusterRoleRuleMapping
resp.WriteAsJson(rules)
}
func ClusterRoleRules(req *restful.Request, resp *restful.Response) {
clusterRoleName := req.PathParameter("clusterrole")
clusterRole, err := iam.GetClusterRole(clusterRoleName)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
rules, err := iam.GetClusterRoleSimpleRules([]*v1.ClusterRole{clusterRole})
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(rules)
}
func ClusterRoleUsers(req *restful.Request, resp *restful.Response) {
clusterRoleName := req.PathParameter("clusterrole")
users, err := iam.ClusterRoleUsers(clusterRoleName)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(users)
}

142
pkg/apiserver/iam/auth.go Normal file
View File

@@ -0,0 +1,142 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/models"
"net/http"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/utils"
jwtutils "kubesphere.io/kubesphere/pkg/utils/jwt"
)
type Spec struct {
Token string `json:"token"`
}
type Status struct {
Authenticated bool `json:"authenticated"`
User map[string]interface{} `json:"user,omitempty"`
}
type TokenReview struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Spec *Spec `json:"spec,omitempty"`
Status *Status `json:"status,omitempty"`
}
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
const (
APIVersion = "authentication.k8s.io/v1beta1"
KindTokenReview = "TokenReview"
)
func LoginHandler(req *restful.Request, resp *restful.Response) {
var loginRequest LoginRequest
err := req.ReadEntity(&loginRequest)
if err != nil || loginRequest.Username == "" || loginRequest.Password == "" {
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.Wrap(fmt.Errorf("incorrect username or password")))
return
}
ip := utils.RemoteIp(req.Request)
token, err := iam.Login(loginRequest.Username, loginRequest.Password, ip)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.Wrap(err))
return
}
resp.WriteAsJson(models.Token{Token: token})
}
// k8s token review
func TokenReviewHandler(req *restful.Request, resp *restful.Response) {
var tokenReview TokenReview
err := req.ReadEntity(&tokenReview)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if tokenReview.Spec == nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("token must not be null")))
return
}
uToken := tokenReview.Spec.Token
token, err := jwtutils.ValidateToken(uToken)
if err != nil {
failed := TokenReview{APIVersion: APIVersion,
Kind: KindTokenReview,
Status: &Status{
Authenticated: false,
},
}
resp.WriteAsJson(failed)
return
}
claims := token.Claims.(jwt.MapClaims)
username := claims["username"].(string)
conn, err := iam.NewConnection()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
user, err := iam.UserDetail(username, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
success := TokenReview{APIVersion: APIVersion,
Kind: KindTokenReview,
Status: &Status{
Authenticated: true,
User: map[string]interface{}{"username": user.Username, "uid": user.Username, "groups": user.Groups},
},
}
resp.WriteAsJson(success)
return
}

253
pkg/apiserver/iam/groups.go Normal file
View File

@@ -0,0 +1,253 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam
import (
"fmt"
"net/http"
"regexp"
"strings"
"github.com/emicklei/go-restful"
"github.com/go-ldap/ldap"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam"
)
func CreateGroup(req *restful.Request, resp *restful.Response) {
//var json map[string]interface{}
var group models.Group
err := req.ReadEntity(&group)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if !regexp.MustCompile("[a-z0-9]([-a-z0-9]*[a-z0-9])?").MatchString(group.Name) {
resp.WriteHeaderAndEntity(http.StatusBadRequest, fmt.Errorf("incalid group name %s", group))
return
}
if group.Creator == "" {
resp.WriteHeaderAndEntity(http.StatusBadRequest, fmt.Errorf("creator should not be null"))
return
}
created, err := iam.CreateGroup(group)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(created)
}
func DeleteGroup(req *restful.Request, resp *restful.Response) {
path := req.PathParameter("path")
if path == "" {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("group path must not be null")))
return
}
err := iam.DeleteGroup(path)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func UpdateGroup(req *restful.Request, resp *restful.Response) {
groupPathInPath := req.PathParameter("path")
var group models.Group
req.ReadEntity(&group)
if groupPathInPath != group.Path {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("the path of group (%s) does not match the path on the URL (%s)", group.Path, groupPathInPath)))
return
}
edited, err := iam.UpdateGroup(&group)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(edited)
}
func GroupDetail(req *restful.Request, resp *restful.Response) {
path := req.PathParameter("path")
conn, err := iam.NewConnection()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
group, err := iam.GroupDetail(path, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(group)
}
func GroupUsers(req *restful.Request, resp *restful.Response) {
path := req.PathParameter("path")
conn, err := iam.NewConnection()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
group, err := iam.GroupDetail(path, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
users := make([]*models.User, 0)
modify := false
for i := 0; i < len(group.Members); i++ {
name := group.Members[i]
user, err := iam.UserDetail(name, conn)
if err != nil {
if ldap.IsErrorWithCode(err, 32) {
group.Members = append(group.Members[:i], group.Members[i+1:]...)
i--
modify = true
continue
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
}
clusterRoles, err := iam.GetClusterRoles(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for i := 0; i < len(clusterRoles); i++ {
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
user.ClusterRole = clusterRoles[i].Name
break
}
}
if group.Path == group.Name {
workspaceRole := iam.GetWorkspaceRole(clusterRoles, group.Name)
user.WorkspaceRole = workspaceRole
}
users = append(users, user)
}
if modify {
go iam.UpdateGroup(group)
}
resp.WriteAsJson(users)
}
func CountHandler(req *restful.Request, resp *restful.Response) {
count, err := iam.CountChild("")
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(map[string]int{"total_count": count})
}
func RootGroupList(req *restful.Request, resp *restful.Response) {
array := req.QueryParameter("path")
if array == "" {
groups, err := iam.ChildList("")
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(groups)
} else {
paths := strings.Split(array, ",")
groups := make([]*models.Group, 0)
conn, err := iam.NewConnection()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
for _, v := range paths {
path := strings.TrimSpace(v)
group, err := iam.GroupDetail(path, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
groups = append(groups, group)
}
resp.WriteAsJson(groups)
}
}

365
pkg/apiserver/iam/users.go Normal file
View File

@@ -0,0 +1,365 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam
import (
"fmt"
"net/http"
"regexp"
"strconv"
"strings"
"github.com/emicklei/go-restful"
"github.com/go-ldap/ldap"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam"
)
const (
emailRegex = "^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$"
)
func CreateUser(req *restful.Request, resp *restful.Response) {
var user models.User
err := req.ReadEntity(&user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if user.Username == "" {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid username")))
return
}
if !regexp.MustCompile(emailRegex).MatchString(user.Email) {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid email")))
return
}
if len(user.Password) < 6 {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid password")))
return
}
err = iam.CreateUser(user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func DeleteUser(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("name")
operator := req.HeaderParameter(constants.UserNameHeader)
if operator == username {
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(fmt.Errorf("cannot delete yourself")))
return
}
err := iam.DeleteUser(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func UpdateUser(req *restful.Request, resp *restful.Response) {
usernameInPath := req.PathParameter("name")
username := req.HeaderParameter(constants.UserNameHeader)
var user models.User
err := req.ReadEntity(&user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if usernameInPath != user.Username {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("the name of user (%s) does not match the name on the URL (%s)", user.Username, usernameInPath)))
return
}
if !regexp.MustCompile(emailRegex).MatchString(user.Email) {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid email")))
return
}
if user.Password != "" && len(user.Password) < 6 {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid password")))
return
}
if username == user.Username && user.Password != "" {
_, err = iam.Login(username, user.CurrentPassword, "")
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("incorrect current password")))
return
}
}
err = iam.UpdateUser(user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func UserLoginLog(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("name")
logs, err := iam.LoginLog(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
result := make([]map[string]string, 0)
for _, v := range logs {
item := strings.Split(v, ",")
time := item[0]
var ip string
if len(item) > 1 {
ip = item[1]
}
result = append(result, map[string]string{"login_time": time, "login_ip": ip})
}
resp.WriteAsJson(result)
}
func CurrentUserDetail(req *restful.Request, resp *restful.Response) {
username := req.HeaderParameter(constants.UserNameHeader)
conn, err := iam.NewConnection()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
user, err := iam.UserDetail(username, conn)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
}
return
}
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
clusterRules, err := iam.GetClusterRoleSimpleRules(clusterRoles)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for i := 0; i < len(clusterRoles); i++ {
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
user.ClusterRole = clusterRoles[i].Name
break
}
}
user.ClusterRules = clusterRules
resp.WriteAsJson(user)
}
func NamespacesListHandler(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("name")
namespaces, err := iam.GetNamespaces(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(namespaces)
}
func UserDetail(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("name")
conn, err := iam.NewConnection()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
user, err := iam.UserDetail(username, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
clusterRules, err := iam.GetClusterRoleSimpleRules(clusterRoles)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
workspaceRoles := iam.GetWorkspaceRoles(clusterRoles)
for i := 0; i < len(clusterRoles); i++ {
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
user.ClusterRole = clusterRoles[i].Name
break
}
}
user.ClusterRules = clusterRules
user.WorkspaceRoles = workspaceRoles
resp.WriteAsJson(user)
}
func UserList(req *restful.Request, resp *restful.Response) {
limit, err := strconv.Atoi(req.QueryParameter("limit"))
if err != nil {
limit = 65535
}
offset, err := strconv.Atoi(req.QueryParameter("offset"))
if err != nil {
offset = 0
}
if check := req.QueryParameter("check"); check != "" {
exist, err := iam.UserCreateCheck(check)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(map[string]bool{"exist": exist})
return
}
conn, err := iam.NewConnection()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
if query := req.QueryParameter("name"); query != "" {
names := strings.Split(query, ",")
users := make([]*models.User, 0)
for _, name := range names {
user, err := iam.UserDetail(name, conn)
if err != nil {
if ldap.IsErrorWithCode(err, 32) {
continue
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
}
users = append(users, user)
}
resp.WriteAsJson(users)
return
}
var total int
var users []models.User
if query := req.QueryParameter("search"); query != "" {
total, users, err = iam.Search(query, limit, offset)
} else if query := req.QueryParameter("keyword"); query != "" {
total, users, err = iam.Search(query, limit, offset)
} else {
total, users, err = iam.UserList(limit, offset)
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for i := 0; i < len(users); i++ {
clusterRoles, err := iam.GetClusterRoles(users[i].Username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for j := 0; j < len(clusterRoles); j++ {
if clusterRoles[j].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
users[i].ClusterRole = clusterRoles[j].Name
break
}
}
}
items := make([]interface{}, 0)
for _, u := range users {
items = append(items, u)
}
resp.WriteAsJson(models.PageableResponse{Items: items, TotalCount: total})
}

View File

@@ -0,0 +1,746 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam
import (
"fmt"
"net/http"
"regexp"
"sort"
"strconv"
"strings"
"github.com/emicklei/go-restful"
"github.com/go-ldap/ldap"
"k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
apierror "k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/metrics"
"kubesphere.io/kubesphere/pkg/models/workspaces"
sliceutils "kubesphere.io/kubesphere/pkg/utils"
)
const UserNameHeader = "X-Token-Username"
func WorkspaceRoles(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
roles, err := workspaces.Roles(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(roles)
}
func WorkspaceMemberQuery(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, errors.Wrap(err))
return
}
resp.WriteAsJson(users)
}
func WorkspaceMemberDetail(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, errors.Wrap(err))
return
}
namespaces, err := workspaces.Namespaces(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
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.WriteAsJson(user)
}
func WorkspaceMemberInvite(req *restful.Request, resp *restful.Response) {
var users []models.UserInvite
workspace := req.PathParameter("name")
err := req.ReadEntity(&users)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
err = workspaces.Invite(workspace, users)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func WorkspaceMemberRemove(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, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
exist, err := workspaces.NamespaceExistCheck(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(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, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
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, errors.Wrap(err))
return
}
err = workspaces.DeleteDevopsProject(username, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
var devops models.DevopsProject
err := req.ReadEntity(&devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(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, errors.Wrap(err))
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, errors.Wrap(fmt.Errorf("invalid workspace name")))
return
}
resp.WriteAsJson(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, errors.Wrap(err))
return
}
result := models.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range devOpsProjects {
result.Items = append(result.Items, n)
}
resp.WriteAsJson(result)
}
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
var workspace models.Workspace
username := req.HeaderParameter(UserNameHeader)
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("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, errors.Wrap(err))
return
}
resp.WriteAsJson(created)
}
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
if name == "" || strings.Contains(name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
return
}
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
err = workspaces.Delete(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
var workspace models.Workspace
name := req.PathParameter("name")
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if name != workspace.Name {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(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, errors.Wrap(fmt.Errorf("invalid workspace name")))
return
}
workspace.Path = workspace.Name
workspace.Members = nil
edited, err := workspaces.Edit(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(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, errors.Wrap(err))
return
}
resp.WriteAsJson(workspace)
}
// List all workspaces for the current user
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
keyword := req.QueryParameter("keyword")
username := req.HeaderParameter(constants.UserNameHeader)
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
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.WriteAsJson(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, errors.Wrap(err))
return
}
result := models.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range namespaces {
result.Items = append(result.Items, n)
}
resp.WriteAsJson(result)
}
func DevopsRulesHandler(req *restful.Request, resp *restful.Response) {
//workspaceName := req.PathParameter("workspace")
username := req.HeaderParameter(constants.UserNameHeader)
devopsName := req.PathParameter("devops")
var rules []models.SimpleRule
role, err := iam.GetDevopsRole(devopsName, username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
switch role {
case "developer":
rules = []models.SimpleRule{
{Name: "pipelines", Actions: []string{"view", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
}
break
case "owner":
rules = []models.SimpleRule{
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "devops", Actions: []string{"edit", "view", "delete"}},
}
break
case "maintainer":
rules = []models.SimpleRule{
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "devops", Actions: []string{"view"}},
}
break
case "reporter":
fallthrough
default:
rules = []models.SimpleRule{
{Name: "pipelines", Actions: []string{"view"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
}
break
}
resp.WriteAsJson(rules)
}
func NamespacesRulesHandler(req *restful.Request, resp *restful.Response) {
workspaceName := req.PathParameter("workspace")
username := req.HeaderParameter(constants.UserNameHeader)
namespaceName := req.PathParameter("namespace")
namespace, err := iam.GetNamespace(namespaceName)
if err != nil {
if apierror.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("permission undefined")))
} else {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
}
return
}
if namespace.Labels == nil || namespace.Labels["kubesphere.io/workspace"] != workspaceName {
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(fmt.Errorf("permission undefined")))
return
}
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
roles, err := iam.GetRoles(username, namespaceName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for _, clusterRole := range clusterRoles {
role := new(rbac.Role)
role.Name = clusterRole.Name
role.Labels = clusterRole.Labels
role.Namespace = namespaceName
role.Annotations = clusterRole.Annotations
role.Kind = "Role"
role.Rules = clusterRole.Rules
roles = append(roles, role)
}
rules, err := iam.GetRoleSimpleRules(roles, namespaceName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
if rules[namespaceName] == nil {
resp.WriteAsJson(make([]models.SimpleRule, 0))
} else {
resp.WriteAsJson(rules[namespaceName])
}
}
func WorkspaceRulesHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
username := req.HeaderParameter(constants.UserNameHeader)
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
rules := iam.GetWorkspaceSimpleRules(clusterRoles, workspace)
if rules[workspace] != nil {
resp.WriteAsJson(rules[workspace])
} else if rules["*"] != nil {
resp.WriteAsJson(rules["*"])
} else {
resp.WriteAsJson(make([]models.SimpleRule, 0))
}
}
func WorkspaceMemberList(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
limit, err := strconv.Atoi(req.QueryParameter("limit"))
if err != nil {
limit = 500
}
offset, err := strconv.Atoi(req.QueryParameter("offset"))
if err != nil {
offset = 0
}
conn, err := iam.NewConnection()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
group, err := iam.GroupDetail(workspace, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
keyword := ""
if query := req.QueryParameter("keyword"); query != "" {
keyword = query
}
users := make([]*models.User, 0)
total := len(group.Members)
members := sliceutils.RemoveString(group.Members, func(item string) bool {
return keyword != "" && !strings.Contains(item, keyword)
})
for i := 0; i < len(members); i++ {
username := members[i]
if i < offset {
continue
}
if len(users) == limit {
break
}
user, err := iam.UserDetail(username, conn)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
group.Members = sliceutils.RemoveString(group.Members, func(item string) bool {
return item == username
})
continue
} else {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
}
clusterRoles, err := iam.GetClusterRoles(username)
for i := 0; i < len(clusterRoles); i++ {
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
user.ClusterRole = clusterRoles[i].Name
break
}
}
if group.Path == group.Name {
workspaceRole := iam.GetWorkspaceRole(clusterRoles, group.Name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
user.WorkspaceRole = workspaceRole
}
users = append(users, user)
}
if total > len(group.Members) {
go iam.UpdateGroup(group)
}
if req.QueryParameter("limit") != "" {
resp.WriteAsJson(map[string]interface{}{"items": users, "total_count": len(members)})
} else {
resp.WriteAsJson(users)
}
}

View File

@@ -21,9 +21,10 @@ import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/storage" "kubesphere.io/kubesphere/pkg/models/storage"
"net/http"
) )
type scMetricsItem struct { type ScMetricsItem struct {
Name string `json:"name"` Name string `json:"name"`
Metrics *storage.ScMetrics `json:"metrics"` Metrics *storage.ScMetrics `json:"metrics"`
} }
@@ -35,11 +36,12 @@ func GetScMetrics(request *restful.Request, response *restful.Response) {
metrics, err := storage.GetScMetrics(scName) metrics, err := storage.GetScMetrics(scName)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
result := scMetricsItem{ result := ScMetricsItem{
Name: scName, Metrics: metrics, Name: scName, Metrics: metrics,
} }
@@ -51,21 +53,23 @@ func GetScMetrics(request *restful.Request, response *restful.Response) {
func GetScMetricsList(request *restful.Request, response *restful.Response) { func GetScMetricsList(request *restful.Request, response *restful.Response) {
scList, err := storage.GetScList() scList, err := storage.GetScList()
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
// Set return value // Set return value
items := make([]scMetricsItem, 0) items := make([]ScMetricsItem, 0)
for _, v := range scList { for _, v := range scList {
metrics, err := storage.GetScMetrics(v.GetName()) metrics, err := storage.GetScMetrics(v.GetName())
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
item := scMetricsItem{ item := ScMetricsItem{
Name: v.GetName(), Metrics: metrics, Name: v.GetName(), Metrics: metrics,
} }

View File

@@ -0,0 +1,220 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package monitoring
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/models/metrics"
)
func 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 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 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 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 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 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 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 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 MonitorComponentStatus(request *restful.Request, response *restful.Response) {
requestParams := client.ParseMonitoringRequestParams(request)
status := metrics.MonitorComponentStatus(requestParams)
response.WriteAsJson(status)
}

View File

@@ -19,10 +19,9 @@
package operations package operations
import ( import (
"net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/workloads" "kubesphere.io/kubesphere/pkg/models/workloads"
"net/http"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
@@ -40,10 +39,11 @@ func RerunJob(req *restful.Request, resp *restful.Response) {
case "rerun": case "rerun":
err = workloads.JobReRun(namespace, job) err = workloads.JobReRun(namespace, job)
default: default:
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, fmt.Sprintf("invalid operation %s", action))) resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid operation %s", action)))
return return
} }
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -20,6 +20,7 @@ package operations
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/nodes" "kubesphere.io/kubesphere/pkg/models/nodes"
@@ -31,7 +32,8 @@ func DrainNode(request *restful.Request, response *restful.Response) {
err := nodes.DrainNode(nodeName) err := nodes.DrainNode(nodeName)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -20,48 +20,30 @@ package quotas
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi" "net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/quotas" "kubesphere.io/kubesphere/pkg/models/quotas"
) )
func V1Alpha2(ws *restful.WebService) { func GetNamespaceQuotas(req *restful.Request, resp *restful.Response) {
tags := []string{"quotas"}
ws.Route(ws.GET("/quotas").
To(getClusterQuotas).
Doc("get whole cluster's resource usage").
Writes(quotas.ResourceQuota{}).
Metadata(restfulspec.KeyOpenAPITags, tags))
ws.Route(ws.GET("/namespaces/{namespace}/quotas").
Doc("get specified namespace's resource quota and usage").
Param(ws.PathParameter("namespace", "namespace's name").
DataType("string")).
Writes(quotas.ResourceQuota{}).
Metadata(restfulspec.KeyOpenAPITags, tags).
To(getNamespaceQuotas))
}
func getNamespaceQuotas(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace") namespace := req.PathParameter("namespace")
quota, err := quotas.GetNamespaceQuotas(namespace) quota, err := quotas.GetNamespaceQuotas(namespace)
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
resp.WriteAsJson(quota) resp.WriteAsJson(quota)
} }
func getClusterQuotas(req *restful.Request, resp *restful.Response) { func GetClusterQuotas(req *restful.Request, resp *restful.Response) {
quota, err := quotas.GetClusterQuotas() quota, err := quotas.GetClusterQuotas()
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -20,55 +20,29 @@ package registries
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/registries" "kubesphere.io/kubesphere/pkg/models/registries"
) )
func V1Alpha2(ws *restful.WebService) { func RegistryVerify(request *restful.Request, response *restful.Response) {
ws.Route(ws.POST("registries/verify").To(registryVerify))
}
func registryVerify(request *restful.Request, response *restful.Response) {
authInfo := registries.AuthInfo{} authInfo := registries.AuthInfo{}
err := request.ReadEntity(&authInfo) err := request.ReadEntity(&authInfo)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
err = registries.RegistryVerify(authInfo) err = registries.RegistryVerify(authInfo)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
response.WriteAsJson(errors.None) response.WriteAsJson(errors.None)
} }
//func (c *registriesHandler) handlerImageSearch(request *restful.Request, response *restful.Response) {
//
// registry := request.PathParameter("name")
// searchWord := request.PathParameter("searchWord")
// namespace := request.PathParameter("namespace")
//
// res := c.registries.ImageSearch(namespace, registry, searchWord)
//
// response.WriteAsJson(res)
//
//}
//
//func (c *registriesHandler) handlerGetImageTags(request *restful.Request, response *restful.Response) {
//
// registry := request.PathParameter("name")
// image := request.QueryParameter("image")
// namespace := request.PathParameter("namespace")
//
// res := c.registries.GetImageTags(namespace, registry, image)
//
// response.WriteAsJson(res)
//}

View File

@@ -19,6 +19,7 @@ package resources
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/resources" "kubesphere.io/kubesphere/pkg/models/resources"
@@ -27,14 +28,15 @@ import (
func ClusterResourceHandler(req *restful.Request, resp *restful.Response) { func ClusterResourceHandler(req *restful.Request, resp *restful.Response) {
resourceName := req.PathParameter("resources") resourceName := req.PathParameter("resources")
conditions := req.QueryParameter(params.Conditions) conditions, err := params.ParseConditions(req)
orderBy := req.QueryParameter(params.OrderBy) orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging)) limit, offset := params.ParsePaging(req)
reverse := params.ParseReserve(req.QueryParameter(params.Reserve)) reverse := params.ParseReverse(req)
result, err := resources.ListClusterResource(resourceName, conditions, orderBy, reverse, limit, offset) result, err := resources.ListClusterResource(resourceName, conditions, orderBy, reverse, limit, offset)
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -19,6 +19,7 @@ package resources
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/resources" "kubesphere.io/kubesphere/pkg/models/resources"
@@ -28,14 +29,15 @@ import (
func NamespaceResourceHandler(req *restful.Request, resp *restful.Response) { func NamespaceResourceHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace") namespace := req.PathParameter("namespace")
resourceName := req.PathParameter("resources") resourceName := req.PathParameter("resources")
conditions := req.QueryParameter(params.Conditions) conditions, err := params.ParseConditions(req)
orderBy := req.QueryParameter(params.OrderBy) orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging)) limit, offset := params.ParsePaging(req)
reverse := params.ParseReserve(req.QueryParameter(params.Reserve)) reverse := params.ParseReverse(req)
result, err := resources.ListNamespaceResource(namespace, resourceName, conditions, orderBy, reverse, limit, offset) result, err := resources.ListNamespaceResource(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -20,6 +20,7 @@ package resources
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/storage" "kubesphere.io/kubesphere/pkg/models/storage"
@@ -43,7 +44,8 @@ func GetPodListByPvc(request *restful.Request, response *restful.Response) {
pvcName := request.PathParameter("pvc") pvcName := request.PathParameter("pvc")
nsName := request.PathParameter("namespace") nsName := request.PathParameter("namespace")
pods, err := storage.GetPodListByPvc(pvcName, nsName) pods, err := storage.GetPodListByPvc(pvcName, nsName)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
result := podListByPvc{Name: pvcName, Namespace: nsName, Pods: pods} result := podListByPvc{Name: pvcName, Namespace: nsName, Pods: pods}
@@ -56,7 +58,8 @@ func GetPvcListBySc(request *restful.Request, response *restful.Response) {
scName := request.PathParameter("storageclass") scName := request.PathParameter("storageclass")
claims, err := storage.GetPvcListBySc(scName) claims, err := storage.GetPvcListBySc(scName)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -19,6 +19,7 @@ package resources
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/kubeconfig" "kubesphere.io/kubesphere/pkg/models/kubeconfig"
@@ -31,7 +32,8 @@ func GetKubectl(req *restful.Request, resp *restful.Response) {
kubectlPod, err := kubectl.GetKubectlPod(user) kubectlPod, err := kubectl.GetKubectlPod(user)
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
@@ -44,7 +46,8 @@ func GetKubeconfig(req *restful.Request, resp *restful.Response) {
kubectlConfig, err := kubeconfig.GetKubeConfig(user) kubectlConfig, err := kubeconfig.GetKubeConfig(user)
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -22,93 +22,59 @@ import (
"strconv" "strconv"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/api/apps/v1"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/revisions" "kubesphere.io/kubesphere/pkg/models/revisions"
) )
func V1Alpha2(ws *restful.WebService) { func GetDaemonSetRevision(req *restful.Request, resp *restful.Response) {
ws.Route(ws.GET("/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}").
To(getDaemonSetRevision).
Metadata(restfulspec.KeyOpenAPITags, []string{"daemonsets", "revision"}).
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{}))
ws.Route(ws.GET("/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}").
To(getDeployRevision).
Metadata(restfulspec.KeyOpenAPITags, []string{"deployments", "revision"}).
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{}))
ws.Route(ws.GET("/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}").
To(getStatefulSetRevision).
Metadata(restfulspec.KeyOpenAPITags, []string{"statefulsets", "revisions"}).
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) {
daemonset := req.PathParameter("daemonset") daemonset := req.PathParameter("daemonset")
namespace := req.PathParameter("namespace") namespace := req.PathParameter("namespace")
revision, err := strconv.Atoi(req.PathParameter("revision")) revision, err := strconv.Atoi(req.PathParameter("revision"))
if err != nil { if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error())) resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return return
} }
result, err := revisions.GetDaemonSetRevision(namespace, daemonset, revision) result, err := revisions.GetDaemonSetRevision(namespace, daemonset, revision)
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
resp.WriteAsJson(result) resp.WriteAsJson(result)
} }
func getDeployRevision(req *restful.Request, resp *restful.Response) { func GetDeployRevision(req *restful.Request, resp *restful.Response) {
deploy := req.PathParameter("deployment") deploy := req.PathParameter("deployment")
namespace := req.PathParameter("namespace") namespace := req.PathParameter("namespace")
revision := req.PathParameter("revision") revision := req.PathParameter("revision")
result, err := revisions.GetDeployRevision(namespace, deploy, revision) result, err := revisions.GetDeployRevision(namespace, deploy, revision)
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
resp.WriteAsJson(result) resp.WriteAsJson(result)
} }
func getStatefulSetRevision(req *restful.Request, resp *restful.Response) { func GetStatefulSetRevision(req *restful.Request, resp *restful.Response) {
statefulset := req.PathParameter("statefulset") statefulset := req.PathParameter("statefulset")
namespace := req.PathParameter("namespace") namespace := req.PathParameter("namespace")
revision, err := strconv.Atoi(req.PathParameter("revision")) revision, err := strconv.Atoi(req.PathParameter("revision"))
if err != nil { if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error())) resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return return
} }
result, err := revisions.GetStatefulSetRevision(namespace, statefulset, revision) result, err := revisions.GetStatefulSetRevision(namespace, statefulset, revision)
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }

View File

@@ -19,58 +19,31 @@
package routers package routers
import ( import (
"fmt"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"net/http"
"strings" "strings"
"github.com/golang/glog"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"kubesphere.io/kubesphere/pkg/models/routers" "kubesphere.io/kubesphere/pkg/models/routers"
) )
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.GET("/routers").To(getAllRouters).
Doc("Get all routers"))
ws.Route(ws.GET("/users/{username}/routers").To(getAllRoutersOfUser).
Doc("Get routers for user"))
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")))
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")))
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")))
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")))
}
type Router struct { type Router struct {
RouterType string `json:"type"` RouterType string `json:"type"`
Annotations map[string]string `json:"annotations"` Annotations map[string]string `json:"annotations"`
} }
// Get all namespace ingress controller services // Get all namespace ingress controller services
func getAllRouters(request *restful.Request, response *restful.Response) { func GetAllRouters(request *restful.Request, response *restful.Response) {
routers, err := routers.GetAllRouters() routers, err := routers.GetAllRouters()
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
@@ -78,13 +51,14 @@ func getAllRouters(request *restful.Request, response *restful.Response) {
} }
// Get all namespace ingress controller services for user // Get all namespace ingress controller services for user
func getAllRoutersOfUser(request *restful.Request, response *restful.Response) { func GetAllRoutersOfUser(request *restful.Request, response *restful.Response) {
username := request.PathParameter("username") username := request.PathParameter("username")
routers, err := routers.GetAllRoutersOfUser(username) routers, err := routers.GetAllRoutersOfUser(username)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
@@ -92,12 +66,13 @@ func getAllRoutersOfUser(request *restful.Request, response *restful.Response) {
} }
// Get ingress controller service for specified namespace // Get ingress controller service for specified namespace
func getRouter(request *restful.Request, response *restful.Response) { func GetRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace") namespace := request.PathParameter("namespace")
router, err := routers.GetRouter(namespace) router, err := routers.GetRouter(namespace)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
@@ -105,7 +80,7 @@ func getRouter(request *restful.Request, response *restful.Response) {
} }
// Create ingress controller and related services // Create ingress controller and related services
func createRouter(request *restful.Request, response *restful.Response) { func CreateRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace") namespace := request.PathParameter("namespace")
@@ -119,18 +94,17 @@ func createRouter(request *restful.Request, response *restful.Response) {
var router *v1.Service var router *v1.Service
serviceType, annotationMap, err := ParseParameter(newRouter) serviceType, annotationMap, err := parseParameter(newRouter)
if err != nil { if err != nil {
glog.Error("Wrong annotations, missing key or value") response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("wrong annotations, missing key or value")))
response.WriteHeaderAndEntity(http.StatusBadRequest,
errors.New(errors.InvalidArgument, "Wrong annotations, missing key or value"))
return return
} }
router, err = routers.CreateRouter(namespace, serviceType, annotationMap) router, err = routers.CreateRouter(namespace, serviceType, annotationMap)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
@@ -138,19 +112,20 @@ func createRouter(request *restful.Request, response *restful.Response) {
} }
// Delete ingress controller and services // Delete ingress controller and services
func deleteRouter(request *restful.Request, response *restful.Response) { func DeleteRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace") namespace := request.PathParameter("namespace")
router, err := routers.DeleteRouter(namespace) router, err := routers.DeleteRouter(namespace)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
response.WriteAsJson(router) response.WriteAsJson(router)
} }
func updateRouter(request *restful.Request, response *restful.Response) { func UpdateRouter(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace") namespace := request.PathParameter("namespace")
@@ -158,23 +133,23 @@ func updateRouter(request *restful.Request, response *restful.Response) {
err := request.ReadEntity(&newRouter) err := request.ReadEntity(&newRouter)
if err != nil { if err != nil {
glog.Error(err) response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
return return
} }
serviceType, annotationMap, err := ParseParameter(newRouter) serviceType, annotationMap, err := parseParameter(newRouter)
router, err := routers.UpdateRouter(namespace, serviceType, annotationMap) router, err := routers.UpdateRouter(namespace, serviceType, annotationMap)
if errors.HandlerError(err, response) { if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
response.WriteAsJson(router) response.WriteAsJson(router)
} }
func ParseParameter(router Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) { func parseParameter(router Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) {
routerType = v1.ServiceTypeNodePort routerType = v1.ServiceTypeNodePort

View File

@@ -35,7 +35,9 @@ type ContainerBuilder []func(c *restful.Container) error
func NewWebService(gv schema.GroupVersion) *restful.WebService { func NewWebService(gv schema.GroupVersion) *restful.WebService {
webservice := restful.WebService{} webservice := restful.WebService{}
webservice.Path(ApiRootPath + "/" + gv.String()) webservice.Path(ApiRootPath + "/" + gv.String()).
Consumes(restful.MIME_JSON).
Produces(restful.MIME_JSON)
return &webservice return &webservice
} }

View File

@@ -20,39 +20,25 @@ package workloadstatuses
import ( import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi" "net/http"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/status" "kubesphere.io/kubesphere/pkg/models/status"
) )
func V1Alpha2(ws *restful.WebService) { func GetClusterResourceStatus(req *restful.Request, resp *restful.Response) {
tags := []string{"workloadStatus"}
ws.Route(ws.GET("/workloadstatuses").
Doc("get abnormal workloads' count of whole cluster").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(getClusterResourceStatus))
ws.Route(ws.GET("/namespaces/{namespace}/workloadstatuses").
Doc("get abnormal workloads' count of specified namespace").
Param(ws.PathParameter("namespace", "the name of namespace").
DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
To(getNamespacesResourceStatus))
}
func getClusterResourceStatus(req *restful.Request, resp *restful.Response) {
res, err := status.GetClusterResourceStatus() res, err := status.GetClusterResourceStatus()
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
resp.WriteAsJson(res) resp.WriteAsJson(res)
} }
func getNamespacesResourceStatus(req *restful.Request, resp *restful.Response) { func GetNamespacesResourceStatus(req *restful.Request, resp *restful.Response) {
res, err := status.GetNamespacesResourceStatus(req.PathParameter("namespace")) res, err := status.GetNamespacesResourceStatus(req.PathParameter("namespace"))
if errors.HandlerError(err, resp) { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return return
} }
resp.WriteAsJson(res) resp.WriteAsJson(res)

View File

@@ -16,491 +16,3 @@
*/ */
package workspaces package workspaces
import (
"net/http"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/metrics"
"github.com/emicklei/go-restful"
"k8s.io/api/core/v1"
"fmt"
"strings"
"strconv"
"regexp"
"sort"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/workspaces"
)
const UserNameHeader = "X-Token-Username"
func V1Alpha2(ws *restful.WebService) {
ws.Route(ws.GET("/workspaces").To(UserWorkspaceListHandler))
ws.Route(ws.POST("/workspaces").To(WorkspaceCreateHandler))
ws.Route(ws.DELETE("/workspaces/{name}").To(DeleteWorkspaceHandler))
ws.Route(ws.GET("/workspaces/{name}").To(WorkspaceDetailHandler))
ws.Route(ws.PUT("/workspaces/{name}").To(WorkspaceEditHandler))
ws.Route(ws.GET("/workspaces/{workspace}/namespaces").To(UserNamespaceListHandler))
ws.Route(ws.GET("/workspaces/{workspace}/members/{username}/namespaces").To(UserNamespaceListHandler))
ws.Route(ws.POST("/workspaces/{name}/namespaces").To(NamespaceCreateHandler))
ws.Route(ws.DELETE("/workspaces/{name}/namespaces/{namespace}").To(NamespaceDeleteHandler))
ws.Route(ws.GET("/workspaces/{name}/namespaces/{namespace}").To(NamespaceCheckHandler))
ws.Route(ws.GET("/namespaces/{namespace}").To(NamespaceCheckHandler))
ws.Route(ws.GET("/workspaces/{name}/devops").To(DevOpsProjectHandler))
ws.Route(ws.GET("/workspaces/{name}/members/{username}/devops").To(DevOpsProjectHandler))
ws.Route(ws.POST("/workspaces/{name}/devops").To(DevOpsProjectCreateHandler))
ws.Route(ws.DELETE("/workspaces/{name}/devops/{id}").To(DevOpsProjectDeleteHandler))
ws.Route(ws.GET("/workspaces/{name}/members").To(MembersHandler))
ws.Route(ws.GET("/workspaces/{name}/members/{member}").To(MemberHandler))
ws.Route(ws.GET("/workspaces/{name}/roles").To(RolesHandler))
// TODO /workspaces/{name}/roles/{role}
ws.Route(ws.POST("/workspaces/{name}/members").To(MembersInviteHandler))
ws.Route(ws.DELETE("/workspaces/{name}/members").To(MembersRemoveHandler))
}
func RolesHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if errors.HandlerError(err, resp) {
return
}
roles, err := workspaces.Roles(workspace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(roles)
}
func MembersHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
keyword := req.QueryParameter("keyword")
users, err := workspaces.GetWorkspaceMembers(workspace, keyword)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(users)
}
func MemberHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("member")
user, err := iam.GetUser(username)
if errors.HandlerError(err, resp) {
return
}
namespaces, err := workspaces.Namespaces(workspace)
if errors.HandlerError(err, resp) {
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.WriteAsJson(user)
}
func MembersInviteHandler(req *restful.Request, resp *restful.Response) {
var users []workspaces.UserInvite
workspace := req.PathParameter("name")
err := req.ReadEntity(&users)
if errors.HandlerError(err, resp) {
return
}
err = workspaces.Invite(workspace, users)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
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 errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
exist, err := workspaces.NamespaceExistCheck(namespace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(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 errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
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, errors.New(errors.Internal, err.Error()))
return
}
err = workspaces.DeleteDevopsProject(username, devops)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
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, errors.New(errors.InvalidArgument, err.Error()))
return
}
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(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, errors.New(errors.InvalidArgument, 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, errors.New(errors.InvalidArgument, err.Error()))
return
}
resp.WriteAsJson(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 errors.HandlerError(err, resp) {
return
}
result := models.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range devOpsProjects {
result.Items = append(result.Items, n)
}
resp.WriteAsJson(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, errors.New(errors.InvalidArgument, err.Error()))
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "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 errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(created)
}
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
if name == "" || strings.Contains(name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
return
}
workspace, err := workspaces.Detail(name)
if errors.HandlerError(err, resp) {
return
}
err = workspaces.Delete(workspace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(errors.None)
}
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, errors.New(errors.InvalidArgument, 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, errors.New(errors.InvalidArgument, "invalid workspace name"))
return
}
workspace.Path = workspace.Name
workspace.Members = nil
edited, err := workspaces.Edit(&workspace)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(edited)
}
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if errors.HandlerError(err, resp) {
return
}
resp.WriteAsJson(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 errors.HandlerError(err, resp) {
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.WriteAsJson(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 errors.HandlerError(err, resp) {
return
}
result := models.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range namespaces {
result.Items = append(result.Items, n)
}
resp.WriteAsJson(result)
}

View File

@@ -1,51 +1,56 @@
/* /*
Copyright 2018 The KubeSphere Authors.
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package client package client
import ( import (
"fmt" "flag"
"log"
"sync"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
"github.com/golang/glog"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
) )
var dbClient *gorm.DB var (
dbClientOnce sync.Once
dbClient *gorm.DB
dsn string
)
func NewDBClient() *gorm.DB { func init() {
conn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", "", "", "", "") flag.StringVar(&dsn, "database-connection", "root@tcp(localhost:3306)/kubesphere?charset=utf8&parseTime=True", "data source name")
}
db, err := gorm.Open("mysql", conn) func DBClient() *gorm.DB {
dbClientOnce.Do(func() {
var err error
dbClient, err = gorm.Open("mysql", dsn)
if err != nil { if err != nil {
glog.Error(err) log.Fatalln(err)
panic(err)
}
return db
} }
func NewSharedDBClient() *gorm.DB { if err := dbClient.DB().Ping(); err != nil {
log.Fatalln(err)
}
})
if dbClient != nil {
err := dbClient.DB().Ping()
if err == nil {
return dbClient return dbClient
} else {
glog.Error(err)
panic(err)
}
}
return NewDBClient()
} }

View File

@@ -19,25 +19,31 @@
package client package client
import ( import (
"flag"
"fmt" "fmt"
"log"
"os" "os"
"sync" "sync"
"k8s.io/client-go/tools/clientcmd"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
"github.com/golang/glog"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
) )
var ( var (
KubeConfigFile string kubeConfigFile string
k8sClient *kubernetes.Clientset k8sClient *kubernetes.Clientset
k8sClientOnce sync.Once k8sClientOnce sync.Once
KubeConfig *rest.Config KubeConfig *rest.Config
) )
func init() {
flag.StringVar(&kubeConfigFile, "kubeconfig", fmt.Sprintf("%s/.kube/config", os.Getenv("HOME")), "path to kubeconfig file")
}
func K8sClient() *kubernetes.Clientset { func K8sClient() *kubernetes.Clientset {
k8sClientOnce.Do(func() { k8sClientOnce.Do(func() {
@@ -45,14 +51,10 @@ func K8sClient() *kubernetes.Clientset {
config, err := getKubeConfig() config, err := getKubeConfig()
if err != nil { if err != nil {
glog.Fatalf("cannot load kubeconfig: %v", err) log.Fatalln(err)
} }
k8sClient, err = kubernetes.NewForConfig(config) k8sClient = kubernetes.NewForConfigOrDie(config)
if err != nil {
glog.Fatalf("cannot create k8s client: %v", err)
}
KubeConfig = config KubeConfig = config
}) })
@@ -62,36 +64,28 @@ func K8sClient() *kubernetes.Clientset {
func getKubeConfig() (kubeConfig *rest.Config, err error) { func getKubeConfig() (kubeConfig *rest.Config, err error) {
if KubeConfigFile == "" { if kubeConfigFile == "" {
if env := os.Getenv("KUBECONFIG"); env != "" { if env := os.Getenv("KUBECONFIG"); env != "" {
KubeConfigFile = env kubeConfigFile = env
} else { } else {
if home, err := homedir.Dir(); err == nil { if home, err := homedir.Dir(); err == nil {
KubeConfigFile = fmt.Sprintf("%s/.kube/config", home) kubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
} }
} }
} }
if KubeConfigFile != "" { if _, err = os.Stat(kubeConfigFile); err == nil {
kubeConfig, err = clientcmd.BuildConfigFromFlags("", kubeConfigFile)
kubeConfig, err = clientcmd.BuildConfigFromFlags("", KubeConfigFile)
if err != nil {
return nil, err
}
} else { } else {
kubeConfig, err = rest.InClusterConfig() kubeConfig, err = rest.InClusterConfig()
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
kubeConfig.QPS = 1e6 kubeConfig.QPS = 1e6
kubeConfig.Burst = 1e6 kubeConfig.Burst = 1e6
return kubeConfig, nil return kubeConfig, nil
} }

188
pkg/client/ldap/channel.go Normal file
View File

@@ -0,0 +1,188 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ldap
import (
"errors"
"log"
"sync"
"github.com/go-ldap/ldap"
)
// channelPool implements the Pool interface based on buffered channels.
type channelPool struct {
// storage for our net.Conn connections
mu sync.Mutex
conns chan ldap.Client
name string
aliveChecks bool
// net.Conn generator
factory PoolFactory
closeAt []uint16
}
// PoolFactory is a function to create new connections.
type PoolFactory func(string) (ldap.Client, error)
// NewChannelPool returns a new pool based on buffered channels with an initial
// capacity and maximum capacity. Factory is used when initial capacity is
// greater than zero to fill the pool. A zero initialCap doesn't fill the Pool
// until a new Get() is called. During a Get(), If there is no new connection
// available in the pool, a new connection will be created via the Factory()
// method.
//
// closeAt will automagically mark the connection as unusable if the return code
// of the call is one of those passed, most likely you want to set this to something
// like
// []uint8{ldap.LDAPResultTimeLimitExceeded, ldap.ErrorNetwork}
func NewChannelPool(initialCap, maxCap int, name string, factory PoolFactory, closeAt []uint16) (Pool, error) {
if initialCap < 0 || maxCap <= 0 || initialCap > maxCap {
return nil, errors.New("invalid capacity settings")
}
c := &channelPool{
conns: make(chan ldap.Client, maxCap),
name: name,
factory: factory,
closeAt: closeAt,
aliveChecks: true,
}
// create initial connections, if something goes wrong,
// just close the pool error out.
for i := 0; i < initialCap; i++ {
conn, err := factory(c.name)
if err != nil {
c.Close()
return nil, errors.New("factory is not able to fill the pool: " + err.Error())
}
c.conns <- conn
}
return c, nil
}
func (c *channelPool) AliveChecks(on bool) {
c.mu.Lock()
c.aliveChecks = on
c.mu.Unlock()
}
func (c *channelPool) getConns() chan ldap.Client {
c.mu.Lock()
conns := c.conns
c.mu.Unlock()
return conns
}
// Get implements the Pool interfaces Get() method. If there is no new
// connection available in the pool, a new connection will be created via the
// Factory() method.
func (c *channelPool) Get() (*PoolConn, error) {
conns := c.getConns()
if conns == nil {
return nil, ErrClosed
}
// wrap our connections with our ldap.Client implementation (wrapConn
// method) that puts the connection back to the pool if it's closed.
select {
case conn := <-conns:
if conn == nil {
return nil, ErrClosed
}
if !c.aliveChecks || isAlive(conn) {
return c.wrapConn(conn, c.closeAt), nil
}
conn.Close()
return c.NewConn()
default:
return c.NewConn()
}
}
func isAlive(conn ldap.Client) bool {
_, err := conn.Search(&ldap.SearchRequest{BaseDN: "", Scope: ldap.ScopeBaseObject, Filter: "(&)", Attributes: []string{"1.1"}})
return err == nil
}
func (c *channelPool) NewConn() (*PoolConn, error) {
conn, err := c.factory(c.name)
if err != nil {
return nil, err
}
return c.wrapConn(conn, c.closeAt), nil
}
// put puts the connection back to the pool. If the pool is full or closed,
// conn is simply closed. A nil conn will be rejected.
func (c *channelPool) put(conn ldap.Client) {
if conn == nil {
log.Printf("connection is nil. rejecting")
return
}
c.mu.Lock()
defer c.mu.Unlock()
if c.conns == nil {
// pool is closed, close passed connection
conn.Close()
return
}
// put the resource back into the pool. If the pool is full, this will
// block and the default case will be executed.
select {
case c.conns <- conn:
return
default:
// pool is full, close passed connection
conn.Close()
return
}
}
func (c *channelPool) Close() {
c.mu.Lock()
conns := c.conns
c.conns = nil
c.factory = nil
c.mu.Unlock()
if conns == nil {
return
}
close(conns)
for conn := range conns {
conn.Close()
}
return
}
func (c *channelPool) Len() int { return len(c.getConns()) }
func (c *channelPool) wrapConn(conn ldap.Client, closeAt []uint16) *PoolConn {
p := &PoolConn{c: c, closeAt: closeAt}
p.Conn = conn
return p
}

113
pkg/client/ldap/conn.go Normal file
View File

@@ -0,0 +1,113 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ldap
import (
"crypto/tls"
"log"
"time"
"github.com/go-ldap/ldap"
)
// PoolConn implements Client to override the Close() method
type PoolConn struct {
Conn ldap.Client
c *channelPool
unusable bool
closeAt []uint16
}
func (p *PoolConn) Start() {
p.Conn.Start()
}
func (p *PoolConn) StartTLS(config *tls.Config) error {
// FIXME - check if already TLS and then ignore?
return p.Conn.StartTLS(config)
}
// Close() puts the given connects back to the pool instead of closing it.
func (p *PoolConn) Close() {
if p.unusable {
log.Printf("Closing unusable connection")
if p.Conn != nil {
p.Conn.Close()
}
return
}
p.c.put(p.Conn)
}
func (p *PoolConn) SimpleBind(simpleBindRequest *ldap.SimpleBindRequest) (*ldap.SimpleBindResult, error) {
return p.Conn.SimpleBind(simpleBindRequest)
}
func (p *PoolConn) Bind(username, password string) error {
return p.Conn.Bind(username, password)
}
func (p *PoolConn) ModifyDN(modifyDNRequest *ldap.ModifyDNRequest) error {
return p.Conn.ModifyDN(modifyDNRequest)
}
// MarkUnusable() marks the connection not usable any more, to let the pool close it
// instead of returning it to pool.
func (p *PoolConn) MarkUnusable() {
p.unusable = true
}
func (p *PoolConn) autoClose(err error) {
for _, code := range p.closeAt {
if ldap.IsErrorWithCode(err, code) {
p.MarkUnusable()
return
}
}
}
func (p *PoolConn) SetTimeout(t time.Duration) {
p.Conn.SetTimeout(t)
}
func (p *PoolConn) Add(addRequest *ldap.AddRequest) error {
return p.Conn.Add(addRequest)
}
func (p *PoolConn) Del(delRequest *ldap.DelRequest) error {
return p.Conn.Del(delRequest)
}
func (p *PoolConn) Modify(modifyRequest *ldap.ModifyRequest) error {
return p.Conn.Modify(modifyRequest)
}
func (p *PoolConn) Compare(dn, attribute, value string) (bool, error) {
return p.Conn.Compare(dn, attribute, value)
}
func (p *PoolConn) PasswordModify(passwordModifyRequest *ldap.PasswordModifyRequest) (*ldap.PasswordModifyResult, error) {
return p.Conn.PasswordModify(passwordModifyRequest)
}
func (p *PoolConn) Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) {
return p.Conn.Search(searchRequest)
}
func (p *PoolConn) SearchWithPaging(searchRequest *ldap.SearchRequest, pagingSize uint32) (*ldap.SearchResult, error) {
return p.Conn.SearchWithPaging(searchRequest, pagingSize)
}

43
pkg/client/ldap/pool.go Normal file
View File

@@ -0,0 +1,43 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ldap
import (
"errors"
)
var (
// ErrClosed is the error resulting if the pool is closed via pool.Close().
ErrClosed = errors.New("pool is closed")
)
// Pool interface describes a pool implementation. A pool should have maximum
// capacity. An ideal pool is threadsafe and easy to use.
type Pool interface {
// Get returns a new connection from the pool. Closing the connections puts
// it back to the Pool. Closing it when the pool is destroyed or full will
// be counted as an error.
Get() (*PoolConn, error)
// Close closes the pool and all its connections. After Close() the pool is
// no longer usable.
Close()
// Len returns the current number of connections of the pool.
Len() int
}

65
pkg/client/ldapclient.go Normal file
View File

@@ -0,0 +1,65 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
"flag"
"fmt"
"github.com/go-ldap/ldap"
ldapPool "kubesphere.io/kubesphere/pkg/client/ldap"
"os"
"sync"
)
var (
once sync.Once
pool ldapPool.Pool
ldapHost string
ManagerDN string
ManagerPassword string
UserSearchBase string
GroupSearchBase string
)
func init() {
flag.StringVar(&ldapHost, "ldap-server", "localhost:389", "ldap server host")
flag.StringVar(&ManagerDN, "ldap-manager-dn", "cn=admin,dc=example,dc=org", "ldap manager dn")
flag.StringVar(&ManagerPassword, "ldap-manager-password", "admin", "ldap manager password")
flag.StringVar(&UserSearchBase, "ldap-user-search-base", "ou=Users,dc=example,dc=org", "ldap user search base")
flag.StringVar(&GroupSearchBase, "ldap-group-search-base", "ou=Groups,dc=example,dc=org", "ldap group search base")
}
func LdapClient() ldapPool.Pool {
once.Do(func() {
var err error
pool, err = ldapPool.NewChannelPool(8, 96, "kubesphere", func(s string) (ldap.Client, error) {
conn, err := ldap.Dial("tcp", ldapHost)
if err != nil {
return nil, err
}
return conn, nil
}, []uint16{ldap.LDAPResultTimeLimitExceeded, ldap.ErrorNetwork})
if err != nil {
fmt.Fprint(os.Stderr, err.Error())
panic(err)
}
})
return pool
}

View File

@@ -1,18 +1,24 @@
/* /*
Copyright 2018 The KubeSphere Authors.
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package client package client
import ( import (
"flag"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
@@ -20,31 +26,23 @@ import (
"strings" "strings"
"time" "time"
"os"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/golang/glog" "github.com/golang/glog"
) )
const ( const (
DefaultScheme = "http"
DefaultPrometheusPort = "9090"
PrometheusApiPath = "/api/v1/"
DefaultQueryStep = "10m" DefaultQueryStep = "10m"
DefaultQueryTimeout = "10s" DefaultQueryTimeout = "10s"
RangeQueryType = "query_range?" RangeQueryType = "query_range?"
DefaultQueryType = "query?" DefaultQueryType = "query?"
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
) )
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc" var (
var PrometheusEndpointUrl string prometheusAPIEndpoint string
)
func init() { func init() {
if env := os.Getenv(PrometheusAPIServerEnv); env != "" { flag.StringVar(&prometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
PrometheusAPIServer = env
}
PrometheusEndpointUrl = DefaultScheme + "://" + PrometheusAPIServer + ":" + DefaultPrometheusPort + PrometheusApiPath
} }
type MonitoringRequestParams struct { type MonitoringRequestParams struct {
@@ -72,11 +70,10 @@ type MonitoringRequestParams struct {
WorkloadKind string WorkloadKind string
} }
var client = &http.Client{}
func SendMonitoringRequest(queryType string, params string) string { func SendMonitoringRequest(queryType string, params string) string {
epurl := PrometheusEndpointUrl + queryType + params epurl := prometheusAPIEndpoint + queryType + params
response, err := client.Get(epurl)
response, err := http.DefaultClient.Get(epurl)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
} else { } else {
@@ -116,11 +113,11 @@ func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestPa
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ") metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ") workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
nodeId := strings.Trim(request.PathParameter("node_id"), " ") nodeId := strings.Trim(request.PathParameter("node"), " ")
wsName := strings.Trim(request.PathParameter("workspace_name"), " ") wsName := strings.Trim(request.PathParameter("workspace"), " ")
nsName := strings.Trim(request.PathParameter("ns_name"), " ") nsName := strings.Trim(request.PathParameter("namespace"), " ")
podName := strings.Trim(request.PathParameter("pod_name"), " ") podName := strings.Trim(request.PathParameter("pod"), " ")
containerName := strings.Trim(request.PathParameter("container_name"), " ") containerName := strings.Trim(request.PathParameter("container"), " ")
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ") workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
var requestParams = MonitoringRequestParams{ var requestParams = MonitoringRequestParams{

56
pkg/client/redis.go Normal file
View File

@@ -0,0 +1,56 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
"flag"
"log"
"sync"
"github.com/go-redis/redis"
)
var (
redisHost string
redisPassword string
redisDB int
redisClientOnce sync.Once
redisClient *redis.Client
)
func init() {
flag.StringVar(&redisHost, "redis-server", "localhost:6379", "redis server host")
flag.StringVar(&redisPassword, "redis-password", "", "redis password")
flag.IntVar(&redisDB, "redis-db", 0, "redis db")
}
func RedisClient() *redis.Client {
redisClientOnce.Do(func() {
redisClient = redis.NewClient(&redis.Options{
Addr: redisHost,
Password: redisPassword,
DB: redisDB,
})
if err := redisClient.Ping().Err(); err != nil {
log.Fatalln(err)
}
})
return redisClient
}

View File

@@ -1,6 +1,21 @@
package constants /*
import "os" Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package constants
const ( const (
APIVersion = "v1alpha1" APIVersion = "v1alpha1"
@@ -24,32 +39,18 @@ const (
DevopsOwner = "owner" DevopsOwner = "owner"
DevopsReporter = "reporter" DevopsReporter = "reporter"
DevopsAPIServerEnv = "DEVOPS_API_SERVER" envDevopsAPIServer = "DEVOPS_API_SERVER"
AccountAPIServerEnv = "ACCOUNT_API_SERVER" envAccountAPIServer = "ACCOUNT_API_SERVER"
DevopsProxyTokenEnv = "DEVOPS_PROXY_TOKEN" envDevopsProxyToken = "DEVOPS_PROXY_TOKEN"
OpenPitrixProxyTokenEnv = "OPENPITRIX_PROXY_TOKEN" envOpenPitrixProxyToken = "OPENPITRIX_PROXY_TOKEN"
UserNameHeader = "X-Token-Username"
) )
var ( var (
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer} WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
SystemWorkspace = "system-workspace"
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc" DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
AccountAPIServer = "ks-account.kubesphere-system.svc" AccountAPIServer = "ks-account.kubesphere-system.svc"
DevopsProxyToken = ""
OpenPitrixProxyToken = ""
SystemNamespaces = []string{KubeSystemNamespace, OpenPitrixNamespace, KubeSystemNamespace} SystemNamespaces = []string{KubeSystemNamespace, OpenPitrixNamespace, KubeSystemNamespace}
) )
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,17 +0,0 @@
package errors
type Code int
const (
OK Code = iota
Canceled
Unknown
InvalidArgument
Internal // 5
Unavailable
AlreadyExists
NotFound
NotImplement
VerifyFailed
Conflict
)

View File

@@ -1,16 +0,0 @@
// Code generated by "stringer -type=Code"; DO NOT EDIT.
package errors
import "strconv"
const _Code_name = "OKCanceledUnknownInvalidArgumentInternalUnavailableAlreadyExistsWTFNotFoundNotImplementVerifyFailed"
var _Code_index = [...]uint8{0, 2, 10, 17, 32, 40, 51, 64, 67, 75, 87, 99}
func (i Code) String() string {
if i < 0 || i >= Code(len(_Code_index)-1) {
return "Code(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Code_name[_Code_index[i]:_Code_index[i+1]]
}

View File

@@ -1,7 +0,0 @@
package errors
import "testing"
func TestCode_String(t *testing.T) {
t.Log(Code(1).String())
}

View File

@@ -1,105 +1,42 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package errors package errors
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"net"
"net/http"
"reflect"
k8sError "k8s.io/apimachinery/pkg/api/errors"
"github.com/emicklei/go-restful"
"github.com/go-sql-driver/mysql"
"github.com/golang/glog"
) )
type Error struct { type Error struct {
Code Code `json:"code"`
Message string `json:"message"` Message string `json:"message"`
} }
var None = New(OK, "success") var None = Error{Message: "success"}
func (e *Error) Error() string { func (e *Error) Error() string {
return fmt.Sprintf("error: %v,message: %v", e.Code.String(), e.Message) return e.Message
}
func (e *Error) HttpStatusCode() int {
switch e.Code {
case OK:
return http.StatusOK
case InvalidArgument:
return http.StatusBadRequest
case AlreadyExists:
return http.StatusConflict
case Unavailable:
return http.StatusServiceUnavailable
case NotImplement:
return http.StatusNotImplemented
case VerifyFailed:
return http.StatusBadRequest
case Conflict:
return http.StatusConflict
case Internal:
fallthrough
case Unknown:
fallthrough
default:
return http.StatusInternalServerError
}
} }
func New(code Code, message string) error { func Wrap(err error) Error {
if message == "" { return Error{Message: err.Error()}
message = code.String()
}
return &Error{Code: code, Message: message}
} }
func HandlerError(err error, resp *restful.Response) bool { func Parse(data []byte) error {
if err == nil {
return false
}
glog.Errorln(reflect.TypeOf(err), err)
resp.WriteHeaderAndEntity(wrapper(err))
return true
}
func wrapper(err error) (int, interface{}) {
switch err.(type) {
case *Error:
case *json.UnmarshalTypeError:
err = New(InvalidArgument, err.Error())
case *mysql.MySQLError:
err = wrapperMysqlError(err.(*mysql.MySQLError))
case *net.OpError:
err = New(Internal, err.Error())
default:
if k8sError.IsNotFound(err) {
err = New(NotFound, err.Error())
} else {
err = New(Unknown, err.Error())
}
}
return err.(*Error).HttpStatusCode(), err
}
func wrapperMysqlError(sqlError *mysql.MySQLError) error {
switch sqlError.Number {
case 1062:
return New(AlreadyExists, sqlError.Message)
default:
return New(Unknown, sqlError.Message)
}
}
func Wrap(data []byte) error {
var j map[string]string var j map[string]string
err := json.Unmarshal(data, &j) err := json.Unmarshal(data, &j)
if err != nil { if err != nil {

View File

@@ -18,47 +18,27 @@
package components package components
import ( import (
"time" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/models"
lister "k8s.io/client-go/listers/core/v1" "kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"github.com/golang/glog" "github.com/golang/glog"
coreV1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
) )
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"`
}
var (
componentStatusLister lister.ComponentStatusLister
serviceLister lister.ServiceLister
podLister lister.PodLister
nodeLister lister.NodeLister
)
func init() {
componentStatusLister = informers.SharedInformerFactory().Core().V1().ComponentStatuses().Lister()
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
podLister = informers.SharedInformerFactory().Core().V1().Pods().Lister()
nodeLister = informers.SharedInformerFactory().Core().V1().Nodes().Lister()
}
func GetComponentStatus(name string) (interface{}, error) { func GetComponentStatus(name string) (interface{}, error) {
var service *coreV1.Service var service *corev1.Service
var err error var err error
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
for _, ns := range constants.SystemNamespaces { for _, ns := range constants.SystemNamespaces {
service, err = serviceLister.Services(ns).Get(name) service, err = serviceLister.Services(ns).Get(name)
if err == nil { if err == nil {
@@ -70,13 +50,15 @@ func GetComponentStatus(name string) (interface{}, error) {
return nil, err return nil, err
} }
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
pods, err := podLister.Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector)) pods, err := podLister.Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
if err != nil { if err != nil {
return nil, err return nil, err
} }
component := Component{ component := models.Component{
Name: service.Name, Name: service.Name,
Namespace: service.Namespace, Namespace: service.Namespace,
SelfLink: service.SelfLink, SelfLink: service.SelfLink,
@@ -102,11 +84,11 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
status := make(map[string]interface{}) status := make(map[string]interface{})
componentStatuses, err := componentStatusLister.List(labels.Everything()) componentStatuses, err := client.K8sClient().CoreV1().ComponentStatuses().List(meta_v1.ListOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, cs := range componentStatuses { for _, cs := range componentStatuses.Items {
status[cs.Name] = cs.Conditions[0] status[cs.Name] = cs.Conditions[0]
} }
@@ -119,6 +101,8 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
for k, v := range systemComponentStatus { for k, v := range systemComponentStatus {
status[k] = v status[k] = v
} }
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
// get node status // get node status
nodes, err := nodeLister.List(labels.Everything()) nodes, err := nodeLister.List(labels.Everything())
if err != nil { if err != nil {
@@ -132,7 +116,7 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
for _, nodes := range nodes { for _, nodes := range nodes {
totalNodes++ totalNodes++
for _, condition := range nodes.Status.Conditions { for _, condition := range nodes.Status.Conditions {
if condition.Type == coreV1.NodeReady && condition.Status == coreV1.ConditionTrue { if condition.Type == corev1.NodeReady && condition.Status == corev1.ConditionTrue {
healthyNodes++ healthyNodes++
} }
} }
@@ -147,11 +131,12 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
} }
func GetAllComponentsStatus() (map[string]interface{}, error) { func GetAllComponentsStatus() (map[string]interface{}, error) {
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
status := make(map[string]interface{}) status := make(map[string]interface{})
var err error var err error
for _, ns := range constants.SystemNamespaces { for _, ns := range constants.SystemNamespaces {
nsStatus := make(map[string]interface{}) nsStatus := make(map[string]interface{})
@@ -164,7 +149,7 @@ func GetAllComponentsStatus() (map[string]interface{}, error) {
} }
for _, service := range services { for _, service := range services {
component := Component{ component := models.Component{
Name: service.Name, Name: service.Name,
Namespace: service.Namespace, Namespace: service.Namespace,
SelfLink: service.SelfLink, SelfLink: service.SelfLink,

822
pkg/models/iam/am.go Normal file
View File

@@ -0,0 +1,822 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"kubesphere.io/kubesphere/pkg/informers"
"log"
"net/http"
"regexp"
"strings"
"github.com/go-ldap/ldap"
corev1 "k8s.io/api/core/v1"
"k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/kubernetes/pkg/util/slice"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
)
func GetNamespaces(username string) ([]*corev1.Namespace, error) {
roles, err := GetRoles(username, "")
if err != nil {
return nil, err
}
namespaces := make([]*corev1.Namespace, 0)
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
for _, role := range roles {
namespace, err := namespaceLister.Get(role.Name)
if err != nil {
return nil, err
}
namespaces = append(namespaces, namespace)
}
return namespaces, nil
}
func GetNamespacesByWorkspace(workspace string) ([]*corev1.Namespace, error) {
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
return namespaceLister.List(labels.SelectorFromSet(labels.Set{"kubesphere.io/workspace": workspace}))
}
func GetDevopsRole(projectId string, username string) (string, error) {
//Hard fix
if username == "admin" {
return "owner", nil
}
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/api/v1alpha/projects/%s/members", constants.DevopsAPIServer, projectId), nil)
if err != nil {
return "", err
}
req.Header.Set(constants.UserNameHeader, username)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
if resp.StatusCode > 200 {
return "", errors.New(string(data))
}
var result []map[string]string
err = json.Unmarshal(data, &result)
if err != nil {
return "", err
}
for _, item := range result {
if item["username"] == username {
return item["role"], nil
}
}
return "", nil
}
func GetNamespace(namespaceName string) (*corev1.Namespace, error) {
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
return namespaceLister.Get(namespaceName)
}
func GetRoles(username string, namespace string) ([]*v1.Role, error) {
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
roleLister := informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
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) {
log.Println(err)
break
} else {
return nil, err
}
} else {
if subject.Kind == v1.UserKind && subject.Name == username {
rule, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name)
if err == nil {
roles = append(roles, rule)
break
} else if apierrors.IsNotFound(err) {
log.Println(err)
break
} else {
return nil, err
}
}
}
}
}
}
return roles, nil
}
func GetClusterRoles(username string) ([]*v1.ClusterRole, error) {
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil {
return nil, err
}
roles := make([]*v1.ClusterRole, 0)
for _, rb := range clusterRoleBindings {
if rb.RoleRef.Kind == ClusterRoleKind {
for _, subject := range rb.Subjects {
if subject.Kind == v1.UserKind && subject.Name == username {
role, err := clusterRoleLister.Get(rb.RoleRef.Name)
role = role.DeepCopy()
if err == nil {
if role.Annotations == nil {
role.Annotations = make(map[string]string, 0)
}
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = rb.Name
if rb.Annotations != nil &&
rb.Annotations["rbac.authorization.k8s.io/clusterrole"] == rb.RoleRef.Name {
role.Annotations["rbac.authorization.k8s.io/clusterrole"] = "true"
}
roles = append(roles, role)
break
} else if apierrors.IsNotFound(err) {
log.Println(err)
break
} else {
return nil, err
}
}
}
}
}
return roles, nil
}
func GetRoleBindings(namespace string, roleName string) ([]*v1.RoleBinding, error) {
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
roleBindingList, err := roleBindingLister.List(labels.Everything())
if err != nil {
return nil, err
}
items := make([]*v1.RoleBinding, 0)
for _, roleBinding := range roleBindingList {
if roleName == "" {
items = append(items, roleBinding)
} else if roleBinding.RoleRef.Name == roleName {
items = append(items, roleBinding)
}
}
return items, nil
}
func GetClusterRoleBindings(clusterRoleName string) ([]*v1.ClusterRoleBinding, error) {
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
roleBindingList, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil {
return nil, err
}
items := make([]*v1.ClusterRoleBinding, 0)
for _, roleBinding := range roleBindingList {
if roleBinding.RoleRef.Name == clusterRoleName {
items = append(items, roleBinding)
}
}
return items, nil
}
func ClusterRoleUsers(clusterRoleName string) ([]*models.User, error) {
roleBindings, err := GetClusterRoleBindings(clusterRoleName)
if err != nil {
return nil, err
}
conn, err := NewConnection()
if err != nil {
return nil, err
}
defer conn.Close()
names := make([]string, 0)
users := make([]*models.User, 0)
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && !strings.HasPrefix(subject.Name, "system") &&
!slice.ContainsString(names, subject.Name, nil) {
names = append(names, subject.Name)
user, err := UserDetail(subject.Name, conn)
if ldap.IsErrorWithCode(err, 32) {
continue
}
if err != nil {
return nil, err
}
users = append(users, user)
}
}
}
return users, nil
}
func RoleUsers(namespace string, roleName string) ([]*models.User, error) {
roleBindings, err := GetRoleBindings(namespace, roleName)
if err != nil {
return nil, err
}
conn, err := NewConnection()
if err != nil {
return nil, err
}
defer conn.Close()
names := make([]string, 0)
users := make([]*models.User, 0)
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind &&
!strings.HasPrefix(subject.Name, "system") &&
!slice.ContainsString(names, subject.Name, nil) {
names = append(names, subject.Name)
user, err := UserDetail(subject.Name, conn)
if ldap.IsErrorWithCode(err, 32) {
continue
}
if err != nil {
return nil, err
}
users = append(users, user)
}
}
}
return users, nil
}
func NamespaceUsers(namespaceName string) ([]*models.User, error) {
roleBindings, err := GetRoleBindings(namespaceName, "")
if err != nil {
return nil, err
}
conn, err := NewConnection()
if err != nil {
return nil, err
}
defer conn.Close()
names := make([]string, 0)
users := make([]*models.User, 0)
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind &&
!slice.ContainsString(names, subject.Name, nil) &&
!strings.HasPrefix(subject.Name, "system") {
if roleBinding.Name == "viewer" {
continue
}
if roleBinding.Name == "admin" {
continue
}
names = append(names, subject.Name)
user, err := UserDetail(subject.Name, conn)
if ldap.IsErrorWithCode(err, 32) {
continue
}
if err != nil {
return nil, err
}
user.Role = roleBinding.RoleRef.Name
user.RoleBinding = roleBinding.Name
users = append(users, user)
}
}
}
return users, nil
}
func GetWorkspaceRoles(clusterRoles []*v1.ClusterRole) map[string]string {
workspaceRoles := make(map[string]string, 0)
for _, v := range clusterRoles {
if groups := regexp.MustCompile(fmt.Sprintf(`^system:(\S+):(%s)$`, strings.Join(constants.WorkSpaceRoles, "|"))).FindStringSubmatch(v.Name); len(groups) == 3 {
workspaceRoles[groups[1]] = groups[2]
}
}
return workspaceRoles
}
func GetWorkspaceRole(clusterRoles []*v1.ClusterRole, workspace string) string {
for _, v := range clusterRoles {
if groups := regexp.MustCompile(fmt.Sprintf(`^system:(\S+):(%s)$`, strings.Join(constants.WorkSpaceRoles, "|"))).FindStringSubmatch(v.Name); len(groups) == 3 {
if groups[1] == workspace {
return groups[2]
}
}
}
return ""
}
func GetWorkspaceSimpleRules(clusterRoles []*v1.ClusterRole, workspace string) map[string][]models.SimpleRule {
workspaceRules := make(map[string][]models.SimpleRule, 0)
clusterSimpleRules := make([]models.SimpleRule, 0)
clusterRules := make([]v1.PolicyRule, 0)
for _, clusterRole := range clusterRoles {
clusterRules = append(clusterRules, clusterRole.Rules...)
}
for i := 0; i < len(policy.WorkspaceRoleRuleMapping); i++ {
rule := models.SimpleRule{Name: policy.WorkspaceRoleRuleMapping[i].Name}
rule.Actions = make([]string, 0)
for j := 0; j < (len(policy.WorkspaceRoleRuleMapping[i].Actions)); j++ {
if RulesMatchesAction(clusterRules, policy.WorkspaceRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, policy.WorkspaceRoleRuleMapping[i].Actions[j].Name)
}
}
if len(rule.Actions) > 0 {
clusterSimpleRules = append(clusterSimpleRules, rule)
}
}
if len(clusterRules) > 0 {
workspaceRules["*"] = clusterSimpleRules
}
for _, v := range clusterRoles {
if groups := regexp.MustCompile(fmt.Sprintf(`^system:(\S+):(%s)$`, strings.Join(constants.WorkSpaceRoles, "|"))).FindStringSubmatch(v.Name); len(groups) == 3 {
if workspace != "" && groups[1] != workspace {
continue
}
policyRules := make([]v1.PolicyRule, 0)
for _, rule := range v.Rules {
rule.ResourceNames = nil
policyRules = append(policyRules, rule)
}
rules := make([]models.SimpleRule, 0)
for i := 0; i < len(policy.WorkspaceRoleRuleMapping); i++ {
rule := models.SimpleRule{Name: policy.WorkspaceRoleRuleMapping[i].Name}
rule.Actions = make([]string, 0)
for j := 0; j < (len(policy.WorkspaceRoleRuleMapping[i].Actions)); j++ {
action := policy.WorkspaceRoleRuleMapping[i].Actions[j]
if RulesMatchesAction(policyRules, action) {
rule.Actions = append(rule.Actions, action.Name)
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
workspaceRules[groups[1]] = merge(rules, clusterSimpleRules)
}
}
return workspaceRules
}
func merge(clusterRules, rules []models.SimpleRule) []models.SimpleRule {
for _, clusterRule := range clusterRules {
exist := false
for i := 0; i < len(rules); i++ {
if rules[i].Name == clusterRule.Name {
exist = true
for _, action := range clusterRule.Actions {
if !slice.ContainsString(rules[i].Actions, action, nil) {
rules[i].Actions = append(rules[i].Actions, action)
}
}
}
}
if !exist {
rules = append(rules, clusterRule)
}
}
return rules
}
// Convert cluster roles to rules
func GetClusterRoleSimpleRules(clusterRoles []*v1.ClusterRole) ([]models.SimpleRule, error) {
clusterRules := make([]v1.PolicyRule, 0)
for _, v := range clusterRoles {
clusterRules = append(clusterRules, v.Rules...)
}
rules := make([]models.SimpleRule, 0)
for i := 0; i < len(policy.ClusterRoleRuleMapping); i++ {
validActions := make([]string, 0)
for j := 0; j < (len(policy.ClusterRoleRuleMapping[i].Actions)); j++ {
if RulesMatchesAction(clusterRules, policy.ClusterRoleRuleMapping[i].Actions[j]) {
validActions = append(validActions, policy.ClusterRoleRuleMapping[i].Actions[j].Name)
}
}
if len(validActions) > 0 {
rules = append(rules, models.SimpleRule{Name: policy.ClusterRoleRuleMapping[i].Name, Actions: validActions})
}
}
return rules, nil
}
// Convert roles to rules
func GetRoleSimpleRules(roles []*v1.Role, namespace string) (map[string][]models.SimpleRule, error) {
rulesMapping := make(map[string][]models.SimpleRule, 0)
policyRulesMapping := make(map[string][]v1.PolicyRule, 0)
for _, v := range roles {
if namespace != "" && v.Namespace != namespace {
continue
}
policyRules := policyRulesMapping[v.Namespace]
if policyRules == nil {
policyRules = make([]v1.PolicyRule, 0)
}
policyRules = append(policyRules, v.Rules...)
policyRulesMapping[v.Namespace] = policyRules
}
for namespace, policyRules := range policyRulesMapping {
rules := make([]models.SimpleRule, 0)
for i := 0; i < len(policy.RoleRuleMapping); i++ {
rule := models.SimpleRule{Name: policy.RoleRuleMapping[i].Name}
rule.Actions = make([]string, 0)
for j := 0; j < len(policy.RoleRuleMapping[i].Actions); j++ {
if RulesMatchesAction(policyRules, policy.RoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, policy.RoleRuleMapping[i].Actions[j].Name)
}
}
if len(rule.Actions) > 0 {
rules = append(rules, rule)
}
}
rulesMapping[namespace] = rules
}
return rulesMapping, nil
}
func CreateClusterRoleBinding(username string, clusterRoleName string) error {
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
_, err := clusterRoleLister.Get(clusterRoleName)
if err != nil {
return err
}
clusterRoles, err := GetClusterRoles(username)
if err != nil {
return err
}
for _, clusterRole := range clusterRoles {
if clusterRole.Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
if clusterRole.Name == clusterRoleName {
return nil
}
clusterRoleBindingName := clusterRole.Annotations["rbac.authorization.k8s.io/clusterrolebinding"]
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleBinding, err := clusterRoleBindingLister.Get(clusterRoleBindingName)
if err != nil {
return err
}
for i, v := range clusterRoleBinding.Subjects {
if v.Kind == v1.UserKind && v.Name == username {
clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects[:i], clusterRoleBinding.Subjects[i+1:]...)
break
}
}
_, err = client.K8sClient().RbacV1().ClusterRoleBindings().Update(clusterRoleBinding)
if err != nil {
return err
}
break
}
}
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil {
return err
}
var clusterRoleBinding *v1.ClusterRoleBinding
for _, roleBinding := range clusterRoleBindings {
if roleBinding.Annotations != nil && roleBinding.Annotations["rbac.authorization.k8s.io/clusterrole"] == clusterRoleName &&
roleBinding.RoleRef.Name == clusterRoleName {
clusterRoleBinding = roleBinding
break
}
}
if clusterRoleBinding != nil {
clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects, v1.Subject{Kind: v1.UserKind, Name: username})
_, err := client.K8sClient().RbacV1().ClusterRoleBindings().Update(clusterRoleBinding)
if err != nil {
return err
}
} else {
clusterRoleBinding = new(v1.ClusterRoleBinding)
clusterRoleBinding.Annotations = map[string]string{"rbac.authorization.k8s.io/clusterrole": clusterRoleName}
clusterRoleBinding.Name = clusterRoleName
clusterRoleBinding.RoleRef = v1.RoleRef{Name: clusterRoleName, Kind: ClusterRoleKind}
clusterRoleBinding.Subjects = []v1.Subject{{Kind: v1.UserKind, Name: username}}
_, err = client.K8sClient().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
if err != nil {
return err
}
}
return nil
}
func GetRole(namespace string, roleName string) (*v1.Role, error) {
return informers.SharedInformerFactory().Rbac().V1().Roles().Lister().Roles(namespace).Get(roleName)
}
func GetClusterRole(clusterRoleName string) (*v1.ClusterRole, error) {
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
return clusterRoleLister.Get(clusterRoleName)
}
func RulesMatchesAction(rules []v1.PolicyRule, action models.Action) bool {
for _, required := range action.Rules {
if !rulesMatchesRequired(rules, required) {
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
}

54
pkg/models/iam/counter.go Normal file
View File

@@ -0,0 +1,54 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam
import "sync"
type Counter struct {
value int
m *sync.Mutex
}
func NewCounter(value int) Counter {
c := Counter{}
c.m = &sync.Mutex{}
c.Set(value)
return c
}
func (c *Counter) Set(value int) {
c.m.Lock()
c.value = value
c.m.Unlock()
}
func (c *Counter) Add(value int) {
c.m.Lock()
c.value += value
c.m.Unlock()
}
func (c *Counter) Sub(value int) {
c.m.Lock()
c.value -= value
c.m.Unlock()
}
func (c *Counter) Get() int {
return c.value
}

View File

@@ -1,3 +1,20 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam package iam
import ( import (
@@ -7,38 +24,22 @@ import (
"net/http" "net/http"
"strings" "strings"
v12 "k8s.io/client-go/listers/rbac/v1"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"github.com/golang/glog"
"k8s.io/api/rbac/v1" "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/kubernetes/pkg/util/slice" "k8s.io/kubernetes/pkg/util/slice"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
ksErr "kubesphere.io/kubesphere/pkg/errors" kserr "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
) )
const ClusterRoleKind = "ClusterRole" const ClusterRoleKind = "ClusterRole"
var (
clusterRoleBindingLister v12.ClusterRoleBindingLister
clusterRoleLister v12.ClusterRoleLister
roleBindingLister v12.RoleBindingLister
roleLister v12.RoleLister
)
func init() {
clusterRoleBindingLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
roleBindingLister = informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
roleLister = informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
}
// Get user list based on workspace role // Get user list based on workspace role
func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) { func WorkspaceRoleUsers(workspace string, roleName string) ([]models.User, error) {
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName)) workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName))
@@ -67,11 +68,11 @@ func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
return users, nil return users, nil
} }
func GetUsers(names []string) ([]User, error) { func GetUsers(names []string) ([]models.User, error) {
var users []User var users []models.User
if names == nil || len(names) == 0 { if names == nil || len(names) == 0 {
return make([]User, 0), nil return make([]models.User, 0), nil
} }
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ","))) result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
@@ -88,7 +89,7 @@ func GetUsers(names []string) ([]User, error) {
} }
if result.StatusCode > 200 { if result.StatusCode > 200 {
return nil, ksErr.Wrap(data) return nil, kserr.Parse(data)
} }
err = json.Unmarshal(data, &users) err = json.Unmarshal(data, &users)
@@ -100,7 +101,7 @@ func GetUsers(names []string) ([]User, error) {
return users, nil return users, nil
} }
func GetUser(name string) (*User, error) { func GetUser(name string) (*models.User, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name)) result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
@@ -116,10 +117,10 @@ func GetUser(name string) (*User, error) {
} }
if result.StatusCode > 200 { if result.StatusCode > 200 {
return nil, ksErr.Wrap(data) return nil, kserr.Parse(data)
} }
var user User var user models.User
err = json.Unmarshal(data, &user) err = json.Unmarshal(data, &user)
@@ -187,16 +188,8 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
return false, namespaces, nil return false, namespaces, nil
} }
func GetRole(namespace string, name string) (*v1.Role, error) {
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) { func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) {
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole)) clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
if err != nil { if err != nil {
@@ -213,108 +206,6 @@ func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error)
return users, nil return users, nil
} }
func GetClusterRole(name string) (*v1.ClusterRole, error) {
role, err := clusterRoleLister.Get(name)
if err != nil {
return nil, err
}
return role.DeepCopy(), nil
}
func GetRoles(namespace string, username string) ([]v1.Role, error) {
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) {
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 RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool { func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
for _, rule := range rules { for _, rule := range rules {
if ruleMatchesRequired(rule, required) { if ruleMatchesRequired(rule, required) {
@@ -323,139 +214,3 @@ func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
} }
return false 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
}

1155
pkg/models/iam/im.go Normal file

File diff suppressed because it is too large Load Diff

76
pkg/models/iam/path.go Normal file
View File

@@ -0,0 +1,76 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam
import (
"fmt"
"kubesphere.io/kubesphere/pkg/client"
"regexp"
"strings"
)
func convertDNToPath(dn string) string {
paths := regexp.MustCompile("cn=[a-z0-9]([-a-z0-9]*[a-z0-9])?").FindAllString(dn, -1)
if len(paths) > 1 {
for i := 0; i < len(paths); i++ {
paths[i] = strings.Replace(paths[i], "cn=", "", 1)
}
for i, j := 0, len(paths)-1; i < j; i, j = i+1, j-1 {
paths[i], paths[j] = paths[j], paths[i]
}
return strings.Join(paths, ":")
} else if len(paths) == 1 {
return strings.Replace(paths[0], "cn=", "", -1)
} else {
return ""
}
}
func splitPath(path string) (searchBase string, cn string) {
paths := strings.Split(path, ":")
length := len(paths)
if length > 2 {
cn = paths[length-1]
basePath := paths[:length-1]
for i := 0; i < len(basePath); i++ {
basePath[i] = fmt.Sprintf("cn=%s", basePath[i])
}
for i, j := 0, length-2; i < j; i, j = i+1, j-1 {
basePath[i], basePath[j] = basePath[j], basePath[i]
}
searchBase = fmt.Sprintf("%s,%s", strings.Join(basePath, ","), client.GroupSearchBase)
} else if length == 2 {
searchBase = fmt.Sprintf("cn=%s,%s", paths[0], client.GroupSearchBase)
cn = paths[1]
} else {
searchBase = client.GroupSearchBase
if paths[0] == "" {
cn = "*"
} else {
cn = paths[0]
}
}
return
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +0,0 @@
package iam
import (
"k8s.io/api/rbac/v1"
)
type Action struct {
Name string `json:"name"`
Rules []v1.PolicyRule `json:"rules"`
}
type Rule struct {
Name string `json:"name"`
Actions []Action `json:"actions"`
}
type SimpleRule struct {
Name string `json:"name"`
Actions []string `json:"actions"`
}
type User struct {
Username string `json:"username"`
Groups []string `json:"groups"`
Password string `json:"password,omitempty"`
AvatarUrl string `json:"avatar_url"`
Description string `json:"description"`
Email string `json:"email"`
LastLoginTime string `json:"last_login_time"`
Status int `json:"status"`
ClusterRole string `json:"cluster_role"`
ClusterRules []SimpleRule `json:"cluster_rules,omitempty"`
Roles map[string]string `json:"roles,omitempty"`
Rules map[string][]SimpleRule `json:"rules,omitempty"`
Role string `json:"role,omitempty"`
WorkspaceRoles map[string]string `json:"workspace_roles,omitempty"`
WorkspaceRole string `json:"workspace_role,omitempty"`
WorkspaceRules map[string][]SimpleRule `json:"workspace_rules,omitempty"`
}

View File

@@ -258,7 +258,7 @@ func CreateKubeConfig(user string) error {
configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: user}, Data: data} configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: user}, Data: data}
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap) _, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
if err != nil && !errors.IsAlreadyExists(err) { if err != nil && !errors.IsAlreadyExists(err) {
glog.Errorf("create user %s's kubeConfig failed, reason: %s", user, err) glog.Errorf("create user %s's kubeConfig failed, reason: %v", user, err)
return err return err
} }
} }
@@ -271,7 +271,7 @@ func GetKubeConfig(user string) (string, error) {
k8sClient := client.K8sClient() k8sClient := client.K8sClient()
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{}) configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{})
if err != nil { if err != nil {
glog.Errorf("cannot get user %s's kubeConfig, reason: %s", user, err) glog.Errorf("cannot get user %s's kubeConfig, reason: %v", user, err)
return "", err return "", err
} }
return configMap.Data[kubectlConfigKey], nil return configMap.Data[kubectlConfigKey], nil
@@ -287,7 +287,7 @@ func DelKubeConfig(user string) error {
deletePolicy := metaV1.DeletePropagationBackground deletePolicy := metaV1.DeletePropagationBackground
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(user, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy}) err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(user, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
if err != nil { if err != nil {
glog.Errorf("delete user %s's kubeConfig failed, reason: %s", user, err) glog.Errorf("delete user %s's kubeConfig failed, reason: %v", user, err)
return err return err
} }
return nil return nil

View File

@@ -20,6 +20,7 @@ package kubectl
import ( import (
"fmt" "fmt"
"kubesphere.io/kubesphere/pkg/models"
"math/rand" "math/rand"
"github.com/golang/glog" "github.com/golang/glog"
@@ -38,18 +39,12 @@ const (
namespace = constants.KubeSphereControlNamespace namespace = constants.KubeSphereControlNamespace
) )
type PodInfo struct { func GetKubectlPod(username string) (models.PodInfo, error) {
Namespace string `json:"namespace"`
Pod string `json:"pod"`
Container string `json:"container"`
}
func GetKubectlPod(username string) (PodInfo, error) {
k8sClient := client.K8sClient() k8sClient := client.K8sClient()
deploy, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(username, metav1.GetOptions{}) deploy, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(username, metav1.GetOptions{})
if err != nil { if err != nil {
glog.Errorln(err) glog.Errorln(err)
return PodInfo{}, err return models.PodInfo{}, err
} }
selectors := deploy.Spec.Selector.MatchLabels selectors := deploy.Spec.Selector.MatchLabels
@@ -57,16 +52,16 @@ func GetKubectlPod(username string) (PodInfo, error) {
podList, err := k8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSelector}) podList, err := k8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
if err != nil { if err != nil {
glog.Errorln(err) glog.Errorln(err)
return PodInfo{}, err return models.PodInfo{}, err
} }
pod, err := selectCorrectPod(namespace, podList.Items) pod, err := selectCorrectPod(namespace, podList.Items)
if err != nil { if err != nil {
glog.Errorln(err) glog.Errorln(err)
return PodInfo{}, err return models.PodInfo{}, err
} }
info := PodInfo{Namespace: pod.Namespace, Pod: pod.Name, Container: pod.Status.ContainerStatuses[0].Name} info := models.PodInfo{Namespace: pod.Namespace, Pod: pod.Name, Container: pod.Status.ContainerStatuses[0].Name}
return info, nil return info, nil

View File

@@ -20,14 +20,13 @@ package metrics
import ( import (
"fmt" "fmt"
"kubesphere.io/kubesphere/pkg/models"
"net/url" "net/url"
"regexp" "regexp"
"strings" "strings"
"sync" "sync"
"time" "time"
v12 "k8s.io/client-go/listers/core/v1"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/components" "kubesphere.io/kubesphere/pkg/models/components"
@@ -50,7 +49,6 @@ import (
var ( var (
jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
nodeStatusDelLabel = []string{"endpoint", "instance", "job", "namespace", "pod", "service"} nodeStatusDelLabel = []string{"endpoint", "instance", "job", "namespace", "pod", "service"}
nodeLister v12.NodeLister
) )
const ( const (
@@ -126,10 +124,6 @@ type OneComponentStatus struct {
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
} }
func init() {
nodeLister = informers.SharedInformerFactory().Core().V1().Nodes().Lister()
}
func getAllWorkspaceNames(formatedMetric *FormatedMetric) map[string]int { func getAllWorkspaceNames(formatedMetric *FormatedMetric) map[string]int {
var wsMap = make(map[string]int) var wsMap = make(map[string]int)
@@ -197,12 +191,12 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
var timestampMap = make(map[float64]bool) var timestampMap = make(map[float64]bool)
if fmtMetrics.Data.ResultType == ResultTypeMatrix { if fmtMetrics.Data.ResultType == ResultTypeMatrix {
for i, _ := range fmtMetrics.Data.Result { for i := range fmtMetrics.Data.Result {
values, exist := fmtMetrics.Data.Result[i][ResultItemValues] values, exist := fmtMetrics.Data.Result[i][ResultItemValues]
if exist { if exist {
valueArray, sure := values.([]interface{}) valueArray, sure := values.([]interface{})
if sure { if sure {
for j, _ := range valueArray { for j := range valueArray {
timeAndValue := valueArray[j].([]interface{}) timeAndValue := valueArray[j].([]interface{})
timestampMap[float64(timeAndValue[0].(uint64))] = true timestampMap[float64(timeAndValue[0].(uint64))] = true
} }
@@ -213,7 +207,7 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
timestampArray := make([]float64, len(timestampMap)) timestampArray := make([]float64, len(timestampMap))
i := 0 i := 0
for timestamp, _ := range timestampMap { for timestamp := range timestampMap {
timestampArray[i] = timestamp timestampArray[i] = timestamp
i++ i++
} }
@@ -230,7 +224,7 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
formatValueArray := make([][]interface{}, len(timestampArray)) formatValueArray := make([][]interface{}, len(timestampArray))
j := 0 j := 0
for k, _ := range timestampArray { for k := range timestampArray {
valueItem, sure := valueArray[j].([]interface{}) valueItem, sure := valueArray[j].([]interface{})
if sure && float64(valueItem[0].(uint64)) == timestampArray[k] { if sure && float64(valueItem[0].(uint64)) == timestampArray[k] {
formatValueArray[k] = []interface{}{int64(timestampArray[k]), valueItem[1]} formatValueArray[k] = []interface{}{int64(timestampArray[k]), valueItem[1]}
@@ -294,7 +288,7 @@ func GetMetric(queryType, params, metricName string) *FormatedMetric {
} }
func GetNodeAddressInfo() *map[string][]v1.NodeAddress { func GetNodeAddressInfo() *map[string][]v1.NodeAddress {
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
nodes, err := nodeLister.List(labels.Everything()) nodes, err := nodeLister.List(labels.Everything())
if err != nil { if err != nil {
@@ -938,7 +932,7 @@ func MonitorComponentStatus(monitoringRequest *client.MonitoringRequestParams) *
nsStatus, exist := Components[ns] nsStatus, exist := Components[ns]
if exist { if exist {
for _, nsStatusItem := range nsStatus.(map[string]interface{}) { for _, nsStatusItem := range nsStatus.(map[string]interface{}) {
component := nsStatusItem.(components.Component) component := nsStatusItem.(models.Component)
namespaceComponentTotalMap[ns] += 1 namespaceComponentTotalMap[ns] += 1
if component.HealthyBackends != 0 && component.HealthyBackends == component.TotalBackends { if component.HealthyBackends != 0 && component.HealthyBackends == component.TotalBackends {
namespaceComponentHealthyMap[ns] += 1 namespaceComponentHealthyMap[ns] += 1

View File

@@ -33,7 +33,6 @@ import (
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"kubesphere.io/kubesphere/pkg/client" "kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/errors"
) )
func DrainNode(nodename string) (err error) { func DrainNode(nodename string) (err error) {
@@ -45,7 +44,7 @@ func DrainNode(nodename string) (err error) {
} }
if node.Spec.Unschedulable { if node.Spec.Unschedulable {
return errors.New(errors.Conflict, fmt.Sprintf("node %s have been drained", nodename)) return fmt.Errorf("node %s have been drained", nodename)
} }
data := []byte(" {\"spec\":{\"unschedulable\":true}}") data := []byte(" {\"spec\":{\"unschedulable\":true}}")

View File

@@ -23,10 +23,10 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
v12 "k8s.io/client-go/listers/core/v1"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/resources" "kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/params"
) )
const ( const (
@@ -51,27 +51,17 @@ var (
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods, statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles, namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles,
jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs} jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs}
resouceQuotaLister v12.ResourceQuotaLister
) )
type ResourceQuota struct {
Namespace string `json:"namespace"`
Data v1.ResourceQuotaStatus `json:"data"`
}
func getUsage(namespace, resource string) (int, error) { func getUsage(namespace, resource string) (int, error) {
list, err := resources.ListNamespaceResource(namespace, resource, "", "", false, -1, 0) list, err := resources.ListNamespaceResource(namespace, resource, &params.Conditions{}, "", false, -1, 0)
if err != nil { if err != nil {
return 0, err return 0, err
} }
return list.TotalCount, nil return list.TotalCount, nil
} }
func init() { func GetClusterQuotas() (*models.ResourceQuota, error) {
resouceQuotaLister = informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
}
func GetClusterQuotas() (*ResourceQuota, error) {
quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)} quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
@@ -85,11 +75,11 @@ func GetClusterQuotas() (*ResourceQuota, error) {
quota.Used[v1.ResourceName(k)] = quantity quota.Used[v1.ResourceName(k)] = quantity
} }
return &ResourceQuota{Namespace: "\"\"", Data: quota}, nil return &models.ResourceQuota{Namespace: "\"\"", Data: quota}, nil
} }
func GetNamespaceQuotas(namespace string) (*ResourceQuota, error) { func GetNamespaceQuotas(namespace string) (*models.ResourceQuota, error) {
quota, err := getNamespaceResourceQuota(namespace) quota, err := getNamespaceResourceQuota(namespace)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
@@ -115,7 +105,7 @@ func GetNamespaceQuotas(namespace string) (*ResourceQuota, error) {
} }
} }
return &ResourceQuota{Namespace: namespace, Data: *quota}, nil return &models.ResourceQuota{Namespace: namespace, Data: *quota}, nil
} }
func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) { func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
@@ -135,7 +125,8 @@ func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
} }
func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) { func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
quotaList, err := resouceQuotaLister.ResourceQuotas(namespace).List(labels.Everything()) resourceQuotaLister := informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
quotaList, err := resourceQuotaLister.ResourceQuotas(namespace).List(labels.Everything())
if err != nil || len(quotaList) == 0 { if err != nil || len(quotaList) == 0 {
return nil, err return nil, err
} }

View File

@@ -20,12 +20,11 @@ package registries
import ( import (
"context" "context"
"encoding/base64" "encoding/base64"
"fmt"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/golang/glog" "github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/errors"
) )
type AuthInfo struct { type AuthInfo struct {
@@ -62,6 +61,6 @@ func RegistryVerify(authInfo AuthInfo) error {
if resp.Status == loginSuccess { if resp.Status == loginSuccess {
return nil return nil
} else { } else {
return errors.New(errors.VerifyFailed, resp.Status) return fmt.Errorf(resp.Status)
} }
} }

View File

@@ -18,19 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
rbac "k8s.io/api/rbac/v1" rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/listers/rbac/v1"
) )
type clusterRoleSearcher struct { type clusterRoleSearcher struct {
clusterRoleLister v1.ClusterRoleLister
} }
// exactly match // exactly Match
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool { func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -45,7 +45,7 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool { func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -86,8 +86,8 @@ func (*clusterRoleSearcher) compare(a, b *rbac.ClusterRole, orderBy string) bool
} }
} }
func (s *clusterRoleSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *clusterRoleSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
clusterRoles, err := s.clusterRoleLister.List(labels.Everything()) clusterRoles, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister().List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -95,11 +95,11 @@ func (s *clusterRoleSearcher) search(conditions *conditions, orderBy string, rev
result := make([]*rbac.ClusterRole, 0) result := make([]*rbac.ClusterRole, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = clusterRoles result = clusterRoles
} else { } else {
for _, item := range clusterRoles { for _, item := range clusterRoles {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,20 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/core/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type configMapSearcher struct { type configMapSearcher struct {
configMapLister lister.ConfigMapLister
} }
// exactly match // exactly Match
func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool { func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -46,7 +45,7 @@ func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) boo
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool { func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -91,8 +90,8 @@ func (*configMapSearcher) compare(a, b *v1.ConfigMap, orderBy string) bool {
} }
} }
func (s *configMapSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *configMapSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
configMaps, err := s.configMapLister.ConfigMaps(namespace).List(labels.Everything()) configMaps, err := informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -100,11 +99,11 @@ func (s *configMapSearcher) search(namespace string, conditions *conditions, ord
result := make([]*v1.ConfigMap, 0) result := make([]*v1.ConfigMap, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = configMaps result = configMaps
} else { } else {
for _, item := range configMaps { for _, item := range configMaps {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,28 +18,28 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/batch/v2alpha1" "k8s.io/api/batch/v1beta1"
"k8s.io/api/batch/v2alpha1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type cronJobSearcher struct { type cronJobSearcher struct {
cronJobLister lister.CronJobLister
} }
func cronJobStatus(item *v2alpha1.CronJob) string { func cronJobStatus(item *v1beta1.CronJob) string {
if item.Spec.Suspend != nil && *item.Spec.Suspend { if item.Spec.Suspend != nil && *item.Spec.Suspend {
return paused return paused
} }
return running return running
} }
// Exactly match // Exactly Match
func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) bool { func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
case status: case status:
@@ -53,7 +53,7 @@ func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) b
return true return true
} }
func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v2alpha1.CronJob) bool { func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.CronJob) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -88,7 +88,7 @@ func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v2alpha1.CronJob) b
return true return true
} }
func (*cronJobSearcher) compare(a, b *v2alpha1.CronJob, orderBy string) bool { func (*cronJobSearcher) compare(a, b *v1beta1.CronJob, orderBy string) bool {
switch orderBy { switch orderBy {
case createTime: case createTime:
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time) return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
@@ -99,20 +99,20 @@ func (*cronJobSearcher) compare(a, b *v2alpha1.CronJob, orderBy string) bool {
} }
} }
func (s *cronJobSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *cronJobSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
cronJobs, err := s.cronJobLister.CronJobs(namespace).List(labels.Everything()) cronJobs, err := informers.SharedInformerFactory().Batch().V1beta1().CronJobs().Lister().CronJobs(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
} }
result := make([]*v2alpha1.CronJob, 0) result := make([]*v1beta1.CronJob, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = cronJobs result = cronJobs
} else { } else {
for _, item := range cronJobs { for _, item := range cronJobs {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,17 +18,16 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/apps/v1"
"k8s.io/api/apps/v1" "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type daemonSetSearcher struct { type daemonSetSearcher struct {
daemonSetLister lister.DaemonSetLister
} }
func daemonSetStatus(item *v1.DaemonSet) string { func daemonSetStatus(item *v1.DaemonSet) string {
@@ -41,7 +40,7 @@ func daemonSetStatus(item *v1.DaemonSet) string {
} }
} }
// Exactly match // Exactly Match
func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool { func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -102,8 +101,8 @@ func (*daemonSetSearcher) compare(a, b *v1.DaemonSet, orderBy string) bool {
} }
} }
func (s *daemonSetSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *daemonSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
daemonSets, err := s.daemonSetLister.DaemonSets(namespace).List(labels.Everything()) daemonSets, err := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister().DaemonSets(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -111,11 +110,11 @@ func (s *daemonSetSearcher) search(namespace string, conditions *conditions, ord
result := make([]*v1.DaemonSet, 0) result := make([]*v1.DaemonSet, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = daemonSets result = daemonSets
} else { } else {
for _, item := range daemonSets { for _, item := range daemonSets {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,18 +18,17 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/apps/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/api/apps/v1" "k8s.io/api/apps/v1"
) )
type deploymentSearcher struct { type deploymentSearcher struct {
deploymentLister lister.DeploymentLister
} }
func deploymentStatus(item *v1.Deployment) string { func deploymentStatus(item *v1.Deployment) string {
@@ -45,7 +44,7 @@ func deploymentStatus(item *v1.Deployment) string {
return stopped return stopped
} }
// Exactly match // Exactly Match
func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool { func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -106,8 +105,8 @@ func (*deploymentSearcher) compare(a, b *v1.Deployment, orderBy string) bool {
} }
} }
func (s *deploymentSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *deploymentSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
deployments, err := s.deploymentLister.Deployments(namespace).List(labels.Everything()) deployments, err := informers.SharedInformerFactory().Apps().V1().Deployments().Lister().Deployments(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -115,11 +114,11 @@ func (s *deploymentSearcher) search(namespace string, conditions *conditions, or
result := make([]*v1.Deployment, 0) result := make([]*v1.Deployment, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = deployments result = deployments
} else { } else {
for _, item := range deployments { for _, item := range deployments {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,21 +18,20 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/extensions/v1beta1"
extensions "k8s.io/api/extensions/v1beta1" extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type ingressSearcher struct { type ingressSearcher struct {
ingressLister lister.IngressLister
} }
// exactly match // exactly Match
func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress) bool { func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -47,7 +46,7 @@ func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress)
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress) bool { func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -92,8 +91,8 @@ func (*ingressSearcher) compare(a, b *extensions.Ingress, orderBy string) bool {
} }
} }
func (s *ingressSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *ingressSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
ingresses, err := s.ingressLister.Ingresses(namespace).List(labels.Everything()) ingresses, err := informers.SharedInformerFactory().Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -101,11 +100,11 @@ func (s *ingressSearcher) search(namespace string, conditions *conditions, order
result := make([]*extensions.Ingress, 0) result := make([]*extensions.Ingress, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = ingresses result = ingresses
} else { } else {
for _, item := range ingresses { for _, item := range ingresses {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,37 +18,36 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
"time" "time"
lister "k8s.io/client-go/listers/batch/v1" batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
batchV1 "k8s.io/api/batch/v1"
coreV1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type jobSearcher struct { type jobSearcher struct {
jobLister lister.JobLister
} }
func jobStatus(item *batchV1.Job) string { func jobStatus(item *batchv1.Job) string {
status := "" status := ""
for _, condition := range item.Status.Conditions { for _, condition := range item.Status.Conditions {
if condition.Type == batchV1.JobFailed && condition.Status == coreV1.ConditionTrue { if condition.Type == batchv1.JobFailed && condition.Status == corev1.ConditionTrue {
status = failed status = failed
} }
if condition.Type == batchV1.JobComplete && condition.Status == coreV1.ConditionTrue { if condition.Type == batchv1.JobComplete && condition.Status == corev1.ConditionTrue {
status = complete status = complete
} }
} }
return status return status
} }
// Exactly match // Exactly Match
func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool { func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
case status: case status:
@@ -62,7 +61,7 @@ func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool {
return true return true
} }
func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchV1.Job) bool { func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchv1.Job) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -97,7 +96,7 @@ func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchV1.Job) bool {
return true return true
} }
func jobUpdateTime(item *batchV1.Job) time.Time { func jobUpdateTime(item *batchv1.Job) time.Time {
updateTime := item.CreationTimestamp.Time updateTime := item.CreationTimestamp.Time
for _, condition := range item.Status.Conditions { for _, condition := range item.Status.Conditions {
if updateTime.Before(condition.LastProbeTime.Time) { if updateTime.Before(condition.LastProbeTime.Time) {
@@ -110,7 +109,7 @@ func jobUpdateTime(item *batchV1.Job) time.Time {
return updateTime return updateTime
} }
func (*jobSearcher) compare(a, b *batchV1.Job, orderBy string) bool { func (*jobSearcher) compare(a, b *batchv1.Job, orderBy string) bool {
switch orderBy { switch orderBy {
case updateTime: case updateTime:
return jobUpdateTime(a).After(jobUpdateTime(b)) return jobUpdateTime(a).After(jobUpdateTime(b))
@@ -121,20 +120,20 @@ func (*jobSearcher) compare(a, b *batchV1.Job, orderBy string) bool {
} }
} }
func (s *jobSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *jobSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
jobs, err := s.jobLister.Jobs(namespace).List(labels.Everything()) jobs, err := informers.SharedInformerFactory().Batch().V1().Jobs().Lister().Jobs(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
} }
result := make([]*batchV1.Job, 0) result := make([]*batchv1.Job, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = jobs result = jobs
} else { } else {
for _, item := range jobs { for _, item := range jobs {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,19 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
lister "k8s.io/client-go/listers/core/v1"
) )
type namespaceSearcher struct { type namespaceSearcher struct {
namespaceLister lister.NamespaceLister
} }
// exactly match // exactly Match
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool { func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -45,7 +45,7 @@ func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) boo
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool { func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -90,8 +90,8 @@ func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
} }
} }
func (s *namespaceSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *namespaceSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
namespaces, err := s.namespaceLister.List(labels.Everything()) namespaces, err := informers.SharedInformerFactory().Core().V1().Namespaces().Lister().List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -99,11 +99,11 @@ func (s *namespaceSearcher) search(conditions *conditions, orderBy string, rever
result := make([]*v1.Namespace, 0) result := make([]*v1.Namespace, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = namespaces result = namespaces
} else { } else {
for _, item := range namespaces { for _, item := range namespaces {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,19 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
lister "k8s.io/client-go/listers/core/v1"
) )
type nodeSearcher struct { type nodeSearcher struct {
nodeLister lister.NodeLister
} }
// exactly match // exactly Match
func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool { func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -45,7 +45,7 @@ func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool { func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -90,8 +90,8 @@ func (*nodeSearcher) compare(a, b *v1.Node, orderBy string) bool {
} }
} }
func (s *nodeSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *nodeSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
nodes, err := s.nodeLister.List(labels.Everything()) nodes, err := informers.SharedInformerFactory().Core().V1().Nodes().Lister().List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -99,11 +99,11 @@ func (s *nodeSearcher) search(conditions *conditions, orderBy string, reverse bo
result := make([]*v1.Node, 0) result := make([]*v1.Node, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = nodes result = nodes
} else { } else {
for _, item := range nodes { for _, item := range nodes {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,20 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/core/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type persistentVolumeClaimSearcher struct { type persistentVolumeClaimSearcher struct {
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
} }
// exactly match // exactly Match
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool { func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -46,7 +45,7 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool { func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -91,8 +90,8 @@ func (*persistentVolumeClaimSearcher) compare(a, b *v1.PersistentVolumeClaim, or
} }
} }
func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
persistentVolumeClaims, err := s.persistentVolumeClaimLister.PersistentVolumeClaims(namespace).List(labels.Everything()) persistentVolumeClaims, err := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister().PersistentVolumeClaims(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -100,11 +99,11 @@ func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *con
result := make([]*v1.PersistentVolumeClaim, 0) result := make([]*v1.PersistentVolumeClaim, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = persistentVolumeClaims result = persistentVolumeClaims
} else { } else {
for _, item := range persistentVolumeClaims { for _, item := range persistentVolumeClaims {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,20 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
v12 "k8s.io/client-go/listers/core/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type podSearcher struct { type podSearcher struct {
podLister v12.PodLister
} }
// exactly match // exactly Match
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool { func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -46,7 +45,7 @@ func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool { func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -91,9 +90,9 @@ func (*podSearcher) compare(a, b *v1.Pod, orderBy string) bool {
} }
} }
func (s *podSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *podSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
pods, err := s.podLister.Pods(namespace).List(labels.Everything()) pods, err := informers.SharedInformerFactory().Core().V1().Pods().Lister().Pods(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -101,11 +100,11 @@ func (s *podSearcher) search(namespace string, conditions *conditions, orderBy s
result := make([]*v1.Pod, 0) result := make([]*v1.Pod, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = pods result = pods
} else { } else {
for _, item := range pods { for _, item := range pods {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,74 +18,35 @@
package resources package resources
import ( import (
"regexp" "fmt"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/params"
"strings" "strings"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/errors"
) )
func init() { func init() {
namespacedResources[ConfigMaps] = &configMapSearcher{ namespacedResources[ConfigMaps] = &configMapSearcher{}
configMapLister: informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister(), namespacedResources[CronJobs] = &cronJobSearcher{}
} namespacedResources[DaemonSets] = &daemonSetSearcher{}
namespacedResources[CronJobs] = &cronJobSearcher{ namespacedResources[Deployments] = &deploymentSearcher{}
cronJobLister: informers.SharedInformerFactory().Batch().V2alpha1().CronJobs().Lister(), namespacedResources[Ingresses] = &ingressSearcher{}
} namespacedResources[Jobs] = &jobSearcher{}
namespacedResources[DaemonSets] = &daemonSetSearcher{ namespacedResources[PersistentVolumeClaims] = &persistentVolumeClaimSearcher{}
daemonSetLister: informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister(), namespacedResources[Secrets] = &secretSearcher{}
} namespacedResources[Services] = &serviceSearcher{}
namespacedResources[Deployments] = &deploymentSearcher{ namespacedResources[StatefulSets] = &statefulSetSearcher{}
deploymentLister: informers.SharedInformerFactory().Apps().V1().Deployments().Lister(), namespacedResources[Pods] = &podSearcher{}
} namespacedResources[Roles] = &roleSearcher{}
namespacedResources[Ingresses] = &ingressSearcher{
ingressLister: informers.SharedInformerFactory().Extensions().V1beta1().Ingresses().Lister(),
}
namespacedResources[Jobs] = &jobSearcher{
jobLister: informers.SharedInformerFactory().Batch().V1().Jobs().Lister(),
}
namespacedResources[PersistentVolumeClaims] = &persistentVolumeClaimSearcher{
persistentVolumeClaimLister: informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister(),
}
namespacedResources[Secrets] = &secretSearcher{
secretLister: informers.SharedInformerFactory().Core().V1().Secrets().Lister(),
}
namespacedResources[Services] = &serviceSearcher{
serviceLister: informers.SharedInformerFactory().Core().V1().Services().Lister(),
}
namespacedResources[StatefulSets] = &statefulSetSearcher{
statefulSetLister: informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister(),
}
namespacedResources[Pods] = &podSearcher{
podLister: informers.SharedInformerFactory().Core().V1().Pods().Lister(),
}
namespacedResources[Roles] = &roleSearcher{
roleLister: informers.SharedInformerFactory().Rbac().V1().Roles().Lister(),
}
clusterResources[Nodes] = &nodeSearcher{ clusterResources[Nodes] = &nodeSearcher{}
nodeLister: informers.SharedInformerFactory().Core().V1().Nodes().Lister(), clusterResources[Namespaces] = &namespaceSearcher{}
} clusterResources[ClusterRoles] = &clusterRoleSearcher{}
clusterResources[Namespaces] = &namespaceSearcher{ clusterResources[StorageClasses] = &storageClassesSearcher{}
namespaceLister: informers.SharedInformerFactory().Core().V1().Namespaces().Lister(),
}
clusterResources[ClusterRoles] = &clusterRoleSearcher{
clusterRoleLister: informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister(),
}
clusterResources[StorageClasses] = &storageClassesSearcher{
storageClassesLister: informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister(),
}
} }
var namespacedResources = make(map[string]namespacedSearcherInterface) var namespacedResources = make(map[string]namespacedSearcherInterface)
var clusterResources = make(map[string]clusterSearcherInterface) var clusterResources = make(map[string]clusterSearcherInterface)
type conditions struct {
match map[string]string
fuzzy map[string]string
}
const ( const (
name = "name" name = "name"
label = "label" label = "label"
@@ -123,33 +84,26 @@ const (
) )
type namespacedSearcherInterface interface { type namespacedSearcherInterface interface {
search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
} }
type clusterSearcherInterface interface { type clusterSearcherInterface interface {
search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
} }
func ListNamespaceResource(namespace, resource, conditionStr, orderBy string, reverse bool, limit, offset int) (*ResourceList, error) { func ListNamespaceResource(namespace, resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
items := make([]interface{}, 0) items := make([]interface{}, 0)
total := 0 total := 0
var err error var err error
conditions, err := parseToConditions(conditionStr)
if err != nil {
return nil, err
}
var result []interface{} var result []interface{}
if searcher, ok := namespacedResources[resource]; ok { if searcher, ok := namespacedResources[resource]; ok {
result, err = searcher.search(namespace, conditions, orderBy, reverse) result, err = searcher.search(namespace, conditions, orderBy, reverse)
} else { } else {
return nil, errors.New(errors.NotImplement, "not support") return nil, fmt.Errorf("not support")
} }
if err != nil { if err != nil {
return nil, errors.New(errors.Internal, err.Error()) return nil, err
} }
total = len(result) total = len(result)
@@ -160,16 +114,14 @@ func ListNamespaceResource(namespace, resource, conditionStr, orderBy string, re
} }
} }
return &ResourceList{TotalCount: total, Items: items}, nil return &models.PageableResponse{TotalCount: total, Items: items}, nil
} }
func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, limit, offset int) (*ResourceList, error) { func ListClusterResource(resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
items := make([]interface{}, 0) items := make([]interface{}, 0)
total := 0 total := 0
var err error var err error
conditions, err := parseToConditions(conditionStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -179,11 +131,11 @@ func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, l
if searcher, ok := clusterResources[resource]; ok { if searcher, ok := clusterResources[resource]; ok {
result, err = searcher.search(conditions, orderBy, reverse) result, err = searcher.search(conditions, orderBy, reverse)
} else { } else {
return nil, errors.New(errors.NotImplement, "not support") return nil, fmt.Errorf("not support")
} }
if err != nil { if err != nil {
return nil, errors.New(errors.Internal, err.Error()) return nil, err
} }
total = len(result) total = len(result)
@@ -194,36 +146,7 @@ func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, l
} }
} }
return &ResourceList{TotalCount: total, Items: items}, nil return &models.PageableResponse{TotalCount: total, Items: items}, nil
}
func parseToConditions(str string) (*conditions, error) {
conditions := &conditions{match: make(map[string]string, 0), fuzzy: make(map[string]string, 0)}
if str == "" {
return conditions, nil
}
for _, item := range strings.Split(str, ",") {
if strings.Count(item, "=") > 1 || strings.Count(item, "~") > 1 {
return nil, errors.New(errors.InvalidArgument, "invalid condition")
}
if groups := regexp.MustCompile(`(\S+)([=~])(\S+)`).FindStringSubmatch(item); len(groups) == 4 {
if groups[2] == "=" {
conditions.match[groups[1]] = groups[3]
} else {
conditions.fuzzy[groups[1]] = groups[3]
}
} else {
return nil, errors.New(errors.InvalidArgument, "invalid condition")
}
}
return conditions, nil
}
type ResourceList struct {
TotalCount int `json:"total_count"`
Items []interface{} `json:"items"`
} }
func searchFuzzy(m map[string]string, key, value string) bool { func searchFuzzy(m map[string]string, key, value string) bool {

View File

@@ -18,20 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
rbac "k8s.io/api/rbac/v1" rbac "k8s.io/api/rbac/v1"
lister "k8s.io/client-go/listers/rbac/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type roleSearcher struct { type roleSearcher struct {
roleLister lister.RoleLister
} }
// exactly match // exactly Match
func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool { func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -46,7 +45,7 @@ func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool { func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -87,8 +86,8 @@ func (*roleSearcher) compare(a, b *rbac.Role, orderBy string) bool {
} }
} }
func (s *roleSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *roleSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
roles, err := s.roleLister.Roles(namespace).List(labels.Everything()) roles, err := informers.SharedInformerFactory().Rbac().V1().Roles().Lister().Roles(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -96,11 +95,11 @@ func (s *roleSearcher) search(namespace string, conditions *conditions, orderBy
result := make([]*rbac.Role, 0) result := make([]*rbac.Role, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = roles result = roles
} else { } else {
for _, item := range roles { for _, item := range roles {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,20 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/core/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type secretSearcher struct { type secretSearcher struct {
secretLister lister.SecretLister
} }
// exactly match // exactly Match
func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool { func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -50,7 +49,7 @@ func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool { func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -95,8 +94,8 @@ func (*secretSearcher) compare(a, b *v1.Secret, orderBy string) bool {
} }
} }
func (s *secretSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *secretSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
secrets, err := s.secretLister.Secrets(namespace).List(labels.Everything()) secrets, err := informers.SharedInformerFactory().Core().V1().Secrets().Lister().Secrets(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -104,11 +103,11 @@ func (s *secretSearcher) search(namespace string, conditions *conditions, orderB
result := make([]*v1.Secret, 0) result := make([]*v1.Secret, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = secrets result = secrets
} else { } else {
for _, item := range secrets { for _, item := range secrets {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,20 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/core/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type serviceSearcher struct { type serviceSearcher struct {
serviceLister lister.ServiceLister
} }
// exactly match // exactly Match
func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool { func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -46,7 +45,7 @@ func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool { func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -91,8 +90,8 @@ func (*serviceSearcher) compare(a, b *v1.Service, orderBy string) bool {
} }
} }
func (s *serviceSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *serviceSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
services, err := s.serviceLister.Services(namespace).List(labels.Everything()) services, err := informers.SharedInformerFactory().Core().V1().Services().Lister().Services(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -100,11 +99,11 @@ func (s *serviceSearcher) search(namespace string, conditions *conditions, order
result := make([]*v1.Service, 0) result := make([]*v1.Service, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = services result = services
} else { } else {
for _, item := range services { for _, item := range services {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,17 +18,16 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
lister "k8s.io/client-go/listers/apps/v1"
"k8s.io/api/apps/v1" "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
) )
type statefulSetSearcher struct { type statefulSetSearcher struct {
statefulSetLister lister.StatefulSetLister
} }
func statefulSetStatus(item *v1.StatefulSet) string { func statefulSetStatus(item *v1.StatefulSet) string {
@@ -44,7 +43,7 @@ func statefulSetStatus(item *v1.StatefulSet) string {
return stopped return stopped
} }
// Exactly match // Exactly Match
func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool { func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -105,8 +104,8 @@ func (*statefulSetSearcher) compare(a, b *v1.StatefulSet, orderBy string) bool {
} }
} }
func (s *statefulSetSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *statefulSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
statefulSets, err := s.statefulSetLister.StatefulSets(namespace).List(labels.Everything()) statefulSets, err := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister().StatefulSets(namespace).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -114,11 +113,11 @@ func (s *statefulSetSearcher) search(namespace string, conditions *conditions, o
result := make([]*v1.StatefulSet, 0) result := make([]*v1.StatefulSet, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = statefulSets result = statefulSets
} else { } else {
for _, item := range statefulSets { for _, item := range statefulSets {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -18,19 +18,19 @@
package resources package resources
import ( import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort" "sort"
"strings" "strings"
"k8s.io/api/storage/v1" "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
lister "k8s.io/client-go/listers/storage/v1"
) )
type storageClassesSearcher struct { type storageClassesSearcher struct {
storageClassesLister lister.StorageClassLister
} }
// exactly match // exactly Match
func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool { func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
@@ -45,7 +45,7 @@ func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageCl
return true return true
} }
// fuzzy searchInNamespace // Fuzzy searchInNamespace
func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool { func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool {
for k, v := range fuzzy { for k, v := range fuzzy {
switch k { switch k {
@@ -86,8 +86,8 @@ func (*storageClassesSearcher) compare(a, b *v1.StorageClass, orderBy string) bo
} }
} }
func (s *storageClassesSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) { func (s *storageClassesSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
storageClasses, err := s.storageClassesLister.List(labels.Everything()) storageClasses, err := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister().List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -95,11 +95,11 @@ func (s *storageClassesSearcher) search(conditions *conditions, orderBy string,
result := make([]*v1.StorageClass, 0) result := make([]*v1.StorageClass, 0)
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 { if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
result = storageClasses result = storageClasses
} else { } else {
for _, item := range storageClasses { for _, item := range storageClasses {
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) { if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
result = append(result, item) result = append(result, item)
} }
} }

View File

@@ -24,29 +24,11 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/apps/v1" "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
lister "k8s.io/client-go/listers/apps/v1"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
) )
var (
daemonSetLister lister.DaemonSetLister
deploymentLister lister.DeploymentLister
replicaSetLister lister.ReplicaSetLister
statefulSetLister lister.StatefulSetLister
controllerRevisionLister lister.ControllerRevisionLister
)
func init() {
daemonSetLister = informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister()
deploymentLister = informers.SharedInformerFactory().Apps().V1().Deployments().Lister()
replicaSetLister = informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
statefulSetLister = informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister()
controllerRevisionLister = informers.SharedInformerFactory().Apps().V1().ControllerRevisions().Lister()
}
func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error) { func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error) {
deploymentLister := informers.SharedInformerFactory().Apps().V1().Deployments().Lister()
deploy, err := deploymentLister.Deployments(namespace).Get(name) deploy, err := deploymentLister.Deployments(namespace).Get(name)
if err != nil { if err != nil {
glog.Errorf("get deployment %s failed, reason: %s", name, err) glog.Errorf("get deployment %s failed, reason: %s", name, err)
@@ -56,6 +38,7 @@ func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error)
labelMap := deploy.Spec.Template.Labels labelMap := deploy.Spec.Template.Labels
labelSelector := labels.Set(labelMap).AsSelector() labelSelector := labels.Set(labelMap).AsSelector()
replicaSetLister := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
rsList, err := replicaSetLister.ReplicaSets(namespace).List(labelSelector) rsList, err := replicaSetLister.ReplicaSets(namespace).List(labelSelector)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -67,11 +50,11 @@ func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error)
} }
} }
return nil, errors.New(errors.NotFound, fmt.Sprintf("revision not found %v#%v", name, revision)) return nil, fmt.Errorf("revision not found %v#%v", name, revision)
} }
func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) { func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
daemonSetLister := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister()
ds, err := daemonSetLister.DaemonSets(namespace).Get(name) ds, err := daemonSetLister.DaemonSets(namespace).Get(name)
if err != nil { if err != nil {
@@ -84,7 +67,7 @@ func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.Controll
} }
func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) { func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
statefulSetLister := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister()
st, err := statefulSetLister.StatefulSets(namespace).Get(name) st, err := statefulSetLister.StatefulSets(namespace).Get(name)
if err != nil { if err != nil {
@@ -97,7 +80,7 @@ func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.Contro
func getControllerRevision(namespace, name string, labelMap map[string]string, revision int) (*v1.ControllerRevision, error) { func getControllerRevision(namespace, name string, labelMap map[string]string, revision int) (*v1.ControllerRevision, error) {
labelSelector := labels.Set(labelMap).AsSelector() labelSelector := labels.Set(labelMap).AsSelector()
controllerRevisionLister := informers.SharedInformerFactory().Apps().V1().ControllerRevisions().Lister()
revisions, err := controllerRevisionLister.ControllerRevisions(namespace).List(labelSelector) revisions, err := controllerRevisionLister.ControllerRevisions(namespace).List(labelSelector)
if err != nil { if err != nil {
@@ -110,5 +93,5 @@ func getControllerRevision(namespace, name string, labelMap map[string]string, r
} }
} }
return nil, errors.New(errors.NotFound, fmt.Sprintf("revision not found %v#%v", name, revision)) return nil, fmt.Errorf("revision not found %v#%v", name, revision)
} }

View File

@@ -23,15 +23,12 @@ import (
"io/ioutil" "io/ioutil"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
v12 "k8s.io/client-go/listers/core/v1"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"github.com/golang/glog" "github.com/golang/glog"
coreV1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
extensionsV1beta1 "k8s.io/api/extensions/v1beta1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
"k8s.io/api/rbac/v1" "k8s.io/api/rbac/v1"
@@ -43,18 +40,10 @@ import (
"kubesphere.io/kubesphere/pkg/models/iam" "kubesphere.io/kubesphere/pkg/models/iam"
) )
var ( func GetAllRouters() ([]*corev1.Service, error) {
serviceLister v12.ServiceLister
)
func init() {
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
}
func GetAllRouters() ([]*coreV1.Service, error) {
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend"}) selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend"})
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector) services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
if err != nil { if err != nil {
@@ -65,7 +54,7 @@ func GetAllRouters() ([]*coreV1.Service, error) {
return services, nil return services, nil
} }
func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) { func GetAllRoutersOfUser(username string) ([]*corev1.Service, error) {
allNamespace, namespaces, err := iam.GetUserNamespaces(username, v1.PolicyRule{ allNamespace, namespaces, err := iam.GetUserNamespaces(username, v1.PolicyRule{
Verbs: []string{"get", "list"}, Verbs: []string{"get", "list"},
APIGroups: []string{""}, APIGroups: []string{""},
@@ -82,7 +71,7 @@ func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
return GetAllRouters() return GetAllRouters()
} }
routers := make([]*coreV1.Service, 0) routers := make([]*corev1.Service, 0)
for _, namespace := range namespaces { for _, namespace := range namespaces {
router, err := GetRouter(namespace) router, err := GetRouter(namespace)
@@ -99,11 +88,11 @@ func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
} }
// Get router from a namespace // Get router from a namespace
func GetRouter(namespace string) (*coreV1.Service, error) { func GetRouter(namespace string) (*corev1.Service, error) {
serviceName := constants.IngressControllerPrefix + namespace serviceName := constants.IngressControllerPrefix + namespace
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend", "project": namespace}) selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend", "project": namespace})
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector) services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
if err != nil { if err != nil {
@@ -116,7 +105,7 @@ func GetRouter(namespace string) (*coreV1.Service, error) {
} }
} }
return nil, errors.New(errors.NotFound, fmt.Sprintf("resources not found %s", serviceName)) return nil, fmt.Errorf("resources not found %s", serviceName)
} }
// Load all resource yamls // Load all resource yamls
@@ -148,11 +137,11 @@ func LoadYamls() ([]string, error) {
} }
// Create a ingress controller in a namespace // Create a ingress controller in a namespace
func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) { func CreateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
k8sClient := client.K8sClient() k8sClient := client.K8sClient()
var router *coreV1.Service var router *corev1.Service
yamls, err := LoadYamls() yamls, err := LoadYamls()
@@ -170,8 +159,8 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
} }
switch obj.(type) { switch obj.(type) {
case *coreV1.Service: case *corev1.Service:
service := obj.(*coreV1.Service) service := obj.(*corev1.Service)
service.SetAnnotations(annotations) service.SetAnnotations(annotations)
service.Spec.Type = routerType service.Spec.Type = routerType
@@ -190,8 +179,8 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
router = service router = service
case *extensionsV1beta1.Deployment: case *extensionsv1beta1.Deployment:
deployment := obj.(*extensionsV1beta1.Deployment) deployment := obj.(*extensionsv1beta1.Deployment)
deployment.Name = constants.IngressControllerPrefix + namespace deployment.Name = constants.IngressControllerPrefix + namespace
// Add project label // Add project label
@@ -204,7 +193,7 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
// Choose self as master // Choose self as master
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name) deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
if routerType == coreV1.ServiceTypeLoadBalancer { if routerType == corev1.ServiceTypeLoadBalancer {
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace) deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
} else { } else {
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address") deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
@@ -224,11 +213,11 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
// DeleteRouter is used to delete ingress controller related resources in namespace // DeleteRouter is used to delete ingress controller related resources in namespace
// It will not delete ClusterRole resource cause it maybe used by other controllers // It will not delete ClusterRole resource cause it maybe used by other controllers
func DeleteRouter(namespace string) (*coreV1.Service, error) { func DeleteRouter(namespace string) (*corev1.Service, error) {
k8sClient := client.K8sClient() k8sClient := client.K8sClient()
var err error var err error
var router *coreV1.Service var router *corev1.Service
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
@@ -236,9 +225,9 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
// delete controller service // delete controller service
serviceName := constants.IngressControllerPrefix + namespace serviceName := constants.IngressControllerPrefix + namespace
deleteOptions := metaV1.DeleteOptions{} deleteOptions := meta_v1.DeleteOptions{}
listOptions := metaV1.ListOptions{ listOptions := meta_v1.ListOptions{
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace, LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
FieldSelector: "metadata.name=" + serviceName} FieldSelector: "metadata.name=" + serviceName}
@@ -259,7 +248,7 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
// delete controller deployment // delete controller deployment
deploymentName := constants.IngressControllerPrefix + namespace deploymentName := constants.IngressControllerPrefix + namespace
listOptions = metaV1.ListOptions{ listOptions = meta_v1.ListOptions{
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace, LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
} }
deployments, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).List(listOptions) deployments, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).List(listOptions)
@@ -279,10 +268,10 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
} }
// Update Ingress Controller Service, change type from NodePort to Loadbalancer or vice versa. // Update Ingress Controller Service, change type from NodePort to Loadbalancer or vice versa.
func UpdateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) { func UpdateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
k8sClient := client.K8sClient() k8sClient := client.K8sClient()
var router *coreV1.Service var router *corev1.Service
router, err := GetRouter(namespace) router, err := GetRouter(namespace)
@@ -293,7 +282,7 @@ func UpdateRouter(namespace string, routerType coreV1.ServiceType, annotations m
if router == nil { if router == nil {
glog.Error("Trying to update a non-existed router") glog.Error("Trying to update a non-existed router")
return nil, errors.New(errors.Internal, "router not created yet") return nil, fmt.Errorf("router not created yet")
} }
// from LoadBalancer to NodePort, or vice-versa // from LoadBalancer to NodePort, or vice-versa

View File

@@ -18,7 +18,8 @@
package status package status
import ( import (
"fmt" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/params"
"kubesphere.io/kubesphere/pkg/models/resources" "kubesphere.io/kubesphere/pkg/models/resources"
) )
@@ -31,7 +32,7 @@ type workLoadStatus struct {
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) { func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
res := workLoadStatus{Count: make(map[string]int), Namespace: namespace, Items: make(map[string]interface{})} res := workLoadStatus{Count: make(map[string]int), Namespace: namespace, Items: make(map[string]interface{})}
var notReadyList *resources.ResourceList var notReadyList *models.PageableResponse
var err error var err error
for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims} { for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims} {
notReadyStatus := "updating" notReadyStatus := "updating"
@@ -39,7 +40,7 @@ func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
notReadyStatus = "pending" notReadyStatus = "pending"
} }
notReadyList, err = resources.ListNamespaceResource(namespace, resource, fmt.Sprintf("status=%s", notReadyStatus), "", false, -1, 0) notReadyList, err = resources.ListNamespaceResource(namespace, resource, &params.Conditions{Match: map[string]string{"status": notReadyStatus}}, "", false, -1, 0)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -24,9 +24,6 @@ import (
storageV1 "k8s.io/api/storage/v1" storageV1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
lister "k8s.io/client-go/listers/core/v1"
lister2 "k8s.io/client-go/listers/storage/v1"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
) )
@@ -36,18 +33,12 @@ type ScMetrics struct {
PvcNumber string `json:"pvcNumber"` PvcNumber string `json:"pvcNumber"`
} }
var (
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
persistentVolumeLister lister.PersistentVolumeLister
sotrageClassesLister lister2.StorageClassLister
)
func init() { func init() {
persistentVolumeClaimLister = informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
persistentVolumeLister = informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
} }
func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) { func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
persistentVolumeClaimLister := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
all, err := persistentVolumeClaimLister.List(labels.Everything()) all, err := persistentVolumeClaimLister.List(labels.Everything())
if err != nil { if err != nil {
@@ -70,6 +61,7 @@ func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
// Get info of metrics // Get info of metrics
func GetScMetrics(scName string) (*ScMetrics, error) { func GetScMetrics(scName string) (*ScMetrics, error) {
persistentVolumeLister := informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
pvList, err := persistentVolumeLister.List(labels.Everything()) pvList, err := persistentVolumeLister.List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -102,7 +94,7 @@ func GetScMetrics(scName string) (*ScMetrics, error) {
func GetScList() ([]*storageV1.StorageClass, error) { func GetScList() ([]*storageV1.StorageClass, error) {
// Get StorageClass list // Get StorageClass list
scList, err := sotrageClassesLister.List(labels.Everything()) scList, err := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister().List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -20,19 +20,12 @@ package storage
import ( import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
v12 "k8s.io/client-go/listers/core/v1"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
) )
var podLister v12.PodLister
func init() {
podLister = informers.SharedInformerFactory().Core().V1().Pods().Lister()
}
// List pods of a specific persistent volume claims // List pods of a specific persistent volume claims
func GetPodListByPvc(pvc string, ns string) (res []*v1.Pod, err error) { func GetPodListByPvc(pvc string, ns string) (res []*v1.Pod, err error) {
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
podList, err := podLister.Pods(ns).List(labels.Everything()) podList, err := podLister.Pods(ns).List(labels.Everything())
if err != nil { if err != nil {
return nil, err return nil, err

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