add ks-iam and ks-apigateway
Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
@@ -17,9 +17,11 @@ before_install:
|
||||
before_script:
|
||||
- dep ensure -v
|
||||
- docker --version
|
||||
- git clone --single-branch -b v0.11.4 -q https://github.com/mholt/caddy $GOPATH/src/github.com/mholt/caddy
|
||||
|
||||
script:
|
||||
- make all && make test
|
||||
- make test
|
||||
- bash hack/docker_build.sh
|
||||
|
||||
deploy:
|
||||
skip_cleanup: true
|
||||
|
||||
442
Gopkg.lock
generated
442
Gopkg.lock
generated
@@ -2,57 +2,82 @@
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4d6f036ea3fe636bcb2e89850bcdc62a771354e157cd51b8b22a2de8562bf663"
|
||||
name = "cloud.google.com/go"
|
||||
packages = ["compute/metadata"]
|
||||
pruneopts = "UT"
|
||||
revision = "c9474f2f8deb81759839474b6bd1726bbfe1c1c4"
|
||||
version = "v0.36.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f9ae348e1f793dcf9ed930ed47136a67343dbd6809c5c91391322267f4476892"
|
||||
name = "github.com/Microsoft/go-winio"
|
||||
packages = ["."]
|
||||
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
|
||||
version = "v0.4.7"
|
||||
pruneopts = "UT"
|
||||
revision = "1a8911d1ed007260465c3bfbbc785ac6915a0bb8"
|
||||
version = "v0.4.12"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2682518d905d662d984ef9959984ef87cecb777d379bfa9d9fe40e78069b3e4"
|
||||
name = "github.com/PuerkitoBio/purell"
|
||||
packages = ["."]
|
||||
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
|
||||
version = "v1.1.0"
|
||||
pruneopts = "UT"
|
||||
revision = "44968752391892e1b0d0b821ee79e9a85fa13049"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c739832d67eb1e9cc478a19cc1a1ccd78df0397bf8a32978b759152e205f644b"
|
||||
name = "github.com/PuerkitoBio/urlesc"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8"
|
||||
name = "github.com/Sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
||||
version = "v1.0.5"
|
||||
pruneopts = "UT"
|
||||
revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
|
||||
name = "github.com/beorn7/perks"
|
||||
packages = ["quantile"]
|
||||
pruneopts = "UT"
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
pruneopts = "UT"
|
||||
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]]
|
||||
branch = "master"
|
||||
digest = "1:4c7d169280debf9f36b84a0f682094889cccc5dc0db8657f9cffc93b21975a57"
|
||||
name = "github.com/docker/distribution"
|
||||
packages = [
|
||||
"digestset",
|
||||
"reference"
|
||||
"reference",
|
||||
]
|
||||
revision = "749f6afb4572201e3c37325d0ffedb6f32be8950"
|
||||
pruneopts = "UT"
|
||||
revision = "6d62eb1d4a3515399431b713fde3ce5a9b40e8d5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ec821dda59d7dd340498d74f798aa218b2c782bba54a690e866dc4f520d900d5"
|
||||
name = "github.com/docker/docker"
|
||||
packages = [
|
||||
"api",
|
||||
@@ -74,338 +99,466 @@
|
||||
"pkg/ioutils",
|
||||
"pkg/longpath",
|
||||
"pkg/system",
|
||||
"pkg/tlsconfig"
|
||||
"pkg/tlsconfig",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "90d35abf7b3535c1c319c872900fbd76374e521c"
|
||||
version = "v17.05.0-ce-rc3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:02f8f4889e53a6adbc7bf3f2b9007ce8aecb0b79686fc9f99265246c88063f10"
|
||||
name = "github.com/docker/go-connections"
|
||||
packages = [
|
||||
"nat",
|
||||
"sockets",
|
||||
"tlsconfig"
|
||||
"tlsconfig",
|
||||
]
|
||||
revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55"
|
||||
pruneopts = "UT"
|
||||
revision = "97c2040d34dfae1d1b1275fa3a78dbdd2f41cf7e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18"
|
||||
name = "github.com/docker/go-units"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
|
||||
version = "v0.3.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4841e14252a2cecf11840bd05230412ad469709bbacfc12467e2ce5ad07f339b"
|
||||
name = "github.com/docker/libtrust"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8ee7b41ace3ba875c17e38ba7780e7cf0d29882338637861e9f13f04f60ecc5c"
|
||||
name = "github.com/emicklei/go-restful"
|
||||
packages = [
|
||||
".",
|
||||
"log"
|
||||
"log",
|
||||
]
|
||||
revision = "3658237ded108b4134956c1b3050349d93e7b895"
|
||||
version = "v2.7.1"
|
||||
pruneopts = "UT"
|
||||
revision = "85d198d05a92d31823b852b4a5928114912e8949"
|
||||
version = "v2.9.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8ba45daa43acfd9364068b118a6884cb82bc1ef0569dc05260f3b464907e07d9"
|
||||
name = "github.com/emicklei/go-restful-openapi"
|
||||
packages = ["."]
|
||||
revision = "51bf251d405ad1e23511fef0a2dbe40bc70ce2c6"
|
||||
version = "v0.11.0"
|
||||
pruneopts = "UT"
|
||||
revision = "b7062368c258c9e8f8cbe9dd2e6aebfa1b747be6"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda"
|
||||
name = "github.com/ghodss/yaml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-logr/logr"
|
||||
digest = "1:2a792dde3ae5dc95000d4dee312523504ea875b097a2b119a2f55d1d1d32ed61"
|
||||
name = "github.com/go-ldap/ldap"
|
||||
packages = ["."]
|
||||
revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e"
|
||||
pruneopts = "UT"
|
||||
revision = "729c20c2694d870bcd631f0dadaecd088bd7ccbc"
|
||||
version = "v3.0.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-logr/zapr"
|
||||
digest = "1:edd2fa4578eb086265db78a9201d15e76b298dfd0d5c379da83e9c61712cf6df"
|
||||
name = "github.com/go-logr/logr"
|
||||
packages = ["."]
|
||||
revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab"
|
||||
pruneopts = "UT"
|
||||
revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[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"
|
||||
packages = ["."]
|
||||
revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2"
|
||||
pruneopts = "UT"
|
||||
revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:81210e0af657a0fb3638932ec68e645236bceefa4c839823db0c4d918f080895"
|
||||
name = "github.com/go-openapi/jsonreference"
|
||||
packages = ["."]
|
||||
revision = "3fb327e6747da3043567ee86abd02bb6376b6be2"
|
||||
pruneopts = "UT"
|
||||
revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:08656ef9c5a45ddccb7f206ca2d67e12e9fcda4122a83dc0544b5c967267cefa"
|
||||
name = "github.com/go-openapi/spec"
|
||||
packages = ["."]
|
||||
revision = "bce47c9386f9ecd6b86f450478a80103c3fe1402"
|
||||
pruneopts = "UT"
|
||||
revision = "5b6cdde3200976e3ecceb2868706ee39b6aff3e4"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0005186c6608dd542239ac8e4f4f1e2e7c24d493e999113c46b93332f0362fc0"
|
||||
name = "github.com/go-openapi/swag"
|
||||
packages = ["."]
|
||||
revision = "2b0bd4f193d011c203529df626a65d63cb8a79e8"
|
||||
pruneopts = "UT"
|
||||
revision = "1d29f06aebd59ccdf11ae04aa0334ded96e2d909"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[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"
|
||||
packages = ["."]
|
||||
revision = "d523deb1b23d913de5bdada721a6071e71283618"
|
||||
version = "v1.4.0"
|
||||
pruneopts = "UT"
|
||||
revision = "72cd26f257d44c1114970e19afddcd812016007e"
|
||||
version = "v1.4.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4d02824a56d268f74a6b6fdd944b20b58a77c3d70e81008b3ee0c4f1a6777340"
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"sortkeys"
|
||||
"sortkeys",
|
||||
]
|
||||
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
|
||||
version = "v1.0.0"
|
||||
pruneopts = "UT"
|
||||
revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467"
|
||||
name = "github.com/golang/glog"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b7cb6054d3dff43b38ad2e92492f220f57ae6087ee797dca298139776749ace8"
|
||||
name = "github.com/golang/groupcache"
|
||||
packages = ["lru"]
|
||||
pruneopts = "UT"
|
||||
revision = "5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:239c4c7fd2159585454003d9be7207167970194216193a8a210b8d29576f19c9"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp"
|
||||
"ptypes/timestamp",
|
||||
]
|
||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
||||
version = "v1.1.0"
|
||||
pruneopts = "UT"
|
||||
revision = "c823c79ea1570fb5ff454033735a8e68575d1d0f"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0bfbe13936953a98ae3cfe8ed6670d396ad81edf069a806d2f6515d7bb6950df"
|
||||
name = "github.com/google/btree"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb"
|
||||
name = "github.com/google/gofuzz"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:582b704bebaa06b48c29b0cec224a6058a09c86883aaddabde889cd1a5f73e1b"
|
||||
name = "github.com/google/uuid"
|
||||
packages = ["."]
|
||||
revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8"
|
||||
version = "v1.1.0"
|
||||
pruneopts = "UT"
|
||||
revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21"
|
||||
name = "github.com/googleapis/gnostic"
|
||||
packages = [
|
||||
"OpenAPIv2",
|
||||
"compiler",
|
||||
"extensions"
|
||||
"extensions",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b4395b2a4566c24459af3d04009b39cc21762fc77ec7bf7a1aa905c91e8f018d"
|
||||
name = "github.com/gregjones/httpcache"
|
||||
packages = [
|
||||
".",
|
||||
"diskcache"
|
||||
"diskcache",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d15ee511aa0f56baacc1eb4c6b922fa1c03b38413b6be18166b996d82a0156ea"
|
||||
name = "github.com/hashicorp/golang-lru"
|
||||
packages = [
|
||||
".",
|
||||
"simplelru"
|
||||
"simplelru",
|
||||
]
|
||||
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
||||
pruneopts = "UT"
|
||||
revision = "7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c"
|
||||
version = "v0.5.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a0cefd27d12712af4b5018dc7046f245e1e3b5760e2e848c30b171b570708f9b"
|
||||
name = "github.com/imdario/mergo"
|
||||
packages = ["."]
|
||||
revision = "9316a62528ac99aaecb4e47eadd6dc8aa6533d58"
|
||||
version = "v0.3.5"
|
||||
pruneopts = "UT"
|
||||
revision = "7c29201646fa3de8506f701213473dd407f19646"
|
||||
version = "v0.3.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d4e6e8584d0a94ce567d237e19192dae44d57d2767ac7e1d7fbf5626d176381a"
|
||||
name = "github.com/jinzhu/gorm"
|
||||
packages = ["."]
|
||||
revision = "6ed508ec6a4ecb3531899a69cbc746ccf65a4166"
|
||||
version = "v1.9.1"
|
||||
pruneopts = "UT"
|
||||
revision = "472c70caa40267cb89fd8facb07fe6454b578626"
|
||||
version = "v1.9.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:fd97437fbb6b7dce04132cf06775bd258cce305c44add58eb55ca86c6c325160"
|
||||
name = "github.com/jinzhu/inflection"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "04140366298a54a039076d798123ffa108fff46c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f5a2051c55d05548d2d4fd23d244027b59fbd943217df8aa3b5e170ac2fd6e1b"
|
||||
name = "github.com/json-iterator/go"
|
||||
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]]
|
||||
branch = "master"
|
||||
digest = "1:84a5a2b67486d5d67060ac393aa255d05d24ed5ee41daecd5635ec22657b6492"
|
||||
name = "github.com/mailru/easyjson"
|
||||
packages = [
|
||||
"buffer",
|
||||
"jlexer",
|
||||
"jwriter"
|
||||
"jwriter",
|
||||
]
|
||||
revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485"
|
||||
pruneopts = "UT"
|
||||
revision = "6243d8e04c3f819e79757e8bc3faa15c3cb27003"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:fc2b04b0069d6b10bdef96d278fe20c345794009685ed3c8c7f1a6dc023eefec"
|
||||
name = "github.com/mattbaird/jsonpatch"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
pruneopts = "UT"
|
||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
|
||||
name = "github.com/modern-go/concurrent"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
||||
version = "1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
|
||||
name = "github.com/modern-go/reflect2"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
||||
version = "1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ee4d4af67d93cc7644157882329023ce9a7bcfce956a079069a9405521c7cc8d"
|
||||
name = "github.com/opencontainers/go-digest"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
||||
version = "v1.0.0-rc1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e5d0bd87abc2781d14e274807a470acd180f0499f8bf5bb18606e9ec22ad9de9"
|
||||
name = "github.com/pborman/uuid"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
|
||||
version = "v1.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2"
|
||||
name = "github.com/petar/GoLLRB"
|
||||
packages = ["llrb"]
|
||||
pruneopts = "UT"
|
||||
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0e7775ebbcf00d8dd28ac663614af924411c868dca3d5aa762af0fae3808d852"
|
||||
name = "github.com/peterbourgon/diskv"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
|
||||
version = "v2.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
pruneopts = "UT"
|
||||
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||
version = "v0.8.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:93a746f1060a8acbcf69344862b2ceced80f854170e1caae089b2834c5fbf7f4"
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = [
|
||||
"prometheus",
|
||||
"prometheus/internal",
|
||||
"prometheus/promhttp"
|
||||
"prometheus/promhttp",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "505eaef017263e299324067d40ca2c48f6a2cf50"
|
||||
version = "v0.9.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
|
||||
name = "github.com/prometheus/client_model"
|
||||
packages = ["go"]
|
||||
pruneopts = "UT"
|
||||
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:35cf6bdf68db765988baa9c4f10cc5d7dda1126a54bd62e252dbcd0b1fc8da90"
|
||||
name = "github.com/prometheus/common"
|
||||
packages = [
|
||||
"expfmt",
|
||||
"internal/bitbucket.org/ww/goautoneg",
|
||||
"model"
|
||||
"model",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:01cd0cd47758f04c5604daa3be4637e2afa1e0c15af7e08289e95360369e4f48"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [
|
||||
".",
|
||||
"internal/util",
|
||||
"iostats",
|
||||
"nfs",
|
||||
"xfs"
|
||||
"xfs",
|
||||
]
|
||||
revision = "bbced9601137e764853b2fad7ec3e2dc4c504e02"
|
||||
pruneopts = "UT"
|
||||
revision = "d0f344d83b0c80a1bc03b547a2374a9ec6711144"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||
version = "v1.0.1"
|
||||
pruneopts = "UT"
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d"
|
||||
name = "go.uber.org/atomic"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
|
||||
version = "v1.3.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:60bf2a5e347af463c42ed31a493d817f8a72f102543060ed992754e689805d1a"
|
||||
name = "go.uber.org/multierr"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c52caf7bd44f92e54627a31b85baf06a68333a196b3d8d241480a774733dcf8b"
|
||||
name = "go.uber.org/zap"
|
||||
packages = [
|
||||
".",
|
||||
@@ -413,19 +566,23 @@
|
||||
"internal/bufferpool",
|
||||
"internal/color",
|
||||
"internal/exit",
|
||||
"zapcore"
|
||||
"zapcore",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
|
||||
version = "v1.9.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:058e9504b9a79bfe86092974d05bb3298d2aa0c312d266d43148de289a5065d9"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
revision = "7f39a6fea4fe9364fb61e1def6a268a51b4f3a06"
|
||||
pruneopts = "UT"
|
||||
revision = "c2843e01d9a2bc60bb26ad24e09734fdc2d9ec58"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:348e38852dac5030f8ce455e1b8d7a5727bbe0af43c0664efd89ec32414093c0"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
@@ -435,32 +592,38 @@
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/socks",
|
||||
"proxy"
|
||||
"proxy",
|
||||
]
|
||||
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
|
||||
pruneopts = "UT"
|
||||
revision = "56fb01167e7d1e1d17dd87993d34c963f4356e87"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5e9f22cf754ab20a5dff0ae04b12516b112c5b81cd44dccccde148865084d730"
|
||||
name = "golang.org/x/oauth2"
|
||||
packages = [
|
||||
".",
|
||||
"google",
|
||||
"internal",
|
||||
"jws",
|
||||
"jwt"
|
||||
"jwt",
|
||||
]
|
||||
revision = "9b3c75971fc92dd27c6436a37c05c831498658f1"
|
||||
pruneopts = "UT"
|
||||
revision = "e64efc72b421e893cbf63f17ba2221e7d6d0b0f3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:85cd5224b89829559e8327ba2e52e0df72638d33cf3082b066ea9dea34391e2f"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows"
|
||||
"windows",
|
||||
]
|
||||
revision = "fc8bd948cf46f9c7af0f07d34151ce25fe90e477"
|
||||
pruneopts = "UT"
|
||||
revision = "10058d7d4faa7dd5ef860cbd31af00903076e7b8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0c56024909189aee3364b7f21a95a27459f718aa7c199a5c111c36cfffd9eaef"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
@@ -477,24 +640,30 @@
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable",
|
||||
"width"
|
||||
"width",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90"
|
||||
name = "golang.org/x/time"
|
||||
packages = ["rate"]
|
||||
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
|
||||
pruneopts = "UT"
|
||||
revision = "9d24e82272b4f38b78bc8cff74fa936d31ccd8ef"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:6bb2e1cbcf253307a88a531a75aa4d38fecb8d56a0dc9e837e288fe3189954f6"
|
||||
name = "golang.org/x/tools"
|
||||
packages = ["container/intsets"]
|
||||
revision = "44bee7e801e4a70b5fc9a91ff23830ab4df55d5e"
|
||||
pruneopts = "UT"
|
||||
revision = "00c44ba9c14f88ffdd4fb5bfae57fe8dd6d6afb1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7bc25c2efff76b31f146caf630c617be9b666c6164f0632050466fbec0500125"
|
||||
name = "google.golang.org/appengine"
|
||||
packages = [
|
||||
".",
|
||||
@@ -507,24 +676,38 @@
|
||||
"internal/modules",
|
||||
"internal/remote_api",
|
||||
"internal/urlfetch",
|
||||
"urlfetch"
|
||||
"urlfetch",
|
||||
]
|
||||
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
|
||||
version = "v1.1.0"
|
||||
pruneopts = "UT"
|
||||
revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[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"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
|
||||
version = "v0.9.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
pruneopts = "UT"
|
||||
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
||||
version = "v2.2.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:26a67eb988225c6a0600c1af0b35e795ac4d23a9c40a7aa178fa2adc0670f1f7"
|
||||
name = "k8s.io/api"
|
||||
packages = [
|
||||
"admission/v1beta1",
|
||||
@@ -558,12 +741,14 @@
|
||||
"settings/v1alpha1",
|
||||
"storage/v1",
|
||||
"storage/v1alpha1",
|
||||
"storage/v1beta1"
|
||||
"storage/v1beta1",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "b503174bad5991eb66f18247f52e41c3258f6348"
|
||||
version = "kubernetes-1.12.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3c38a27df3152aa083018cb7a8d7b5bd5af5e808733ebbc6ae5b5fe10f8b0f84"
|
||||
name = "k8s.io/apimachinery"
|
||||
packages = [
|
||||
"pkg/api/errors",
|
||||
@@ -609,12 +794,27 @@
|
||||
"pkg/version",
|
||||
"pkg/watch",
|
||||
"third_party/forked/golang/json",
|
||||
"third_party/forked/golang/reflect"
|
||||
"third_party/forked/golang/reflect",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "eddba98df674a16931d2d4ba75edc3a389bf633a"
|
||||
version = "kubernetes-1.12.3"
|
||||
|
||||
[[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"
|
||||
packages = [
|
||||
"discovery",
|
||||
@@ -754,36 +954,30 @@
|
||||
"util/integer",
|
||||
"util/jsonpath",
|
||||
"util/retry",
|
||||
"util/workqueue"
|
||||
"util/workqueue",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "d082d5923d3cc0bfbb066ee5fbdea3d0ca79acf8"
|
||||
version = "kubernetes-1.12.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "k8s.io/component-base"
|
||||
packages = ["logs"]
|
||||
revision = "1925c57e3358154fd54383773de0c0c7710a9196"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/klog"
|
||||
packages = ["."]
|
||||
revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:20ca56a1299fe3787b1cf86c3a0388fbc11d08604783b32a258eca7a947a7fdb"
|
||||
name = "k8s.io/kube-openapi"
|
||||
packages = ["pkg/util/proto"]
|
||||
revision = "d50a959ae76a85c7c262a9767ef29f37093c2b8a"
|
||||
pruneopts = "UT"
|
||||
revision = "15615b16d372105f0c69ff47dfe7402926a65aaa"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ceff1906e568c23d7a337fdda89900d6155aaf93db7cb6da73488ffb649641e1"
|
||||
name = "k8s.io/kubernetes"
|
||||
packages = ["pkg/util/slice"]
|
||||
revision = "721bfa751924da8d1680787490c54b9179b1fed0"
|
||||
version = "v1.13.3"
|
||||
pruneopts = "UT"
|
||||
revision = "c27b913fddd1a6c480c229191a087698aa92f0b1"
|
||||
version = "v1.13.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3c56f356b5cb581860246ca0c08c7a35aa21b2c071b20c428a53b2c3c13c87fd"
|
||||
name = "sigs.k8s.io/controller-runtime"
|
||||
packages = [
|
||||
"pkg/cache",
|
||||
@@ -803,14 +997,68 @@
|
||||
"pkg/webhook/admission",
|
||||
"pkg/webhook/admission/types",
|
||||
"pkg/webhook/internal/metrics",
|
||||
"pkg/webhook/types"
|
||||
"pkg/webhook/types",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "f6f0bc9611363b43664d08fb097ab13243ef621d"
|
||||
version = "v0.1.9"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
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-version = 1
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
# go-tests = 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]]
|
||||
name = "github.com/docker/docker"
|
||||
version = "v17.05.0-ce"
|
||||
|
||||
28
build/ks-apigateway/Dockerfile
Normal file
28
build/ks-apigateway/Dockerfile
Normal 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"]
|
||||
18
build/ks-apiserver/Dockerfile
Normal file
18
build/ks-apiserver/Dockerfile
Normal 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
18
build/ks-iam/Dockerfile
Normal 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"]
|
||||
@@ -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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/cmd/ks-apiserver/app"
|
||||
"os"
|
||||
|
||||
"log"
|
||||
// Install apis
|
||||
_ "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/resources/install"
|
||||
)
|
||||
@@ -16,7 +32,6 @@ func main() {
|
||||
cmd := app.NewAPIServerCommand()
|
||||
|
||||
if err := cmd.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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
|
||||
|
||||
import (
|
||||
goflag "flag"
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
"kubesphere.io/kubesphere/cmd/ks-apiserver/app/options"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/filter"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/options"
|
||||
"kubesphere.io/kubesphere/pkg/signals"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func NewAPIServerCommand() *cobra.Command {
|
||||
s := options.NewServerRunOptions()
|
||||
s := options.SharedOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
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
|
||||
cluster's shared state through which all other components interact.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
//s.AddFlags(cmd.Flags())
|
||||
|
||||
return Run(s)
|
||||
},
|
||||
}
|
||||
|
||||
s.AddFlags(cmd.Flags())
|
||||
|
||||
cmd.Flags().AddFlagSet(s.CommandLine)
|
||||
cmd.Flags().AddGoFlagSet(goflag.CommandLine)
|
||||
glog.CopyStandardLogTo("INFO")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -39,26 +54,11 @@ func Run(s *options.ServerRunOptions) error {
|
||||
|
||||
var err error
|
||||
|
||||
stopChan := signals.SetupSignalHandler()
|
||||
informers.SharedInformerFactory().Start(stopChan)
|
||||
informers.SharedInformerFactory().WaitForCacheSync(stopChan)
|
||||
log.Println("resources sync success")
|
||||
waitForResourceSync()
|
||||
|
||||
container := runtime.Container
|
||||
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)
|
||||
|
||||
if s.InsecurePort != 0 {
|
||||
@@ -71,3 +71,36 @@ func Run(s *options.ServerRunOptions) error {
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -15,12 +15,20 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package v1alpha2
|
||||
package main
|
||||
|
||||
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() {
|
||||
addToWebServiceFuncs = append(addToWebServiceFuncs, monitoring.Route)
|
||||
func main() {
|
||||
|
||||
cmd := app.NewAPIServerCommand()
|
||||
|
||||
if err := cmd.Execute(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
95
cmd/ks-iam/app/server.go
Normal file
95
cmd/ks-iam/app/server.go
Normal 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
4
hack/docker_build.sh
Executable 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 .
|
||||
@@ -3,4 +3,5 @@
|
||||
# Push image to dockerhub, need to support multiple push
|
||||
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
docker push kubespheredev/ks-apiserver:latest
|
||||
docker push kubespheredev/ks-apigateway:latest
|
||||
docker push kubespheredev/ks-apiserver:latest
|
||||
|
||||
172
pkg/apigateway/caddy-plugin/authenticate/authenticate.go
Normal file
172
pkg/apigateway/caddy-plugin/authenticate/authenticate.go
Normal 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"])
|
||||
}
|
||||
}
|
||||
110
pkg/apigateway/caddy-plugin/authenticate/auto_load.go
Normal file
110
pkg/apigateway/caddy-plugin/authenticate/auto_load.go
Normal 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
|
||||
}
|
||||
300
pkg/apigateway/caddy-plugin/authentication/authentication.go
Normal file
300
pkg/apigateway/caddy-plugin/authentication/authentication.go
Normal 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
|
||||
}
|
||||
119
pkg/apigateway/caddy-plugin/authentication/auto_load.go
Normal file
119
pkg/apigateway/caddy-plugin/authentication/auto_load.go
Normal 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
|
||||
}
|
||||
100
pkg/apigateway/caddy-plugin/swagger/auto_load.go
Normal file
100
pkg/apigateway/caddy-plugin/swagger/auto_load.go
Normal 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
|
||||
}
|
||||
45
pkg/apigateway/caddy-plugin/swagger/swagger.go
Normal file
45
pkg/apigateway/caddy-plugin/swagger/swagger.go
Normal 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)
|
||||
}
|
||||
@@ -15,17 +15,19 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package monitoring
|
||||
package install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/monitoring/v1alpha2"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
)
|
||||
|
||||
const apiGroup = "monitoring.kubesphere.io"
|
||||
|
||||
func AddToContainer(container *restful.Container) error {
|
||||
container.Add(v1alpha2.WebService(apiGroup))
|
||||
return nil
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(iamv1alpha2.AddToContainer(container))
|
||||
}
|
||||
214
pkg/apis/iam/v1alpha2/register.go
Normal file
214
pkg/apis/iam/v1alpha2/register.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
@@ -19,6 +19,7 @@ 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/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
@@ -36,8 +37,20 @@ var (
|
||||
func addWebService(c *restful.Container) error {
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
|
||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}").To(metrics.GetScMetrics))
|
||||
webservice.Route(webservice.GET("/metrics/storageclass").To(metrics.GetScMetricsList))
|
||||
tags := []string{"metrics"}
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -15,22 +15,19 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package v1alpha2
|
||||
package install
|
||||
|
||||
import (
|
||||
"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"
|
||||
|
||||
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 init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(monitoringv1alpha2.AddToContainer(container))
|
||||
}
|
||||
207
pkg/apis/monitoring/v1alpha2/register.go
Normal file
207
pkg/apis/monitoring/v1alpha2/register.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/operations"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
const GroupName = "operations.kubesphere.io"
|
||||
@@ -36,20 +37,24 @@ var (
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
|
||||
tags := []string{"Operations"}
|
||||
|
||||
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}").
|
||||
To(operations.RerunJob).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{"jobs"}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Doc("Handle job operation").
|
||||
Param(webservice.PathParameter("job", "job name").
|
||||
DataType("string")).
|
||||
Param(webservice.PathParameter("namespace", "job's namespace").
|
||||
DataType("string")).
|
||||
Param(webservice.QueryParameter("a", "action").
|
||||
DataType("string")).
|
||||
Param(webservice.PathParameter("job", "job name")).
|
||||
Param(webservice.PathParameter("namespace", "job's namespace")).
|
||||
Param(webservice.QueryParameter("a", "action")).
|
||||
Writes(""))
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
@@ -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
|
||||
@@ -20,9 +20,20 @@ package v1alpha2
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"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/revisions"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/routers"
|
||||
"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"
|
||||
@@ -38,18 +49,182 @@ func addWebService(c *restful.Container) error {
|
||||
|
||||
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))
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").To(resources.GetPodListByPvc))
|
||||
tags = []string{"Cluster resources"}
|
||||
|
||||
tags := []string{"users"}
|
||||
webservice.Route(webservice.GET("/users/{username}/kubectl").Doc("get user's kubectl pod").Param(webservice.PathParameter("username",
|
||||
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubectl))
|
||||
webservice.Route(webservice.GET("/users/{username}/kubeconfig").Doc("get users' kubeconfig").Param(webservice.PathParameter("username",
|
||||
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubeconfig))
|
||||
webservice.Route(webservice.GET("/{resources}").
|
||||
To(resources.ClusterResourceHandler).
|
||||
Writes(models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
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)
|
||||
|
||||
|
||||
@@ -22,18 +22,14 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/components"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
ws.Route(ws.GET("/components").To(getComponents))
|
||||
ws.Route(ws.GET("/components/{component}").To(getComponentStatus))
|
||||
ws.Route(ws.GET("/health").To(getSystemHealthStatus))
|
||||
}
|
||||
func GetSystemHealthStatus(request *restful.Request, response *restful.Response) {
|
||||
result, err := components.GetSystemHealthStatus()
|
||||
|
||||
func getSystemHealthStatus(request *restful.Request, response *restful.Response) {
|
||||
result, err := components.GetAllComponentsStatus()
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -41,12 +37,13 @@ func getSystemHealthStatus(request *restful.Request, response *restful.Response)
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
result, err := components.GetComponentStatus(component)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -54,11 +51,12 @@ func getComponentStatus(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// get all componentsHandler
|
||||
func getComponents(request *restful.Request, response *restful.Response) {
|
||||
func GetComponents(request *restful.Request, response *restful.Response) {
|
||||
|
||||
result, err := components.GetAllComponentsStatus()
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -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
190
pkg/apiserver/iam/am.go
Normal 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
142
pkg/apiserver/iam/auth.go
Normal 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
253
pkg/apiserver/iam/groups.go
Normal 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
365
pkg/apiserver/iam/users.go
Normal 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})
|
||||
}
|
||||
746
pkg/apiserver/iam/workspaces.go
Normal file
746
pkg/apiserver/iam/workspaces.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,10 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/storage"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type scMetricsItem struct {
|
||||
type ScMetricsItem struct {
|
||||
Name string `json:"name"`
|
||||
Metrics *storage.ScMetrics `json:"metrics"`
|
||||
}
|
||||
@@ -35,11 +36,12 @@ func GetScMetrics(request *restful.Request, response *restful.Response) {
|
||||
|
||||
metrics, err := storage.GetScMetrics(scName)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := scMetricsItem{
|
||||
result := ScMetricsItem{
|
||||
Name: scName, Metrics: metrics,
|
||||
}
|
||||
|
||||
@@ -51,21 +53,23 @@ func GetScMetrics(request *restful.Request, response *restful.Response) {
|
||||
func GetScMetricsList(request *restful.Request, response *restful.Response) {
|
||||
scList, err := storage.GetScList()
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
// Set return value
|
||||
items := make([]scMetricsItem, 0)
|
||||
items := make([]ScMetricsItem, 0)
|
||||
|
||||
for _, v := range scList {
|
||||
metrics, err := storage.GetScMetrics(v.GetName())
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
item := scMetricsItem{
|
||||
item := ScMetricsItem{
|
||||
Name: v.GetName(), Metrics: metrics,
|
||||
}
|
||||
|
||||
|
||||
220
pkg/apiserver/monitoring/monitoring.go
Normal file
220
pkg/apiserver/monitoring/monitoring.go
Normal 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)
|
||||
}
|
||||
@@ -19,10 +19,9 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/workloads"
|
||||
"net/http"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
@@ -40,10 +39,11 @@ func RerunJob(req *restful.Request, resp *restful.Response) {
|
||||
case "rerun":
|
||||
err = workloads.JobReRun(namespace, job)
|
||||
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
|
||||
}
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package operations
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/nodes"
|
||||
@@ -31,7 +32,8 @@ func DrainNode(request *restful.Request, response *restful.Response) {
|
||||
|
||||
err := nodes.DrainNode(nodeName)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -20,48 +20,30 @@ package quotas
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/quotas"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
|
||||
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) {
|
||||
func GetNamespaceQuotas(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
quota, err := quotas.GetNamespaceQuotas(namespace)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(quota)
|
||||
}
|
||||
|
||||
func getClusterQuotas(req *restful.Request, resp *restful.Response) {
|
||||
func GetClusterQuotas(req *restful.Request, resp *restful.Response) {
|
||||
quota, err := quotas.GetClusterQuotas()
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -20,55 +20,29 @@ package registries
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/registries"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
|
||||
ws.Route(ws.POST("registries/verify").To(registryVerify))
|
||||
|
||||
}
|
||||
|
||||
func registryVerify(request *restful.Request, response *restful.Response) {
|
||||
func RegistryVerify(request *restful.Request, response *restful.Response) {
|
||||
|
||||
authInfo := registries.AuthInfo{}
|
||||
|
||||
err := request.ReadEntity(&authInfo)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = registries.RegistryVerify(authInfo)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
//}
|
||||
|
||||
@@ -19,6 +19,7 @@ package resources
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
@@ -27,14 +28,15 @@ import (
|
||||
|
||||
func ClusterResourceHandler(req *restful.Request, resp *restful.Response) {
|
||||
resourceName := req.PathParameter("resources")
|
||||
conditions := req.QueryParameter(params.Conditions)
|
||||
orderBy := req.QueryParameter(params.OrderBy)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging))
|
||||
reverse := params.ParseReserve(req.QueryParameter(params.Reserve))
|
||||
conditions, err := params.ParseConditions(req)
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package resources
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
@@ -28,14 +29,15 @@ import (
|
||||
func NamespaceResourceHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
resourceName := req.PathParameter("resources")
|
||||
conditions := req.QueryParameter(params.Conditions)
|
||||
orderBy := req.QueryParameter(params.OrderBy)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging))
|
||||
reverse := params.ParseReserve(req.QueryParameter(params.Reserve))
|
||||
conditions, err := params.ParseConditions(req)
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package resources
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/core/v1"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/storage"
|
||||
@@ -43,7 +44,8 @@ func GetPodListByPvc(request *restful.Request, response *restful.Response) {
|
||||
pvcName := request.PathParameter("pvc")
|
||||
nsName := request.PathParameter("namespace")
|
||||
pods, err := storage.GetPodListByPvc(pvcName, nsName)
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
result := podListByPvc{Name: pvcName, Namespace: nsName, Pods: pods}
|
||||
@@ -56,7 +58,8 @@ func GetPvcListBySc(request *restful.Request, response *restful.Response) {
|
||||
scName := request.PathParameter("storageclass")
|
||||
claims, err := storage.GetPvcListBySc(scName)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package resources
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
|
||||
@@ -31,7 +32,8 @@ func GetKubectl(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
kubectlPod, err := kubectl.GetKubectlPod(user)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -44,7 +46,8 @@ func GetKubeconfig(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
kubectlConfig, err := kubeconfig.GetKubeConfig(user)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -22,93 +22,59 @@ import (
|
||||
"strconv"
|
||||
|
||||
"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/models/revisions"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
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) {
|
||||
func GetDaemonSetRevision(req *restful.Request, resp *restful.Response) {
|
||||
daemonset := req.PathParameter("daemonset")
|
||||
namespace := req.PathParameter("namespace")
|
||||
revision, err := strconv.Atoi(req.PathParameter("revision"))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := revisions.GetDaemonSetRevision(namespace, daemonset, revision)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func getDeployRevision(req *restful.Request, resp *restful.Response) {
|
||||
func GetDeployRevision(req *restful.Request, resp *restful.Response) {
|
||||
deploy := req.PathParameter("deployment")
|
||||
namespace := req.PathParameter("namespace")
|
||||
revision := req.PathParameter("revision")
|
||||
|
||||
result, err := revisions.GetDeployRevision(namespace, deploy, revision)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func getStatefulSetRevision(req *restful.Request, resp *restful.Response) {
|
||||
func GetStatefulSetRevision(req *restful.Request, resp *restful.Response) {
|
||||
statefulset := req.PathParameter("statefulset")
|
||||
namespace := req.PathParameter("namespace")
|
||||
revision, err := strconv.Atoi(req.PathParameter("revision"))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := revisions.GetStatefulSetRevision(namespace, statefulset, revision)
|
||||
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -19,58 +19,31 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"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 {
|
||||
RouterType string `json:"type"`
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -78,13 +51,14 @@ func getAllRouters(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
routers, err := routers.GetAllRoutersOfUser(username)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -92,12 +66,13 @@ func getAllRoutersOfUser(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// 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")
|
||||
router, err := routers.GetRouter(namespace)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -105,7 +80,7 @@ func getRouter(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
@@ -119,18 +94,17 @@ func createRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
var router *v1.Service
|
||||
|
||||
serviceType, annotationMap, err := ParseParameter(newRouter)
|
||||
serviceType, annotationMap, err := parseParameter(newRouter)
|
||||
|
||||
if err != nil {
|
||||
glog.Error("Wrong annotations, missing key or value")
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest,
|
||||
errors.New(errors.InvalidArgument, "Wrong annotations, missing key or value"))
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("wrong annotations, missing key or value")))
|
||||
return
|
||||
}
|
||||
|
||||
router, err = routers.CreateRouter(namespace, serviceType, annotationMap)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -138,19 +112,20 @@ func createRouter(request *restful.Request, response *restful.Response) {
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
router, err := routers.DeleteRouter(namespace)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteAsJson(router)
|
||||
}
|
||||
|
||||
func updateRouter(request *restful.Request, response *restful.Response) {
|
||||
func UpdateRouter(request *restful.Request, response *restful.Response) {
|
||||
|
||||
namespace := request.PathParameter("namespace")
|
||||
|
||||
@@ -158,23 +133,23 @@ func updateRouter(request *restful.Request, response *restful.Response) {
|
||||
err := request.ReadEntity(&newRouter)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
||||
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
serviceType, annotationMap, err := ParseParameter(newRouter)
|
||||
serviceType, annotationMap, err := parseParameter(newRouter)
|
||||
|
||||
router, err := routers.UpdateRouter(namespace, serviceType, annotationMap)
|
||||
|
||||
if errors.HandlerError(err, response) {
|
||||
if err != nil {
|
||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@ type ContainerBuilder []func(c *restful.Container) error
|
||||
func NewWebService(gv schema.GroupVersion) *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
|
||||
}
|
||||
|
||||
@@ -20,39 +20,25 @@ package workloadstatuses
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/status"
|
||||
)
|
||||
|
||||
func V1Alpha2(ws *restful.WebService) {
|
||||
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) {
|
||||
func GetClusterResourceStatus(req *restful.Request, resp *restful.Response) {
|
||||
res, err := status.GetClusterResourceStatus()
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
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"))
|
||||
if errors.HandlerError(err, resp) {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(res)
|
||||
|
||||
@@ -16,491 +16,3 @@
|
||||
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -1,51 +1,56 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
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 (
|
||||
"fmt"
|
||||
"flag"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/golang/glog"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
var dbClient *gorm.DB
|
||||
var (
|
||||
dbClientOnce sync.Once
|
||||
dbClient *gorm.DB
|
||||
dsn string
|
||||
)
|
||||
|
||||
func NewDBClient() *gorm.DB {
|
||||
conn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", "", "", "", "")
|
||||
|
||||
db, err := gorm.Open("mysql", conn)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
panic(err)
|
||||
}
|
||||
return db
|
||||
func init() {
|
||||
flag.StringVar(&dsn, "database-connection", "root@tcp(localhost:3306)/kubesphere?charset=utf8&parseTime=True", "data source name")
|
||||
}
|
||||
|
||||
func NewSharedDBClient() *gorm.DB {
|
||||
func DBClient() *gorm.DB {
|
||||
dbClientOnce.Do(func() {
|
||||
var err error
|
||||
dbClient, err = gorm.Open("mysql", dsn)
|
||||
|
||||
if dbClient != nil {
|
||||
err := dbClient.DB().Ping()
|
||||
if err == nil {
|
||||
return dbClient
|
||||
} else {
|
||||
glog.Error(err)
|
||||
panic(err)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
return NewDBClient()
|
||||
if err := dbClient.DB().Ping(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
})
|
||||
|
||||
return dbClient
|
||||
|
||||
}
|
||||
|
||||
@@ -19,25 +19,31 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
var (
|
||||
KubeConfigFile string
|
||||
kubeConfigFile string
|
||||
k8sClient *kubernetes.Clientset
|
||||
k8sClientOnce sync.Once
|
||||
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 {
|
||||
|
||||
k8sClientOnce.Do(func() {
|
||||
@@ -45,14 +51,10 @@ func K8sClient() *kubernetes.Clientset {
|
||||
config, err := getKubeConfig()
|
||||
|
||||
if err != nil {
|
||||
glog.Fatalf("cannot load kubeconfig: %v", err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
k8sClient, err = kubernetes.NewForConfig(config)
|
||||
|
||||
if err != nil {
|
||||
glog.Fatalf("cannot create k8s client: %v", err)
|
||||
}
|
||||
k8sClient = kubernetes.NewForConfigOrDie(config)
|
||||
|
||||
KubeConfig = config
|
||||
})
|
||||
@@ -62,36 +64,28 @@ func K8sClient() *kubernetes.Clientset {
|
||||
|
||||
func getKubeConfig() (kubeConfig *rest.Config, err error) {
|
||||
|
||||
if KubeConfigFile == "" {
|
||||
if kubeConfigFile == "" {
|
||||
if env := os.Getenv("KUBECONFIG"); env != "" {
|
||||
KubeConfigFile = env
|
||||
kubeConfigFile = env
|
||||
} else {
|
||||
if home, err := homedir.Dir(); err == nil {
|
||||
KubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
|
||||
kubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if KubeConfigFile != "" {
|
||||
|
||||
kubeConfig, err = clientcmd.BuildConfigFromFlags("", KubeConfigFile)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = os.Stat(kubeConfigFile); err == nil {
|
||||
kubeConfig, err = clientcmd.BuildConfigFromFlags("", kubeConfigFile)
|
||||
} else {
|
||||
|
||||
kubeConfig, err = rest.InClusterConfig()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kubeConfig.QPS = 1e6
|
||||
kubeConfig.Burst = 1e6
|
||||
|
||||
return kubeConfig, nil
|
||||
|
||||
}
|
||||
|
||||
188
pkg/client/ldap/channel.go
Normal file
188
pkg/client/ldap/channel.go
Normal 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
113
pkg/client/ldap/conn.go
Normal 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
43
pkg/client/ldap/pool.go
Normal 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
65
pkg/client/ldapclient.go
Normal 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
|
||||
}
|
||||
@@ -1,18 +1,24 @@
|
||||
/*
|
||||
Copyright 2018 The KubeSphere Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
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"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -20,31 +26,23 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultScheme = "http"
|
||||
DefaultPrometheusPort = "9090"
|
||||
PrometheusApiPath = "/api/v1/"
|
||||
DefaultQueryStep = "10m"
|
||||
DefaultQueryTimeout = "10s"
|
||||
RangeQueryType = "query_range?"
|
||||
DefaultQueryType = "query?"
|
||||
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
|
||||
DefaultQueryStep = "10m"
|
||||
DefaultQueryTimeout = "10s"
|
||||
RangeQueryType = "query_range?"
|
||||
DefaultQueryType = "query?"
|
||||
)
|
||||
|
||||
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
|
||||
var PrometheusEndpointUrl string
|
||||
var (
|
||||
prometheusAPIEndpoint string
|
||||
)
|
||||
|
||||
func init() {
|
||||
if env := os.Getenv(PrometheusAPIServerEnv); env != "" {
|
||||
PrometheusAPIServer = env
|
||||
}
|
||||
PrometheusEndpointUrl = DefaultScheme + "://" + PrometheusAPIServer + ":" + DefaultPrometheusPort + PrometheusApiPath
|
||||
flag.StringVar(&prometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
|
||||
}
|
||||
|
||||
type MonitoringRequestParams struct {
|
||||
@@ -72,11 +70,10 @@ type MonitoringRequestParams struct {
|
||||
WorkloadKind string
|
||||
}
|
||||
|
||||
var client = &http.Client{}
|
||||
|
||||
func SendMonitoringRequest(queryType string, params string) string {
|
||||
epurl := PrometheusEndpointUrl + queryType + params
|
||||
response, err := client.Get(epurl)
|
||||
epurl := prometheusAPIEndpoint + queryType + params
|
||||
|
||||
response, err := http.DefaultClient.Get(epurl)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
@@ -116,11 +113,11 @@ func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestPa
|
||||
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
|
||||
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
|
||||
|
||||
nodeId := strings.Trim(request.PathParameter("node_id"), " ")
|
||||
wsName := strings.Trim(request.PathParameter("workspace_name"), " ")
|
||||
nsName := strings.Trim(request.PathParameter("ns_name"), " ")
|
||||
podName := strings.Trim(request.PathParameter("pod_name"), " ")
|
||||
containerName := strings.Trim(request.PathParameter("container_name"), " ")
|
||||
nodeId := strings.Trim(request.PathParameter("node"), " ")
|
||||
wsName := strings.Trim(request.PathParameter("workspace"), " ")
|
||||
nsName := strings.Trim(request.PathParameter("namespace"), " ")
|
||||
podName := strings.Trim(request.PathParameter("pod"), " ")
|
||||
containerName := strings.Trim(request.PathParameter("container"), " ")
|
||||
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
|
||||
|
||||
var requestParams = MonitoringRequestParams{
|
||||
|
||||
56
pkg/client/redis.go
Normal file
56
pkg/client/redis.go
Normal 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
|
||||
}
|
||||
@@ -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 (
|
||||
APIVersion = "v1alpha1"
|
||||
@@ -24,32 +39,18 @@ const (
|
||||
DevopsOwner = "owner"
|
||||
DevopsReporter = "reporter"
|
||||
|
||||
DevopsAPIServerEnv = "DEVOPS_API_SERVER"
|
||||
AccountAPIServerEnv = "ACCOUNT_API_SERVER"
|
||||
DevopsProxyTokenEnv = "DEVOPS_PROXY_TOKEN"
|
||||
OpenPitrixProxyTokenEnv = "OPENPITRIX_PROXY_TOKEN"
|
||||
envDevopsAPIServer = "DEVOPS_API_SERVER"
|
||||
envAccountAPIServer = "ACCOUNT_API_SERVER"
|
||||
envDevopsProxyToken = "DEVOPS_PROXY_TOKEN"
|
||||
envOpenPitrixProxyToken = "OPENPITRIX_PROXY_TOKEN"
|
||||
|
||||
UserNameHeader = "X-Token-Username"
|
||||
)
|
||||
|
||||
var (
|
||||
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
||||
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
|
||||
AccountAPIServer = "ks-account.kubesphere-system.svc"
|
||||
DevopsProxyToken = ""
|
||||
OpenPitrixProxyToken = ""
|
||||
SystemNamespaces = []string{KubeSystemNamespace, OpenPitrixNamespace, KubeSystemNamespace}
|
||||
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
||||
SystemWorkspace = "system-workspace"
|
||||
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
|
||||
AccountAPIServer = "ks-account.kubesphere-system.svc"
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package errors
|
||||
|
||||
type Code int
|
||||
|
||||
const (
|
||||
OK Code = iota
|
||||
Canceled
|
||||
Unknown
|
||||
InvalidArgument
|
||||
Internal // 5
|
||||
Unavailable
|
||||
AlreadyExists
|
||||
NotFound
|
||||
NotImplement
|
||||
VerifyFailed
|
||||
Conflict
|
||||
)
|
||||
@@ -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]]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package errors
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCode_String(t *testing.T) {
|
||||
t.Log(Code(1).String())
|
||||
}
|
||||
@@ -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
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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 {
|
||||
Code Code `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
var None = New(OK, "success")
|
||||
var None = Error{Message: "success"}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("error: %v,message: %v", e.Code.String(), 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
|
||||
}
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func New(code Code, message string) error {
|
||||
if message == "" {
|
||||
message = code.String()
|
||||
}
|
||||
return &Error{Code: code, Message: message}
|
||||
func Wrap(err error) Error {
|
||||
return Error{Message: err.Error()}
|
||||
}
|
||||
|
||||
func HandlerError(err error, resp *restful.Response) bool {
|
||||
|
||||
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 {
|
||||
func Parse(data []byte) error {
|
||||
var j map[string]string
|
||||
err := json.Unmarshal(data, &j)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,47 +18,27 @@
|
||||
package components
|
||||
|
||||
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"
|
||||
|
||||
"github.com/golang/glog"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"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) {
|
||||
|
||||
var service *coreV1.Service
|
||||
var service *corev1.Service
|
||||
var err error
|
||||
|
||||
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
|
||||
for _, ns := range constants.SystemNamespaces {
|
||||
service, err = serviceLister.Services(ns).Get(name)
|
||||
if err == nil {
|
||||
@@ -70,13 +50,15 @@ func GetComponentStatus(name string) (interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
|
||||
pods, err := podLister.Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
component := Component{
|
||||
component := models.Component{
|
||||
Name: service.Name,
|
||||
Namespace: service.Namespace,
|
||||
SelfLink: service.SelfLink,
|
||||
@@ -102,11 +84,11 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
||||
|
||||
status := make(map[string]interface{})
|
||||
|
||||
componentStatuses, err := componentStatusLister.List(labels.Everything())
|
||||
componentStatuses, err := client.K8sClient().CoreV1().ComponentStatuses().List(meta_v1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cs := range componentStatuses {
|
||||
for _, cs := range componentStatuses.Items {
|
||||
status[cs.Name] = cs.Conditions[0]
|
||||
}
|
||||
|
||||
@@ -119,6 +101,8 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
||||
for k, v := range systemComponentStatus {
|
||||
status[k] = v
|
||||
}
|
||||
|
||||
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
// get node status
|
||||
nodes, err := nodeLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
@@ -132,7 +116,7 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
||||
for _, nodes := range nodes {
|
||||
totalNodes++
|
||||
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++
|
||||
}
|
||||
}
|
||||
@@ -147,11 +131,12 @@ func GetSystemHealthStatus() (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{})
|
||||
|
||||
var err error
|
||||
|
||||
for _, ns := range constants.SystemNamespaces {
|
||||
|
||||
nsStatus := make(map[string]interface{})
|
||||
@@ -164,7 +149,7 @@ func GetAllComponentsStatus() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
component := Component{
|
||||
component := models.Component{
|
||||
Name: service.Name,
|
||||
Namespace: service.Namespace,
|
||||
SelfLink: service.SelfLink,
|
||||
|
||||
822
pkg/models/iam/am.go
Normal file
822
pkg/models/iam/am.go
Normal 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
54
pkg/models/iam/counter.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
import (
|
||||
@@ -7,38 +24,22 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
v12 "k8s.io/client-go/listers/rbac/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"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/constants"
|
||||
ksErr "kubesphere.io/kubesphere/pkg/errors"
|
||||
kserr "kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
)
|
||||
|
||||
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
|
||||
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))
|
||||
|
||||
@@ -67,11 +68,11 @@ func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUsers(names []string) ([]User, error) {
|
||||
var users []User
|
||||
func GetUsers(names []string) ([]models.User, error) {
|
||||
var users []models.User
|
||||
|
||||
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, ",")))
|
||||
@@ -88,7 +89,7 @@ func GetUsers(names []string) ([]User, error) {
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
return nil, kserr.Parse(data)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &users)
|
||||
@@ -100,7 +101,7 @@ func GetUsers(names []string) ([]User, error) {
|
||||
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))
|
||||
|
||||
@@ -116,10 +117,10 @@ func GetUser(name string) (*User, error) {
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -187,16 +188,8 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
|
||||
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) {
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
|
||||
|
||||
if err != nil {
|
||||
@@ -213,108 +206,6 @@ func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error)
|
||||
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 {
|
||||
for _, rule := range rules {
|
||||
if ruleMatchesRequired(rule, required) {
|
||||
@@ -323,139 +214,3 @@ func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
||||
}
|
||||
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
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
76
pkg/models/iam/path.go
Normal 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
|
||||
}
|
||||
1333
pkg/models/iam/policy/policy.go
Normal file
1333
pkg/models/iam/policy/policy.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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"`
|
||||
}
|
||||
@@ -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}
|
||||
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func GetKubeConfig(user string) (string, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{})
|
||||
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 configMap.Data[kubectlConfigKey], nil
|
||||
@@ -287,7 +287,7 @@ func DelKubeConfig(user string) error {
|
||||
deletePolicy := metaV1.DeletePropagationBackground
|
||||
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(user, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
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 nil
|
||||
|
||||
@@ -20,6 +20,7 @@ package kubectl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"math/rand"
|
||||
|
||||
"github.com/golang/glog"
|
||||
@@ -38,18 +39,12 @@ const (
|
||||
namespace = constants.KubeSphereControlNamespace
|
||||
)
|
||||
|
||||
type PodInfo struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Pod string `json:"pod"`
|
||||
Container string `json:"container"`
|
||||
}
|
||||
|
||||
func GetKubectlPod(username string) (PodInfo, error) {
|
||||
func GetKubectlPod(username string) (models.PodInfo, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
deploy, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(username, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return PodInfo{}, err
|
||||
return models.PodInfo{}, err
|
||||
}
|
||||
|
||||
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})
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return PodInfo{}, err
|
||||
return models.PodInfo{}, err
|
||||
}
|
||||
|
||||
pod, err := selectCorrectPod(namespace, podList.Items)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
|
||||
@@ -20,14 +20,13 @@ package metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/components"
|
||||
@@ -50,7 +49,6 @@ import (
|
||||
var (
|
||||
jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
nodeStatusDelLabel = []string{"endpoint", "instance", "job", "namespace", "pod", "service"}
|
||||
nodeLister v12.NodeLister
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -126,10 +124,6 @@ type OneComponentStatus struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
nodeLister = informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
}
|
||||
|
||||
func getAllWorkspaceNames(formatedMetric *FormatedMetric) map[string]int {
|
||||
|
||||
var wsMap = make(map[string]int)
|
||||
@@ -197,12 +191,12 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
||||
var timestampMap = make(map[float64]bool)
|
||||
|
||||
if fmtMetrics.Data.ResultType == ResultTypeMatrix {
|
||||
for i, _ := range fmtMetrics.Data.Result {
|
||||
for i := range fmtMetrics.Data.Result {
|
||||
values, exist := fmtMetrics.Data.Result[i][ResultItemValues]
|
||||
if exist {
|
||||
valueArray, sure := values.([]interface{})
|
||||
if sure {
|
||||
for j, _ := range valueArray {
|
||||
for j := range valueArray {
|
||||
timeAndValue := valueArray[j].([]interface{})
|
||||
timestampMap[float64(timeAndValue[0].(uint64))] = true
|
||||
}
|
||||
@@ -213,7 +207,7 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
||||
|
||||
timestampArray := make([]float64, len(timestampMap))
|
||||
i := 0
|
||||
for timestamp, _ := range timestampMap {
|
||||
for timestamp := range timestampMap {
|
||||
timestampArray[i] = timestamp
|
||||
i++
|
||||
}
|
||||
@@ -230,7 +224,7 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
||||
formatValueArray := make([][]interface{}, len(timestampArray))
|
||||
j := 0
|
||||
|
||||
for k, _ := range timestampArray {
|
||||
for k := range timestampArray {
|
||||
valueItem, sure := valueArray[j].([]interface{})
|
||||
if sure && float64(valueItem[0].(uint64)) == timestampArray[k] {
|
||||
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 {
|
||||
|
||||
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
nodes, err := nodeLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
@@ -938,7 +932,7 @@ func MonitorComponentStatus(monitoringRequest *client.MonitoringRequestParams) *
|
||||
nsStatus, exist := Components[ns]
|
||||
if exist {
|
||||
for _, nsStatusItem := range nsStatus.(map[string]interface{}) {
|
||||
component := nsStatusItem.(components.Component)
|
||||
component := nsStatusItem.(models.Component)
|
||||
namespaceComponentTotalMap[ns] += 1
|
||||
if component.HealthyBackends != 0 && component.HealthyBackends == component.TotalBackends {
|
||||
namespaceComponentHealthyMap[ns] += 1
|
||||
|
||||
@@ -33,7 +33,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
func DrainNode(nodename string) (err error) {
|
||||
@@ -45,7 +44,7 @@ func DrainNode(nodename string) (err error) {
|
||||
}
|
||||
|
||||
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}}")
|
||||
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -51,27 +51,17 @@ var (
|
||||
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
|
||||
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles,
|
||||
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) {
|
||||
list, err := resources.ListNamespaceResource(namespace, resource, "", "", false, -1, 0)
|
||||
list, err := resources.ListNamespaceResource(namespace, resource, ¶ms.Conditions{}, "", false, -1, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return list.TotalCount, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
resouceQuotaLister = informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
|
||||
}
|
||||
|
||||
func GetClusterQuotas() (*ResourceQuota, error) {
|
||||
func GetClusterQuotas() (*models.ResourceQuota, error) {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
@@ -135,7 +125,8 @@ func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -20,12 +20,11 @@ package registries
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
type AuthInfo struct {
|
||||
@@ -62,6 +61,6 @@ func RegistryVerify(authInfo AuthInfo) error {
|
||||
if resp.Status == loginSuccess {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New(errors.VerifyFailed, resp.Status)
|
||||
return fmt.Errorf(resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/listers/rbac/v1"
|
||||
)
|
||||
|
||||
type clusterRoleSearcher struct {
|
||||
clusterRoleLister v1.ClusterRoleLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -45,7 +45,7 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
clusterRoles, err := s.clusterRoleLister.List(labels.Everything())
|
||||
func (s *clusterRoleSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
clusterRoles, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -95,11 +95,11 @@ func (s *clusterRoleSearcher) search(conditions *conditions, orderBy string, rev
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type configMapSearcher struct {
|
||||
configMapLister lister.ConfigMapLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) boo
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
configMaps, err := s.configMapLister.ConfigMaps(namespace).List(labels.Everything())
|
||||
func (s *configMapSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
configMaps, err := informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -100,11 +99,11 @@ func (s *configMapSearcher) search(namespace string, conditions *conditions, ord
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,28 +18,28 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/batch/v2alpha1"
|
||||
"k8s.io/api/batch/v1beta1"
|
||||
|
||||
"k8s.io/api/batch/v2alpha1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
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 {
|
||||
return paused
|
||||
}
|
||||
return running
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) bool {
|
||||
// Exactly Match
|
||||
func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
@@ -53,7 +53,7 @@ func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) b
|
||||
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 {
|
||||
switch k {
|
||||
@@ -88,7 +88,7 @@ func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v2alpha1.CronJob) b
|
||||
return true
|
||||
}
|
||||
|
||||
func (*cronJobSearcher) compare(a, b *v2alpha1.CronJob, orderBy string) bool {
|
||||
func (*cronJobSearcher) compare(a, b *v1beta1.CronJob, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
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) {
|
||||
cronJobs, err := s.cronJobLister.CronJobs(namespace).List(labels.Everything())
|
||||
func (s *cronJobSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
cronJobs, err := informers.SharedInformerFactory().Batch().V1beta1().CronJobs().Lister().CronJobs(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,16 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type daemonSetSearcher struct {
|
||||
daemonSetLister lister.DaemonSetLister
|
||||
}
|
||||
|
||||
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 {
|
||||
for k, v := range match {
|
||||
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) {
|
||||
daemonSets, err := s.daemonSetLister.DaemonSets(namespace).List(labels.Everything())
|
||||
func (s *daemonSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
daemonSets, err := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister().DaemonSets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -111,11 +110,11 @@ func (s *daemonSetSearcher) search(namespace string, conditions *conditions, ord
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,18 +18,17 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
)
|
||||
|
||||
type deploymentSearcher struct {
|
||||
deploymentLister lister.DeploymentLister
|
||||
}
|
||||
|
||||
func deploymentStatus(item *v1.Deployment) string {
|
||||
@@ -45,7 +44,7 @@ func deploymentStatus(item *v1.Deployment) string {
|
||||
return stopped
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
// Exactly Match
|
||||
func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool {
|
||||
for k, v := range match {
|
||||
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) {
|
||||
deployments, err := s.deploymentLister.Deployments(namespace).List(labels.Everything())
|
||||
func (s *deploymentSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
deployments, err := informers.SharedInformerFactory().Apps().V1().Deployments().Lister().Deployments(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -115,11 +114,11 @@ func (s *deploymentSearcher) search(namespace string, conditions *conditions, or
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,21 +18,20 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/extensions/v1beta1"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type ingressSearcher struct {
|
||||
ingressLister lister.IngressLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -47,7 +46,7 @@ func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress)
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
ingresses, err := s.ingressLister.Ingresses(namespace).List(labels.Everything())
|
||||
func (s *ingressSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
ingresses, err := informers.SharedInformerFactory().Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -101,11 +100,11 @@ func (s *ingressSearcher) search(namespace string, conditions *conditions, order
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,37 +18,36 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
"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"
|
||||
)
|
||||
|
||||
type jobSearcher struct {
|
||||
jobLister lister.JobLister
|
||||
}
|
||||
|
||||
func jobStatus(item *batchV1.Job) string {
|
||||
func jobStatus(item *batchv1.Job) string {
|
||||
status := ""
|
||||
|
||||
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
|
||||
}
|
||||
if condition.Type == batchV1.JobComplete && condition.Status == coreV1.ConditionTrue {
|
||||
if condition.Type == batchv1.JobComplete && condition.Status == corev1.ConditionTrue {
|
||||
status = complete
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool {
|
||||
// Exactly Match
|
||||
func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
@@ -62,7 +61,7 @@ func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool {
|
||||
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 {
|
||||
switch k {
|
||||
@@ -97,7 +96,7 @@ func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchV1.Job) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func jobUpdateTime(item *batchV1.Job) time.Time {
|
||||
func jobUpdateTime(item *batchv1.Job) time.Time {
|
||||
updateTime := item.CreationTimestamp.Time
|
||||
for _, condition := range item.Status.Conditions {
|
||||
if updateTime.Before(condition.LastProbeTime.Time) {
|
||||
@@ -110,7 +109,7 @@ func jobUpdateTime(item *batchV1.Job) time.Time {
|
||||
return updateTime
|
||||
}
|
||||
|
||||
func (*jobSearcher) compare(a, b *batchV1.Job, orderBy string) bool {
|
||||
func (*jobSearcher) compare(a, b *batchv1.Job, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case updateTime:
|
||||
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) {
|
||||
jobs, err := s.jobLister.Jobs(namespace).List(labels.Everything())
|
||||
func (s *jobSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
jobs, err := informers.SharedInformerFactory().Batch().V1().Jobs().Lister().Jobs(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
)
|
||||
|
||||
type namespaceSearcher struct {
|
||||
namespaceLister lister.NamespaceLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -45,7 +45,7 @@ func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) boo
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
namespaces, err := s.namespaceLister.List(labels.Everything())
|
||||
func (s *namespaceSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
namespaces, err := informers.SharedInformerFactory().Core().V1().Namespaces().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -99,11 +99,11 @@ func (s *namespaceSearcher) search(conditions *conditions, orderBy string, rever
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
)
|
||||
|
||||
type nodeSearcher struct {
|
||||
nodeLister lister.NodeLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -45,7 +45,7 @@ func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
nodes, err := s.nodeLister.List(labels.Everything())
|
||||
func (s *nodeSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
nodes, err := informers.SharedInformerFactory().Core().V1().Nodes().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -99,11 +99,11 @@ func (s *nodeSearcher) search(conditions *conditions, orderBy string, reverse bo
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type persistentVolumeClaimSearcher struct {
|
||||
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
persistentVolumeClaims, err := s.persistentVolumeClaimLister.PersistentVolumeClaims(namespace).List(labels.Everything())
|
||||
func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
persistentVolumeClaims, err := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister().PersistentVolumeClaims(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -100,11 +99,11 @@ func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *con
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type podSearcher struct {
|
||||
podLister v12.PodLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
|
||||
for k, v := range fuzzy {
|
||||
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 {
|
||||
return nil, err
|
||||
@@ -101,11 +100,11 @@ func (s *podSearcher) search(namespace string, conditions *conditions, orderBy s
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,74 +18,35 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
namespacedResources[ConfigMaps] = &configMapSearcher{
|
||||
configMapLister: informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister(),
|
||||
}
|
||||
namespacedResources[CronJobs] = &cronJobSearcher{
|
||||
cronJobLister: informers.SharedInformerFactory().Batch().V2alpha1().CronJobs().Lister(),
|
||||
}
|
||||
namespacedResources[DaemonSets] = &daemonSetSearcher{
|
||||
daemonSetLister: informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister(),
|
||||
}
|
||||
namespacedResources[Deployments] = &deploymentSearcher{
|
||||
deploymentLister: informers.SharedInformerFactory().Apps().V1().Deployments().Lister(),
|
||||
}
|
||||
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(),
|
||||
}
|
||||
namespacedResources[ConfigMaps] = &configMapSearcher{}
|
||||
namespacedResources[CronJobs] = &cronJobSearcher{}
|
||||
namespacedResources[DaemonSets] = &daemonSetSearcher{}
|
||||
namespacedResources[Deployments] = &deploymentSearcher{}
|
||||
namespacedResources[Ingresses] = &ingressSearcher{}
|
||||
namespacedResources[Jobs] = &jobSearcher{}
|
||||
namespacedResources[PersistentVolumeClaims] = &persistentVolumeClaimSearcher{}
|
||||
namespacedResources[Secrets] = &secretSearcher{}
|
||||
namespacedResources[Services] = &serviceSearcher{}
|
||||
namespacedResources[StatefulSets] = &statefulSetSearcher{}
|
||||
namespacedResources[Pods] = &podSearcher{}
|
||||
namespacedResources[Roles] = &roleSearcher{}
|
||||
|
||||
clusterResources[Nodes] = &nodeSearcher{
|
||||
nodeLister: informers.SharedInformerFactory().Core().V1().Nodes().Lister(),
|
||||
}
|
||||
clusterResources[Namespaces] = &namespaceSearcher{
|
||||
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(),
|
||||
}
|
||||
clusterResources[Nodes] = &nodeSearcher{}
|
||||
clusterResources[Namespaces] = &namespaceSearcher{}
|
||||
clusterResources[ClusterRoles] = &clusterRoleSearcher{}
|
||||
clusterResources[StorageClasses] = &storageClassesSearcher{}
|
||||
}
|
||||
|
||||
var namespacedResources = make(map[string]namespacedSearcherInterface)
|
||||
var clusterResources = make(map[string]clusterSearcherInterface)
|
||||
|
||||
type conditions struct {
|
||||
match map[string]string
|
||||
fuzzy map[string]string
|
||||
}
|
||||
|
||||
const (
|
||||
name = "name"
|
||||
label = "label"
|
||||
@@ -123,33 +84,26 @@ const (
|
||||
)
|
||||
|
||||
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 {
|
||||
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)
|
||||
total := 0
|
||||
var err error
|
||||
|
||||
conditions, err := parseToConditions(conditionStr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []interface{}
|
||||
|
||||
if searcher, ok := namespacedResources[resource]; ok {
|
||||
result, err = searcher.search(namespace, conditions, orderBy, reverse)
|
||||
} else {
|
||||
return nil, errors.New(errors.NotImplement, "not support")
|
||||
return nil, fmt.Errorf("not support")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New(errors.Internal, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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)
|
||||
total := 0
|
||||
var err error
|
||||
|
||||
conditions, err := parseToConditions(conditionStr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -179,11 +131,11 @@ func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, l
|
||||
if searcher, ok := clusterResources[resource]; ok {
|
||||
result, err = searcher.search(conditions, orderBy, reverse)
|
||||
} else {
|
||||
return nil, errors.New(errors.NotImplement, "not support")
|
||||
return nil, fmt.Errorf("not support")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New(errors.Internal, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
total = len(result)
|
||||
@@ -194,36 +146,7 @@ func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, l
|
||||
}
|
||||
}
|
||||
|
||||
return &ResourceList{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"`
|
||||
return &models.PageableResponse{TotalCount: total, Items: items}, nil
|
||||
}
|
||||
|
||||
func searchFuzzy(m map[string]string, key, value string) bool {
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
lister "k8s.io/client-go/listers/rbac/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type roleSearcher struct {
|
||||
roleLister lister.RoleLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
roles, err := s.roleLister.Roles(namespace).List(labels.Everything())
|
||||
func (s *roleSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
roles, err := informers.SharedInformerFactory().Rbac().V1().Roles().Lister().Roles(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -96,11 +95,11 @@ func (s *roleSearcher) search(namespace string, conditions *conditions, orderBy
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type secretSearcher struct {
|
||||
secretLister lister.SecretLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -50,7 +49,7 @@ func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
secrets, err := s.secretLister.Secrets(namespace).List(labels.Everything())
|
||||
func (s *secretSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
secrets, err := informers.SharedInformerFactory().Core().V1().Secrets().Lister().Secrets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -104,11 +103,11 @@ func (s *secretSearcher) search(namespace string, conditions *conditions, orderB
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type serviceSearcher struct {
|
||||
serviceLister lister.ServiceLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -46,7 +45,7 @@ func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
services, err := s.serviceLister.Services(namespace).List(labels.Everything())
|
||||
func (s *serviceSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
services, err := informers.SharedInformerFactory().Core().V1().Services().Lister().Services(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -100,11 +99,11 @@ func (s *serviceSearcher) search(namespace string, conditions *conditions, order
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,16 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type statefulSetSearcher struct {
|
||||
statefulSetLister lister.StatefulSetLister
|
||||
}
|
||||
|
||||
func statefulSetStatus(item *v1.StatefulSet) string {
|
||||
@@ -44,7 +43,7 @@ func statefulSetStatus(item *v1.StatefulSet) string {
|
||||
return stopped
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
// Exactly Match
|
||||
func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool {
|
||||
for k, v := range match {
|
||||
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) {
|
||||
statefulSets, err := s.statefulSetLister.StatefulSets(namespace).List(labels.Everything())
|
||||
func (s *statefulSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
statefulSets, err := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister().StatefulSets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -114,11 +113,11 @@ func (s *statefulSetSearcher) search(namespace string, conditions *conditions, o
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/storage/v1"
|
||||
)
|
||||
|
||||
type storageClassesSearcher struct {
|
||||
storageClassesLister lister.StorageClassLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
// exactly Match
|
||||
func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
@@ -45,7 +45,7 @@ func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageCl
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
// Fuzzy searchInNamespace
|
||||
func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool {
|
||||
for k, v := range fuzzy {
|
||||
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) {
|
||||
storageClasses, err := s.storageClassesLister.List(labels.Everything())
|
||||
func (s *storageClassesSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
storageClasses, err := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -95,11 +95,11 @@ func (s *storageClassesSearcher) search(conditions *conditions, orderBy string,
|
||||
|
||||
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
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,29 +24,11 @@ import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"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) {
|
||||
deploymentLister := informers.SharedInformerFactory().Apps().V1().Deployments().Lister()
|
||||
deploy, err := deploymentLister.Deployments(namespace).Get(name)
|
||||
if err != nil {
|
||||
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
|
||||
labelSelector := labels.Set(labelMap).AsSelector()
|
||||
|
||||
replicaSetLister := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
|
||||
rsList, err := replicaSetLister.ReplicaSets(namespace).List(labelSelector)
|
||||
if err != nil {
|
||||
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) {
|
||||
|
||||
daemonSetLister := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister()
|
||||
ds, err := daemonSetLister.DaemonSets(namespace).Get(name)
|
||||
|
||||
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) {
|
||||
|
||||
statefulSetLister := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister()
|
||||
st, err := statefulSetLister.StatefulSets(namespace).Get(name)
|
||||
|
||||
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) {
|
||||
|
||||
labelSelector := labels.Set(labelMap).AsSelector()
|
||||
|
||||
controllerRevisionLister := informers.SharedInformerFactory().Apps().V1().ControllerRevisions().Lister()
|
||||
revisions, err := controllerRevisionLister.ControllerRevisions(namespace).List(labelSelector)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -23,15 +23,12 @@ import (
|
||||
"io/ioutil"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
extensionsV1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
@@ -43,18 +40,10 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
)
|
||||
|
||||
var (
|
||||
serviceLister v12.ServiceLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
}
|
||||
|
||||
func GetAllRouters() ([]*coreV1.Service, error) {
|
||||
func GetAllRouters() ([]*corev1.Service, error) {
|
||||
|
||||
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)
|
||||
|
||||
if err != nil {
|
||||
@@ -65,7 +54,7 @@ func GetAllRouters() ([]*coreV1.Service, error) {
|
||||
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{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
@@ -82,7 +71,7 @@ func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
||||
return GetAllRouters()
|
||||
}
|
||||
|
||||
routers := make([]*coreV1.Service, 0)
|
||||
routers := make([]*corev1.Service, 0)
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
router, err := GetRouter(namespace)
|
||||
@@ -99,11 +88,11 @@ func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
||||
}
|
||||
|
||||
// Get router from a namespace
|
||||
func GetRouter(namespace string) (*coreV1.Service, error) {
|
||||
func GetRouter(namespace string) (*corev1.Service, error) {
|
||||
serviceName := constants.IngressControllerPrefix + 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)
|
||||
|
||||
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
|
||||
@@ -148,11 +137,11 @@ func LoadYamls() ([]string, error) {
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
||||
var router *coreV1.Service
|
||||
var router *corev1.Service
|
||||
|
||||
yamls, err := LoadYamls()
|
||||
|
||||
@@ -170,8 +159,8 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
}
|
||||
|
||||
switch obj.(type) {
|
||||
case *coreV1.Service:
|
||||
service := obj.(*coreV1.Service)
|
||||
case *corev1.Service:
|
||||
service := obj.(*corev1.Service)
|
||||
|
||||
service.SetAnnotations(annotations)
|
||||
service.Spec.Type = routerType
|
||||
@@ -190,8 +179,8 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
|
||||
router = service
|
||||
|
||||
case *extensionsV1beta1.Deployment:
|
||||
deployment := obj.(*extensionsV1beta1.Deployment)
|
||||
case *extensionsv1beta1.Deployment:
|
||||
deployment := obj.(*extensionsv1beta1.Deployment)
|
||||
deployment.Name = constants.IngressControllerPrefix + namespace
|
||||
|
||||
// Add project label
|
||||
@@ -204,7 +193,7 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
// Choose self as master
|
||||
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)
|
||||
} else {
|
||||
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
|
||||
// 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()
|
||||
|
||||
var err error
|
||||
var router *coreV1.Service
|
||||
var router *corev1.Service
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
@@ -236,9 +225,9 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
||||
|
||||
// delete controller service
|
||||
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,
|
||||
FieldSelector: "metadata.name=" + serviceName}
|
||||
|
||||
@@ -259,7 +248,7 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
||||
// delete controller deployment
|
||||
deploymentName := constants.IngressControllerPrefix + namespace
|
||||
|
||||
listOptions = metaV1.ListOptions{
|
||||
listOptions = meta_v1.ListOptions{
|
||||
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
||||
}
|
||||
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.
|
||||
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()
|
||||
|
||||
var router *coreV1.Service
|
||||
var router *corev1.Service
|
||||
|
||||
router, err := GetRouter(namespace)
|
||||
|
||||
@@ -293,7 +282,7 @@ func UpdateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
||||
|
||||
if router == nil {
|
||||
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
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
)
|
||||
@@ -31,7 +32,7 @@ type workLoadStatus struct {
|
||||
|
||||
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
||||
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
|
||||
for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims} {
|
||||
notReadyStatus := "updating"
|
||||
@@ -39,7 +40,7 @@ func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
||||
notReadyStatus = "pending"
|
||||
}
|
||||
|
||||
notReadyList, err = resources.ListNamespaceResource(namespace, resource, fmt.Sprintf("status=%s", notReadyStatus), "", false, -1, 0)
|
||||
notReadyList, err = resources.ListNamespaceResource(namespace, resource, ¶ms.Conditions{Match: map[string]string{"status": notReadyStatus}}, "", false, -1, 0)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -24,9 +24,6 @@ import (
|
||||
storageV1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -36,18 +33,12 @@ type ScMetrics struct {
|
||||
PvcNumber string `json:"pvcNumber"`
|
||||
}
|
||||
|
||||
var (
|
||||
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
|
||||
persistentVolumeLister lister.PersistentVolumeLister
|
||||
sotrageClassesLister lister2.StorageClassLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
persistentVolumeClaimLister = informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
|
||||
persistentVolumeLister = informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
|
||||
|
||||
}
|
||||
|
||||
func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
|
||||
persistentVolumeClaimLister := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
|
||||
all, err := persistentVolumeClaimLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
@@ -70,6 +61,7 @@ func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
|
||||
|
||||
// Get info of metrics
|
||||
func GetScMetrics(scName string) (*ScMetrics, error) {
|
||||
persistentVolumeLister := informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
|
||||
pvList, err := persistentVolumeLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -102,7 +94,7 @@ func GetScMetrics(scName string) (*ScMetrics, error) {
|
||||
func GetScList() ([]*storageV1.StorageClass, error) {
|
||||
|
||||
// Get StorageClass list
|
||||
scList, err := sotrageClassesLister.List(labels.Everything())
|
||||
scList, err := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -20,19 +20,12 @@ package storage
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"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
|
||||
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())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user