Merge pull request #288 from wansir/advanced-2.0-dev
add ks-iam and ks-apigateway
This commit is contained in:
@@ -17,9 +17,11 @@ before_install:
|
|||||||
before_script:
|
before_script:
|
||||||
- dep ensure -v
|
- dep ensure -v
|
||||||
- docker --version
|
- docker --version
|
||||||
|
- git clone --single-branch -b v0.11.4 -q https://github.com/mholt/caddy $GOPATH/src/github.com/mholt/caddy
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- make all && make test
|
- make test
|
||||||
|
- bash hack/docker_build.sh
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
|
|||||||
442
Gopkg.lock
generated
442
Gopkg.lock
generated
@@ -2,57 +2,82 @@
|
|||||||
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:4d6f036ea3fe636bcb2e89850bcdc62a771354e157cd51b8b22a2de8562bf663"
|
||||||
name = "cloud.google.com/go"
|
name = "cloud.google.com/go"
|
||||||
packages = ["compute/metadata"]
|
packages = ["compute/metadata"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "c9474f2f8deb81759839474b6bd1726bbfe1c1c4"
|
revision = "c9474f2f8deb81759839474b6bd1726bbfe1c1c4"
|
||||||
version = "v0.36.0"
|
version = "v0.36.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:f9ae348e1f793dcf9ed930ed47136a67343dbd6809c5c91391322267f4476892"
|
||||||
name = "github.com/Microsoft/go-winio"
|
name = "github.com/Microsoft/go-winio"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
|
pruneopts = "UT"
|
||||||
version = "v0.4.7"
|
revision = "1a8911d1ed007260465c3bfbbc785ac6915a0bb8"
|
||||||
|
version = "v0.4.12"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:a2682518d905d662d984ef9959984ef87cecb777d379bfa9d9fe40e78069b3e4"
|
||||||
name = "github.com/PuerkitoBio/purell"
|
name = "github.com/PuerkitoBio/purell"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
|
pruneopts = "UT"
|
||||||
version = "v1.1.0"
|
revision = "44968752391892e1b0d0b821ee79e9a85fa13049"
|
||||||
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:c739832d67eb1e9cc478a19cc1a1ccd78df0397bf8a32978b759152e205f644b"
|
||||||
name = "github.com/PuerkitoBio/urlesc"
|
name = "github.com/PuerkitoBio/urlesc"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
|
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8"
|
||||||
name = "github.com/Sirupsen/logrus"
|
name = "github.com/Sirupsen/logrus"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
pruneopts = "UT"
|
||||||
version = "v1.0.5"
|
revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5"
|
||||||
|
version = "v1.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
|
||||||
name = "github.com/beorn7/perks"
|
name = "github.com/beorn7/perks"
|
||||||
packages = ["quantile"]
|
packages = ["quantile"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||||
name = "github.com/davecgh/go-spew"
|
name = "github.com/davecgh/go-spew"
|
||||||
packages = ["spew"]
|
packages = ["spew"]
|
||||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
pruneopts = "UT"
|
||||||
version = "v1.1.0"
|
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||||
|
version = "v1.1.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
|
||||||
|
name = "github.com/dgrijalva/jwt-go"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||||
|
version = "v3.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:4c7d169280debf9f36b84a0f682094889cccc5dc0db8657f9cffc93b21975a57"
|
||||||
name = "github.com/docker/distribution"
|
name = "github.com/docker/distribution"
|
||||||
packages = [
|
packages = [
|
||||||
"digestset",
|
"digestset",
|
||||||
"reference"
|
"reference",
|
||||||
]
|
]
|
||||||
revision = "749f6afb4572201e3c37325d0ffedb6f32be8950"
|
pruneopts = "UT"
|
||||||
|
revision = "6d62eb1d4a3515399431b713fde3ce5a9b40e8d5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:ec821dda59d7dd340498d74f798aa218b2c782bba54a690e866dc4f520d900d5"
|
||||||
name = "github.com/docker/docker"
|
name = "github.com/docker/docker"
|
||||||
packages = [
|
packages = [
|
||||||
"api",
|
"api",
|
||||||
@@ -74,338 +99,466 @@
|
|||||||
"pkg/ioutils",
|
"pkg/ioutils",
|
||||||
"pkg/longpath",
|
"pkg/longpath",
|
||||||
"pkg/system",
|
"pkg/system",
|
||||||
"pkg/tlsconfig"
|
"pkg/tlsconfig",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "90d35abf7b3535c1c319c872900fbd76374e521c"
|
revision = "90d35abf7b3535c1c319c872900fbd76374e521c"
|
||||||
version = "v17.05.0-ce-rc3"
|
version = "v17.05.0-ce-rc3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:02f8f4889e53a6adbc7bf3f2b9007ce8aecb0b79686fc9f99265246c88063f10"
|
||||||
name = "github.com/docker/go-connections"
|
name = "github.com/docker/go-connections"
|
||||||
packages = [
|
packages = [
|
||||||
"nat",
|
"nat",
|
||||||
"sockets",
|
"sockets",
|
||||||
"tlsconfig"
|
"tlsconfig",
|
||||||
]
|
]
|
||||||
revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55"
|
pruneopts = "UT"
|
||||||
|
revision = "97c2040d34dfae1d1b1275fa3a78dbdd2f41cf7e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18"
|
||||||
name = "github.com/docker/go-units"
|
name = "github.com/docker/go-units"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
|
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
|
||||||
version = "v0.3.3"
|
version = "v0.3.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:4841e14252a2cecf11840bd05230412ad469709bbacfc12467e2ce5ad07f339b"
|
||||||
name = "github.com/docker/libtrust"
|
name = "github.com/docker/libtrust"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
|
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:8ee7b41ace3ba875c17e38ba7780e7cf0d29882338637861e9f13f04f60ecc5c"
|
||||||
name = "github.com/emicklei/go-restful"
|
name = "github.com/emicklei/go-restful"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"log"
|
"log",
|
||||||
]
|
]
|
||||||
revision = "3658237ded108b4134956c1b3050349d93e7b895"
|
pruneopts = "UT"
|
||||||
version = "v2.7.1"
|
revision = "85d198d05a92d31823b852b4a5928114912e8949"
|
||||||
|
version = "v2.9.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:8ba45daa43acfd9364068b118a6884cb82bc1ef0569dc05260f3b464907e07d9"
|
||||||
name = "github.com/emicklei/go-restful-openapi"
|
name = "github.com/emicklei/go-restful-openapi"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "51bf251d405ad1e23511fef0a2dbe40bc70ce2c6"
|
pruneopts = "UT"
|
||||||
version = "v0.11.0"
|
revision = "b7062368c258c9e8f8cbe9dd2e6aebfa1b747be6"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda"
|
||||||
name = "github.com/ghodss/yaml"
|
name = "github.com/ghodss/yaml"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
|
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
digest = "1:2a792dde3ae5dc95000d4dee312523504ea875b097a2b119a2f55d1d1d32ed61"
|
||||||
name = "github.com/go-logr/logr"
|
name = "github.com/go-ldap/ldap"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e"
|
pruneopts = "UT"
|
||||||
|
revision = "729c20c2694d870bcd631f0dadaecd088bd7ccbc"
|
||||||
|
version = "v3.0.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/go-logr/zapr"
|
digest = "1:edd2fa4578eb086265db78a9201d15e76b298dfd0d5c379da83e9c61712cf6df"
|
||||||
|
name = "github.com/go-logr/logr"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab"
|
pruneopts = "UT"
|
||||||
|
revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e"
|
||||||
version = "v0.1.0"
|
version = "v0.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
digest = "1:d81dfed1aa731d8e4a45d87154ec15ef18da2aa80fa9a2f95bec38577a244a99"
|
||||||
|
name = "github.com/go-logr/zapr"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "03f06a783fbb7dfaf3f629c7825480e43a7105e6"
|
||||||
|
version = "v0.1.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:953a2628e4c5c72856b53f5470ed5e071c55eccf943d798d42908102af2a610f"
|
||||||
name = "github.com/go-openapi/jsonpointer"
|
name = "github.com/go-openapi/jsonpointer"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2"
|
pruneopts = "UT"
|
||||||
|
revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004"
|
||||||
|
version = "v0.18.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
digest = "1:81210e0af657a0fb3638932ec68e645236bceefa4c839823db0c4d918f080895"
|
||||||
name = "github.com/go-openapi/jsonreference"
|
name = "github.com/go-openapi/jsonreference"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "3fb327e6747da3043567ee86abd02bb6376b6be2"
|
pruneopts = "UT"
|
||||||
|
revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3"
|
||||||
|
version = "v0.18.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
digest = "1:08656ef9c5a45ddccb7f206ca2d67e12e9fcda4122a83dc0544b5c967267cefa"
|
||||||
name = "github.com/go-openapi/spec"
|
name = "github.com/go-openapi/spec"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "bce47c9386f9ecd6b86f450478a80103c3fe1402"
|
pruneopts = "UT"
|
||||||
|
revision = "5b6cdde3200976e3ecceb2868706ee39b6aff3e4"
|
||||||
|
version = "v0.18.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
digest = "1:0005186c6608dd542239ac8e4f4f1e2e7c24d493e999113c46b93332f0362fc0"
|
||||||
name = "github.com/go-openapi/swag"
|
name = "github.com/go-openapi/swag"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "2b0bd4f193d011c203529df626a65d63cb8a79e8"
|
pruneopts = "UT"
|
||||||
|
revision = "1d29f06aebd59ccdf11ae04aa0334ded96e2d909"
|
||||||
|
version = "v0.18.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:33082c63746b464db3d1c2c07a1396d860484d97fe857ef9e8668a9b406db09f"
|
||||||
|
name = "github.com/go-redis/redis"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"internal",
|
||||||
|
"internal/consistenthash",
|
||||||
|
"internal/hashtag",
|
||||||
|
"internal/pool",
|
||||||
|
"internal/proto",
|
||||||
|
"internal/util",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "d22fde8721cc915a55aeb6b00944a76a92bfeb6e"
|
||||||
|
version = "v6.15.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:ec6f9bf5e274c833c911923c9193867f3f18788c461f76f05f62bb1510e0ae65"
|
||||||
name = "github.com/go-sql-driver/mysql"
|
name = "github.com/go-sql-driver/mysql"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "d523deb1b23d913de5bdada721a6071e71283618"
|
pruneopts = "UT"
|
||||||
version = "v1.4.0"
|
revision = "72cd26f257d44c1114970e19afddcd812016007e"
|
||||||
|
version = "v1.4.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:4d02824a56d268f74a6b6fdd944b20b58a77c3d70e81008b3ee0c4f1a6777340"
|
||||||
name = "github.com/gogo/protobuf"
|
name = "github.com/gogo/protobuf"
|
||||||
packages = [
|
packages = [
|
||||||
"proto",
|
"proto",
|
||||||
"sortkeys"
|
"sortkeys",
|
||||||
]
|
]
|
||||||
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
|
pruneopts = "UT"
|
||||||
version = "v1.0.0"
|
revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c"
|
||||||
|
version = "v1.2.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467"
|
||||||
name = "github.com/golang/glog"
|
name = "github.com/golang/glog"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
|
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:b7cb6054d3dff43b38ad2e92492f220f57ae6087ee797dca298139776749ace8"
|
||||||
name = "github.com/golang/groupcache"
|
name = "github.com/golang/groupcache"
|
||||||
packages = ["lru"]
|
packages = ["lru"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b"
|
revision = "5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:239c4c7fd2159585454003d9be7207167970194216193a8a210b8d29576f19c9"
|
||||||
name = "github.com/golang/protobuf"
|
name = "github.com/golang/protobuf"
|
||||||
packages = [
|
packages = [
|
||||||
"proto",
|
"proto",
|
||||||
"ptypes",
|
"ptypes",
|
||||||
"ptypes/any",
|
"ptypes/any",
|
||||||
"ptypes/duration",
|
"ptypes/duration",
|
||||||
"ptypes/timestamp"
|
"ptypes/timestamp",
|
||||||
]
|
]
|
||||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
pruneopts = "UT"
|
||||||
version = "v1.1.0"
|
revision = "c823c79ea1570fb5ff454033735a8e68575d1d0f"
|
||||||
|
version = "v1.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:0bfbe13936953a98ae3cfe8ed6670d396ad81edf069a806d2f6515d7bb6950df"
|
||||||
name = "github.com/google/btree"
|
name = "github.com/google/btree"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
|
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb"
|
||||||
name = "github.com/google/gofuzz"
|
name = "github.com/google/gofuzz"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
|
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:582b704bebaa06b48c29b0cec224a6058a09c86883aaddabde889cd1a5f73e1b"
|
||||||
name = "github.com/google/uuid"
|
name = "github.com/google/uuid"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8"
|
pruneopts = "UT"
|
||||||
version = "v1.1.0"
|
revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
|
||||||
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21"
|
||||||
name = "github.com/googleapis/gnostic"
|
name = "github.com/googleapis/gnostic"
|
||||||
packages = [
|
packages = [
|
||||||
"OpenAPIv2",
|
"OpenAPIv2",
|
||||||
"compiler",
|
"compiler",
|
||||||
"extensions"
|
"extensions",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
|
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
|
||||||
version = "v0.2.0"
|
version = "v0.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:b4395b2a4566c24459af3d04009b39cc21762fc77ec7bf7a1aa905c91e8f018d"
|
||||||
name = "github.com/gregjones/httpcache"
|
name = "github.com/gregjones/httpcache"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"diskcache"
|
"diskcache",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f"
|
revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
digest = "1:d15ee511aa0f56baacc1eb4c6b922fa1c03b38413b6be18166b996d82a0156ea"
|
||||||
name = "github.com/hashicorp/golang-lru"
|
name = "github.com/hashicorp/golang-lru"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"simplelru"
|
"simplelru",
|
||||||
]
|
]
|
||||||
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
pruneopts = "UT"
|
||||||
|
revision = "7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c"
|
||||||
|
version = "v0.5.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:a0cefd27d12712af4b5018dc7046f245e1e3b5760e2e848c30b171b570708f9b"
|
||||||
name = "github.com/imdario/mergo"
|
name = "github.com/imdario/mergo"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "9316a62528ac99aaecb4e47eadd6dc8aa6533d58"
|
pruneopts = "UT"
|
||||||
version = "v0.3.5"
|
revision = "7c29201646fa3de8506f701213473dd407f19646"
|
||||||
|
version = "v0.3.7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||||
name = "github.com/inconshreveable/mousetrap"
|
name = "github.com/inconshreveable/mousetrap"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||||
version = "v1.0"
|
version = "v1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:d4e6e8584d0a94ce567d237e19192dae44d57d2767ac7e1d7fbf5626d176381a"
|
||||||
name = "github.com/jinzhu/gorm"
|
name = "github.com/jinzhu/gorm"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "6ed508ec6a4ecb3531899a69cbc746ccf65a4166"
|
pruneopts = "UT"
|
||||||
version = "v1.9.1"
|
revision = "472c70caa40267cb89fd8facb07fe6454b578626"
|
||||||
|
version = "v1.9.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:fd97437fbb6b7dce04132cf06775bd258cce305c44add58eb55ca86c6c325160"
|
||||||
name = "github.com/jinzhu/inflection"
|
name = "github.com/jinzhu/inflection"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "04140366298a54a039076d798123ffa108fff46c"
|
revision = "04140366298a54a039076d798123ffa108fff46c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:f5a2051c55d05548d2d4fd23d244027b59fbd943217df8aa3b5e170ac2fd6e1b"
|
||||||
name = "github.com/json-iterator/go"
|
name = "github.com/json-iterator/go"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "5bc93205020f6311d7e4a34f82c5616a18ec35e5"
|
pruneopts = "UT"
|
||||||
|
revision = "0ff49de124c6f76f8494e194af75bde0f1a49a29"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:31e761d97c76151dde79e9d28964a812c46efc5baee4085b86f68f0c654450de"
|
||||||
|
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e"
|
||||||
|
version = "v1.0.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:84a5a2b67486d5d67060ac393aa255d05d24ed5ee41daecd5635ec22657b6492"
|
||||||
name = "github.com/mailru/easyjson"
|
name = "github.com/mailru/easyjson"
|
||||||
packages = [
|
packages = [
|
||||||
"buffer",
|
"buffer",
|
||||||
"jlexer",
|
"jlexer",
|
||||||
"jwriter"
|
"jwriter",
|
||||||
]
|
]
|
||||||
revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485"
|
pruneopts = "UT"
|
||||||
|
revision = "6243d8e04c3f819e79757e8bc3faa15c3cb27003"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:fc2b04b0069d6b10bdef96d278fe20c345794009685ed3c8c7f1a6dc023eefec"
|
||||||
name = "github.com/mattbaird/jsonpatch"
|
name = "github.com/mattbaird/jsonpatch"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f"
|
revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
|
||||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||||
packages = ["pbutil"]
|
packages = ["pbutil"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79"
|
||||||
name = "github.com/mitchellh/go-homedir"
|
name = "github.com/mitchellh/go-homedir"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
|
revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
|
||||||
name = "github.com/modern-go/concurrent"
|
name = "github.com/modern-go/concurrent"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
|
||||||
name = "github.com/modern-go/reflect2"
|
name = "github.com/modern-go/reflect2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:ee4d4af67d93cc7644157882329023ce9a7bcfce956a079069a9405521c7cc8d"
|
||||||
name = "github.com/opencontainers/go-digest"
|
name = "github.com/opencontainers/go-digest"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
||||||
version = "v1.0.0-rc1"
|
version = "v1.0.0-rc1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:e5d0bd87abc2781d14e274807a470acd180f0499f8bf5bb18606e9ec22ad9de9"
|
||||||
name = "github.com/pborman/uuid"
|
name = "github.com/pborman/uuid"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
|
revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
|
||||||
version = "v1.2"
|
version = "v1.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2"
|
||||||
name = "github.com/petar/GoLLRB"
|
name = "github.com/petar/GoLLRB"
|
||||||
packages = ["llrb"]
|
packages = ["llrb"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
|
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:0e7775ebbcf00d8dd28ac663614af924411c868dca3d5aa762af0fae3808d852"
|
||||||
name = "github.com/peterbourgon/diskv"
|
name = "github.com/peterbourgon/diskv"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
|
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
|
||||||
version = "v2.0.1"
|
version = "v2.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
|
||||||
name = "github.com/pkg/errors"
|
name = "github.com/pkg/errors"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
pruneopts = "UT"
|
||||||
version = "v0.8.0"
|
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||||
|
version = "v0.8.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:93a746f1060a8acbcf69344862b2ceced80f854170e1caae089b2834c5fbf7f4"
|
||||||
name = "github.com/prometheus/client_golang"
|
name = "github.com/prometheus/client_golang"
|
||||||
packages = [
|
packages = [
|
||||||
"prometheus",
|
"prometheus",
|
||||||
"prometheus/internal",
|
"prometheus/internal",
|
||||||
"prometheus/promhttp"
|
"prometheus/promhttp",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "505eaef017263e299324067d40ca2c48f6a2cf50"
|
revision = "505eaef017263e299324067d40ca2c48f6a2cf50"
|
||||||
version = "v0.9.2"
|
version = "v0.9.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
|
||||||
name = "github.com/prometheus/client_model"
|
name = "github.com/prometheus/client_model"
|
||||||
packages = ["go"]
|
packages = ["go"]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
|
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:35cf6bdf68db765988baa9c4f10cc5d7dda1126a54bd62e252dbcd0b1fc8da90"
|
||||||
name = "github.com/prometheus/common"
|
name = "github.com/prometheus/common"
|
||||||
packages = [
|
packages = [
|
||||||
"expfmt",
|
"expfmt",
|
||||||
"internal/bitbucket.org/ww/goautoneg",
|
"internal/bitbucket.org/ww/goautoneg",
|
||||||
"model"
|
"model",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
|
revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
|
||||||
version = "v0.2.0"
|
version = "v0.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:01cd0cd47758f04c5604daa3be4637e2afa1e0c15af7e08289e95360369e4f48"
|
||||||
name = "github.com/prometheus/procfs"
|
name = "github.com/prometheus/procfs"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"internal/util",
|
"internal/util",
|
||||||
"iostats",
|
"iostats",
|
||||||
"nfs",
|
"nfs",
|
||||||
"xfs"
|
"xfs",
|
||||||
]
|
]
|
||||||
revision = "bbced9601137e764853b2fad7ec3e2dc4c504e02"
|
pruneopts = "UT"
|
||||||
|
revision = "d0f344d83b0c80a1bc03b547a2374a9ec6711144"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
|
||||||
name = "github.com/spf13/cobra"
|
name = "github.com/spf13/cobra"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||||
version = "v0.0.3"
|
version = "v0.0.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
|
||||||
name = "github.com/spf13/pflag"
|
name = "github.com/spf13/pflag"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
pruneopts = "UT"
|
||||||
version = "v1.0.1"
|
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||||
|
version = "v1.0.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d"
|
||||||
name = "go.uber.org/atomic"
|
name = "go.uber.org/atomic"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
|
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
|
||||||
version = "v1.3.2"
|
version = "v1.3.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:60bf2a5e347af463c42ed31a493d817f8a72f102543060ed992754e689805d1a"
|
||||||
name = "go.uber.org/multierr"
|
name = "go.uber.org/multierr"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
|
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:c52caf7bd44f92e54627a31b85baf06a68333a196b3d8d241480a774733dcf8b"
|
||||||
name = "go.uber.org/zap"
|
name = "go.uber.org/zap"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@@ -413,19 +566,23 @@
|
|||||||
"internal/bufferpool",
|
"internal/bufferpool",
|
||||||
"internal/color",
|
"internal/color",
|
||||||
"internal/exit",
|
"internal/exit",
|
||||||
"zapcore"
|
"zapcore",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
|
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
|
||||||
version = "v1.9.1"
|
version = "v1.9.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:058e9504b9a79bfe86092974d05bb3298d2aa0c312d266d43148de289a5065d9"
|
||||||
name = "golang.org/x/crypto"
|
name = "golang.org/x/crypto"
|
||||||
packages = ["ssh/terminal"]
|
packages = ["ssh/terminal"]
|
||||||
revision = "7f39a6fea4fe9364fb61e1def6a268a51b4f3a06"
|
pruneopts = "UT"
|
||||||
|
revision = "c2843e01d9a2bc60bb26ad24e09734fdc2d9ec58"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:348e38852dac5030f8ce455e1b8d7a5727bbe0af43c0664efd89ec32414093c0"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = [
|
packages = [
|
||||||
"context",
|
"context",
|
||||||
@@ -435,32 +592,38 @@
|
|||||||
"http2/hpack",
|
"http2/hpack",
|
||||||
"idna",
|
"idna",
|
||||||
"internal/socks",
|
"internal/socks",
|
||||||
"proxy"
|
"proxy",
|
||||||
]
|
]
|
||||||
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
|
pruneopts = "UT"
|
||||||
|
revision = "56fb01167e7d1e1d17dd87993d34c963f4356e87"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:5e9f22cf754ab20a5dff0ae04b12516b112c5b81cd44dccccde148865084d730"
|
||||||
name = "golang.org/x/oauth2"
|
name = "golang.org/x/oauth2"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"google",
|
"google",
|
||||||
"internal",
|
"internal",
|
||||||
"jws",
|
"jws",
|
||||||
"jwt"
|
"jwt",
|
||||||
]
|
]
|
||||||
revision = "9b3c75971fc92dd27c6436a37c05c831498658f1"
|
pruneopts = "UT"
|
||||||
|
revision = "e64efc72b421e893cbf63f17ba2221e7d6d0b0f3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:85cd5224b89829559e8327ba2e52e0df72638d33cf3082b066ea9dea34391e2f"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = [
|
packages = [
|
||||||
"unix",
|
"unix",
|
||||||
"windows"
|
"windows",
|
||||||
]
|
]
|
||||||
revision = "fc8bd948cf46f9c7af0f07d34151ce25fe90e477"
|
pruneopts = "UT"
|
||||||
|
revision = "10058d7d4faa7dd5ef860cbd31af00903076e7b8"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:0c56024909189aee3364b7f21a95a27459f718aa7c199a5c111c36cfffd9eaef"
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
packages = [
|
packages = [
|
||||||
"collate",
|
"collate",
|
||||||
@@ -477,24 +640,30 @@
|
|||||||
"unicode/cldr",
|
"unicode/cldr",
|
||||||
"unicode/norm",
|
"unicode/norm",
|
||||||
"unicode/rangetable",
|
"unicode/rangetable",
|
||||||
"width"
|
"width",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||||
version = "v0.3.0"
|
version = "v0.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90"
|
||||||
name = "golang.org/x/time"
|
name = "golang.org/x/time"
|
||||||
packages = ["rate"]
|
packages = ["rate"]
|
||||||
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
|
pruneopts = "UT"
|
||||||
|
revision = "9d24e82272b4f38b78bc8cff74fa936d31ccd8ef"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
digest = "1:6bb2e1cbcf253307a88a531a75aa4d38fecb8d56a0dc9e837e288fe3189954f6"
|
||||||
name = "golang.org/x/tools"
|
name = "golang.org/x/tools"
|
||||||
packages = ["container/intsets"]
|
packages = ["container/intsets"]
|
||||||
revision = "44bee7e801e4a70b5fc9a91ff23830ab4df55d5e"
|
pruneopts = "UT"
|
||||||
|
revision = "00c44ba9c14f88ffdd4fb5bfae57fe8dd6d6afb1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:7bc25c2efff76b31f146caf630c617be9b666c6164f0632050466fbec0500125"
|
||||||
name = "google.golang.org/appengine"
|
name = "google.golang.org/appengine"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@@ -507,24 +676,38 @@
|
|||||||
"internal/modules",
|
"internal/modules",
|
||||||
"internal/remote_api",
|
"internal/remote_api",
|
||||||
"internal/urlfetch",
|
"internal/urlfetch",
|
||||||
"urlfetch"
|
"urlfetch",
|
||||||
]
|
]
|
||||||
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
|
pruneopts = "UT"
|
||||||
version = "v1.1.0"
|
revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1"
|
||||||
|
version = "v1.4.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:af07c44dc04418be522bfd4e21ca9130d58169ea084e3a883e23772003a381c4"
|
||||||
|
name = "gopkg.in/asn1-ber.v1"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "f715ec2f112d1e4195b827ad68cf44017a3ef2b1"
|
||||||
|
version = "v1.3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a"
|
||||||
name = "gopkg.in/inf.v0"
|
name = "gopkg.in/inf.v0"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
|
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
|
||||||
version = "v0.9.1"
|
version = "v0.9.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
pruneopts = "UT"
|
||||||
version = "v2.2.1"
|
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
||||||
|
version = "v2.2.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:26a67eb988225c6a0600c1af0b35e795ac4d23a9c40a7aa178fa2adc0670f1f7"
|
||||||
name = "k8s.io/api"
|
name = "k8s.io/api"
|
||||||
packages = [
|
packages = [
|
||||||
"admission/v1beta1",
|
"admission/v1beta1",
|
||||||
@@ -558,12 +741,14 @@
|
|||||||
"settings/v1alpha1",
|
"settings/v1alpha1",
|
||||||
"storage/v1",
|
"storage/v1",
|
||||||
"storage/v1alpha1",
|
"storage/v1alpha1",
|
||||||
"storage/v1beta1"
|
"storage/v1beta1",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "b503174bad5991eb66f18247f52e41c3258f6348"
|
revision = "b503174bad5991eb66f18247f52e41c3258f6348"
|
||||||
version = "kubernetes-1.12.3"
|
version = "kubernetes-1.12.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:3c38a27df3152aa083018cb7a8d7b5bd5af5e808733ebbc6ae5b5fe10f8b0f84"
|
||||||
name = "k8s.io/apimachinery"
|
name = "k8s.io/apimachinery"
|
||||||
packages = [
|
packages = [
|
||||||
"pkg/api/errors",
|
"pkg/api/errors",
|
||||||
@@ -609,12 +794,27 @@
|
|||||||
"pkg/version",
|
"pkg/version",
|
||||||
"pkg/watch",
|
"pkg/watch",
|
||||||
"third_party/forked/golang/json",
|
"third_party/forked/golang/json",
|
||||||
"third_party/forked/golang/reflect"
|
"third_party/forked/golang/reflect",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "eddba98df674a16931d2d4ba75edc3a389bf633a"
|
revision = "eddba98df674a16931d2d4ba75edc3a389bf633a"
|
||||||
version = "kubernetes-1.12.3"
|
version = "kubernetes-1.12.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "release-1.10"
|
||||||
|
digest = "1:89837c4f0a1aa35aa5993bd0ee002ed0073e505c08bcb716c9941059e1df3da6"
|
||||||
|
name = "k8s.io/apiserver"
|
||||||
|
packages = [
|
||||||
|
"pkg/apis/audit",
|
||||||
|
"pkg/authentication/user",
|
||||||
|
"pkg/authorization/authorizer",
|
||||||
|
"pkg/endpoints/request",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "30d6a91f580b7a2a240dccebc1a35bff2a6940f6"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:7b85a80c96c7294b896204fca216c35d10e63fd0a021b23c5b5fe00f68932420"
|
||||||
name = "k8s.io/client-go"
|
name = "k8s.io/client-go"
|
||||||
packages = [
|
packages = [
|
||||||
"discovery",
|
"discovery",
|
||||||
@@ -754,36 +954,30 @@
|
|||||||
"util/integer",
|
"util/integer",
|
||||||
"util/jsonpath",
|
"util/jsonpath",
|
||||||
"util/retry",
|
"util/retry",
|
||||||
"util/workqueue"
|
"util/workqueue",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "d082d5923d3cc0bfbb066ee5fbdea3d0ca79acf8"
|
revision = "d082d5923d3cc0bfbb066ee5fbdea3d0ca79acf8"
|
||||||
version = "kubernetes-1.12.3"
|
version = "kubernetes-1.12.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "k8s.io/component-base"
|
digest = "1:20ca56a1299fe3787b1cf86c3a0388fbc11d08604783b32a258eca7a947a7fdb"
|
||||||
packages = ["logs"]
|
|
||||||
revision = "1925c57e3358154fd54383773de0c0c7710a9196"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "k8s.io/klog"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0"
|
|
||||||
version = "v0.2.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "k8s.io/kube-openapi"
|
name = "k8s.io/kube-openapi"
|
||||||
packages = ["pkg/util/proto"]
|
packages = ["pkg/util/proto"]
|
||||||
revision = "d50a959ae76a85c7c262a9767ef29f37093c2b8a"
|
pruneopts = "UT"
|
||||||
|
revision = "15615b16d372105f0c69ff47dfe7402926a65aaa"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:ceff1906e568c23d7a337fdda89900d6155aaf93db7cb6da73488ffb649641e1"
|
||||||
name = "k8s.io/kubernetes"
|
name = "k8s.io/kubernetes"
|
||||||
packages = ["pkg/util/slice"]
|
packages = ["pkg/util/slice"]
|
||||||
revision = "721bfa751924da8d1680787490c54b9179b1fed0"
|
pruneopts = "UT"
|
||||||
version = "v1.13.3"
|
revision = "c27b913fddd1a6c480c229191a087698aa92f0b1"
|
||||||
|
version = "v1.13.4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
digest = "1:3c56f356b5cb581860246ca0c08c7a35aa21b2c071b20c428a53b2c3c13c87fd"
|
||||||
name = "sigs.k8s.io/controller-runtime"
|
name = "sigs.k8s.io/controller-runtime"
|
||||||
packages = [
|
packages = [
|
||||||
"pkg/cache",
|
"pkg/cache",
|
||||||
@@ -803,14 +997,68 @@
|
|||||||
"pkg/webhook/admission",
|
"pkg/webhook/admission",
|
||||||
"pkg/webhook/admission/types",
|
"pkg/webhook/admission/types",
|
||||||
"pkg/webhook/internal/metrics",
|
"pkg/webhook/internal/metrics",
|
||||||
"pkg/webhook/types"
|
"pkg/webhook/types",
|
||||||
]
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
revision = "f6f0bc9611363b43664d08fb097ab13243ef621d"
|
revision = "f6f0bc9611363b43664d08fb097ab13243ef621d"
|
||||||
version = "v0.1.9"
|
version = "v0.1.9"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "af7a1befccf91a9979c7710cf95e61ccb7dc4131fd0cc22e585e2e3b8034f92f"
|
input-imports = [
|
||||||
|
"github.com/dgrijalva/jwt-go",
|
||||||
|
"github.com/docker/docker/api/types",
|
||||||
|
"github.com/docker/docker/client",
|
||||||
|
"github.com/emicklei/go-restful",
|
||||||
|
"github.com/emicklei/go-restful-openapi",
|
||||||
|
"github.com/go-ldap/ldap",
|
||||||
|
"github.com/go-openapi/spec",
|
||||||
|
"github.com/go-redis/redis",
|
||||||
|
"github.com/go-sql-driver/mysql",
|
||||||
|
"github.com/golang/glog",
|
||||||
|
"github.com/jinzhu/gorm",
|
||||||
|
"github.com/json-iterator/go",
|
||||||
|
"github.com/mitchellh/go-homedir",
|
||||||
|
"github.com/spf13/cobra",
|
||||||
|
"github.com/spf13/pflag",
|
||||||
|
"golang.org/x/tools/container/intsets",
|
||||||
|
"gopkg.in/yaml.v2",
|
||||||
|
"k8s.io/api/apps/v1",
|
||||||
|
"k8s.io/api/apps/v1beta2",
|
||||||
|
"k8s.io/api/batch/v1",
|
||||||
|
"k8s.io/api/batch/v1beta1",
|
||||||
|
"k8s.io/api/core/v1",
|
||||||
|
"k8s.io/api/extensions/v1beta1",
|
||||||
|
"k8s.io/api/policy/v1beta1",
|
||||||
|
"k8s.io/api/rbac/v1",
|
||||||
|
"k8s.io/api/storage/v1",
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors",
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource",
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
|
"k8s.io/apimachinery/pkg/labels",
|
||||||
|
"k8s.io/apimachinery/pkg/runtime",
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema",
|
||||||
|
"k8s.io/apimachinery/pkg/types",
|
||||||
|
"k8s.io/apimachinery/pkg/util/runtime",
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait",
|
||||||
|
"k8s.io/apiserver/pkg/authorization/authorizer",
|
||||||
|
"k8s.io/apiserver/pkg/endpoints/request",
|
||||||
|
"k8s.io/client-go/informers",
|
||||||
|
"k8s.io/client-go/informers/core/v1",
|
||||||
|
"k8s.io/client-go/informers/rbac/v1",
|
||||||
|
"k8s.io/client-go/kubernetes",
|
||||||
|
"k8s.io/client-go/kubernetes/scheme",
|
||||||
|
"k8s.io/client-go/plugin/pkg/client/auth/gcp",
|
||||||
|
"k8s.io/client-go/rest",
|
||||||
|
"k8s.io/client-go/tools/cache",
|
||||||
|
"k8s.io/client-go/tools/clientcmd",
|
||||||
|
"k8s.io/client-go/util/workqueue",
|
||||||
|
"k8s.io/kubernetes/pkg/util/slice",
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client/config",
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/manager",
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/runtime/log",
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/runtime/signals",
|
||||||
|
]
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
# go-tests = true
|
# go-tests = true
|
||||||
# unused-packages = true
|
# unused-packages = true
|
||||||
|
|
||||||
|
ignored = ["github.com/mholt/caddy","github.com/mholt/caddy/caddyfile","github.com/mholt/caddy/caddyhttp/httpserver","github.com/mholt/caddy/caddyhttp/staticfiles","github.com/mholt/caddy/caddytls","github.com/mholt/caddy/telemetry"]
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/docker/docker"
|
name = "github.com/docker/docker"
|
||||||
version = "v17.05.0-ce"
|
version = "v17.05.0-ce"
|
||||||
|
|||||||
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"kubesphere.io/kubesphere/cmd/ks-apiserver/app"
|
"kubesphere.io/kubesphere/cmd/ks-apiserver/app"
|
||||||
"os"
|
"log"
|
||||||
|
|
||||||
// Install apis
|
// Install apis
|
||||||
_ "kubesphere.io/kubesphere/pkg/apis/metrics/install"
|
_ "kubesphere.io/kubesphere/pkg/apis/metrics/install"
|
||||||
|
_ "kubesphere.io/kubesphere/pkg/apis/monitoring/install"
|
||||||
_ "kubesphere.io/kubesphere/pkg/apis/operations/install"
|
_ "kubesphere.io/kubesphere/pkg/apis/operations/install"
|
||||||
_ "kubesphere.io/kubesphere/pkg/apis/resources/install"
|
_ "kubesphere.io/kubesphere/pkg/apis/resources/install"
|
||||||
)
|
)
|
||||||
@@ -16,7 +32,6 @@ func main() {
|
|||||||
cmd := app.NewAPIServerCommand()
|
cmd := app.NewAPIServerCommand()
|
||||||
|
|
||||||
if err := cmd.Execute(); err != nil {
|
if err := cmd.Execute(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
log.Fatalln(err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
goflag "flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/emicklei/go-restful-openapi"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"kubesphere.io/kubesphere/cmd/ks-apiserver/app/options"
|
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
"kubesphere.io/kubesphere/pkg/client"
|
|
||||||
"kubesphere.io/kubesphere/pkg/filter"
|
"kubesphere.io/kubesphere/pkg/filter"
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/options"
|
||||||
"kubesphere.io/kubesphere/pkg/signals"
|
"kubesphere.io/kubesphere/pkg/signals"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewAPIServerCommand() *cobra.Command {
|
func NewAPIServerCommand() *cobra.Command {
|
||||||
s := options.NewServerRunOptions()
|
s := options.SharedOptions
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "ks-apiserver",
|
Use: "ks-apiserver",
|
||||||
@@ -23,15 +40,13 @@ func NewAPIServerCommand() *cobra.Command {
|
|||||||
for the api objects. The API Server services REST operations and provides the frontend to the
|
for the api objects. The API Server services REST operations and provides the frontend to the
|
||||||
cluster's shared state through which all other components interact.`,
|
cluster's shared state through which all other components interact.`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
//s.AddFlags(cmd.Flags())
|
|
||||||
|
|
||||||
return Run(s)
|
return Run(s)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
s.AddFlags(cmd.Flags())
|
cmd.Flags().AddFlagSet(s.CommandLine)
|
||||||
|
cmd.Flags().AddGoFlagSet(goflag.CommandLine)
|
||||||
|
glog.CopyStandardLogTo("INFO")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,26 +54,11 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
stopChan := signals.SetupSignalHandler()
|
waitForResourceSync()
|
||||||
informers.SharedInformerFactory().Start(stopChan)
|
|
||||||
informers.SharedInformerFactory().WaitForCacheSync(stopChan)
|
|
||||||
log.Println("resources sync success")
|
|
||||||
|
|
||||||
container := runtime.Container
|
container := runtime.Container
|
||||||
container.Filter(filter.Logging)
|
container.Filter(filter.Logging)
|
||||||
|
|
||||||
if len(s.KubeConfig) > 0 {
|
|
||||||
client.KubeConfigFile = s.KubeConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.ApiDoc {
|
|
||||||
config := restfulspec.Config{
|
|
||||||
WebServices: container.RegisteredWebServices(),
|
|
||||||
APIPath: "/apidoc.json",
|
|
||||||
}
|
|
||||||
container.Add(restfulspec.NewOpenAPIService(config))
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Server listening on %d.", s.InsecurePort)
|
log.Printf("Server listening on %d.", s.InsecurePort)
|
||||||
|
|
||||||
if s.InsecurePort != 0 {
|
if s.InsecurePort != 0 {
|
||||||
@@ -71,3 +71,36 @@ func Run(s *options.ServerRunOptions) error {
|
|||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func waitForResourceSync() {
|
||||||
|
stopChan := signals.SetupSignalHandler()
|
||||||
|
|
||||||
|
informerFactory := informers.SharedInformerFactory()
|
||||||
|
informerFactory.Rbac().V1().Roles().Lister()
|
||||||
|
informerFactory.Rbac().V1().RoleBindings().Lister()
|
||||||
|
informerFactory.Rbac().V1().ClusterRoles().Lister()
|
||||||
|
informerFactory.Rbac().V1().ClusterRoleBindings().Lister()
|
||||||
|
|
||||||
|
informerFactory.Storage().V1().StorageClasses().Lister()
|
||||||
|
|
||||||
|
informerFactory.Core().V1().Namespaces().Lister()
|
||||||
|
informerFactory.Core().V1().Nodes().Lister()
|
||||||
|
informerFactory.Core().V1().ResourceQuotas().Lister()
|
||||||
|
informerFactory.Core().V1().Pods().Lister()
|
||||||
|
informerFactory.Core().V1().Services().Lister()
|
||||||
|
informerFactory.Core().V1().PersistentVolumeClaims().Lister()
|
||||||
|
informerFactory.Core().V1().Secrets().Lister()
|
||||||
|
informerFactory.Core().V1().ConfigMaps().Lister()
|
||||||
|
|
||||||
|
informerFactory.Apps().V1().ControllerRevisions().Lister()
|
||||||
|
informerFactory.Apps().V1().StatefulSets().Lister()
|
||||||
|
informerFactory.Apps().V1().Deployments().Lister()
|
||||||
|
informerFactory.Apps().V1().DaemonSets().Lister()
|
||||||
|
|
||||||
|
informerFactory.Batch().V1().Jobs().Lister()
|
||||||
|
informerFactory.Batch().V1beta1().CronJobs()
|
||||||
|
|
||||||
|
informerFactory.Start(stopChan)
|
||||||
|
informerFactory.WaitForCacheSync(stopChan)
|
||||||
|
log.Println("resources sync success")
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,12 +15,20 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package v1alpha2
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"kubesphere.io/kubesphere/pkg/monitoring/v1alpha2/monitoring"
|
"kubesphere.io/kubesphere/cmd/ks-iam/app"
|
||||||
|
"log"
|
||||||
|
// Install apis
|
||||||
|
_ "kubesphere.io/kubesphere/pkg/apis/iam/install"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func main() {
|
||||||
addToWebServiceFuncs = append(addToWebServiceFuncs, monitoring.Route)
|
|
||||||
|
cmd := app.NewAPIServerCommand()
|
||||||
|
|
||||||
|
if err := cmd.Execute(); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
95
cmd/ks-iam/app/server.go
Normal file
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
|
# Push image to dockerhub, need to support multiple push
|
||||||
|
|
||||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||||
|
docker push kubespheredev/ks-apigateway:latest
|
||||||
docker push kubespheredev/ks-apiserver:latest
|
docker push kubespheredev/ks-apiserver:latest
|
||||||
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.
|
limitations under the License.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package monitoring
|
package install
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"kubesphere.io/kubesphere/pkg/monitoring/v1alpha2"
|
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const apiGroup = "monitoring.kubesphere.io"
|
func init() {
|
||||||
|
Install(runtime.Container)
|
||||||
func AddToContainer(container *restful.Container) error {
|
}
|
||||||
container.Add(v1alpha2.WebService(apiGroup))
|
|
||||||
return nil
|
func Install(container *restful.Container) {
|
||||||
|
urlruntime.Must(iamv1alpha2.AddToContainer(container))
|
||||||
}
|
}
|
||||||
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 (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"github.com/emicklei/go-restful-openapi"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/metrics"
|
"kubesphere.io/kubesphere/pkg/apiserver/metrics"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
@@ -36,8 +37,20 @@ var (
|
|||||||
func addWebService(c *restful.Container) error {
|
func addWebService(c *restful.Container) error {
|
||||||
webservice := runtime.NewWebService(GroupVersion)
|
webservice := runtime.NewWebService(GroupVersion)
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}").To(metrics.GetScMetrics))
|
tags := []string{"metrics"}
|
||||||
webservice.Route(webservice.GET("/metrics/storageclass").To(metrics.GetScMetricsList))
|
|
||||||
|
webservice.Route(webservice.GET("/storageclasses/{storageclass}").
|
||||||
|
To(metrics.GetScMetrics).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("").
|
||||||
|
Param(webservice.PathParameter("storageclass", "storageclass's name")).
|
||||||
|
Writes(metrics.ScMetricsItem{}))
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/storageclasses").
|
||||||
|
To(metrics.GetScMetricsList).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("").
|
||||||
|
Writes([]metrics.ScMetricsItem{}))
|
||||||
|
|
||||||
c.Add(webservice)
|
c.Add(webservice)
|
||||||
|
|
||||||
|
|||||||
@@ -15,22 +15,19 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package v1alpha2
|
package install
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
monitoringv1alpha2 "kubesphere.io/kubesphere/pkg/apis/monitoring/v1alpha2"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
const apiVersion = "v1alpha2"
|
func init() {
|
||||||
|
Install(runtime.Container)
|
||||||
var addToWebServiceFuncs []func(ws *restful.WebService)
|
}
|
||||||
|
|
||||||
func WebService(apiGroup string) *restful.WebService {
|
func Install(container *restful.Container) {
|
||||||
ws := new(restful.WebService)
|
urlruntime.Must(monitoringv1alpha2.AddToContainer(container))
|
||||||
ws.Path("/apis/" + apiGroup + "/" + apiVersion).
|
|
||||||
Produces(restful.MIME_JSON).Consumes(restful.MIME_JSON)
|
|
||||||
for _, f := range addToWebServiceFuncs {
|
|
||||||
f(ws)
|
|
||||||
}
|
|
||||||
return ws
|
|
||||||
}
|
}
|
||||||
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"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/operations"
|
"kubesphere.io/kubesphere/pkg/apiserver/operations"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const GroupName = "operations.kubesphere.io"
|
const GroupName = "operations.kubesphere.io"
|
||||||
@@ -36,20 +37,24 @@ var (
|
|||||||
|
|
||||||
func addWebService(c *restful.Container) error {
|
func addWebService(c *restful.Container) error {
|
||||||
|
|
||||||
|
tags := []string{"Operations"}
|
||||||
|
|
||||||
webservice := runtime.NewWebService(GroupVersion)
|
webservice := runtime.NewWebService(GroupVersion)
|
||||||
|
|
||||||
webservice.Route(webservice.POST("/nodes/{node}/drainage").To(operations.DrainNode))
|
webservice.Route(webservice.POST("/nodes/{node}/drainage").
|
||||||
|
To(operations.DrainNode).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("").
|
||||||
|
Param(webservice.PathParameter("node", "node name")).
|
||||||
|
Writes(errors.Error{}))
|
||||||
|
|
||||||
webservice.Route(webservice.POST("/namespaces/{namespace}/jobs/{job}").
|
webservice.Route(webservice.POST("/namespaces/{namespace}/jobs/{job}").
|
||||||
To(operations.RerunJob).
|
To(operations.RerunJob).
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{"jobs"}).
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
Doc("Handle job operation").
|
Doc("Handle job operation").
|
||||||
Param(webservice.PathParameter("job", "job name").
|
Param(webservice.PathParameter("job", "job name")).
|
||||||
DataType("string")).
|
Param(webservice.PathParameter("namespace", "job's namespace")).
|
||||||
Param(webservice.PathParameter("namespace", "job's namespace").
|
Param(webservice.QueryParameter("a", "action")).
|
||||||
DataType("string")).
|
|
||||||
Param(webservice.QueryParameter("a", "action").
|
|
||||||
DataType("string")).
|
|
||||||
Writes(""))
|
Writes(""))
|
||||||
|
|
||||||
c.Add(webservice)
|
c.Add(webservice)
|
||||||
|
|||||||
@@ -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 (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"github.com/emicklei/go-restful-openapi"
|
"github.com/emicklei/go-restful-openapi"
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/components"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/quotas"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/registries"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/resources"
|
"kubesphere.io/kubesphere/pkg/apiserver/resources"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/revisions"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/routers"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/workloadstatuses"
|
||||||
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const GroupName = "resources.kubesphere.io"
|
const GroupName = "resources.kubesphere.io"
|
||||||
@@ -38,18 +49,182 @@ func addWebService(c *restful.Container) error {
|
|||||||
|
|
||||||
webservice := runtime.NewWebService(GroupVersion)
|
webservice := runtime.NewWebService(GroupVersion)
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").To(resources.NamespaceResourceHandler))
|
tags := []string{"Namespace resources"}
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/{resources}").To(resources.ClusterResourceHandler))
|
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").
|
||||||
|
To(resources.NamespaceResourceHandler).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("Namespace level resource query").
|
||||||
|
Param(webservice.PathParameter("namespace", "which namespace")).
|
||||||
|
Param(webservice.PathParameter("resources", "namespace level resource type")).
|
||||||
|
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
|
||||||
|
Required(false).
|
||||||
|
DataFormat("key=%s,key~%s")).
|
||||||
|
Param(webservice.QueryParameter(params.PagingParam, "page").
|
||||||
|
Required(false).
|
||||||
|
DataFormat("limit=%d,page=%d").
|
||||||
|
DefaultValue("limit=10,page=1")).
|
||||||
|
Writes(models.PageableResponse{}))
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").To(resources.GetPvcListBySc))
|
tags = []string{"Cluster resources"}
|
||||||
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").To(resources.GetPodListByPvc))
|
|
||||||
|
|
||||||
tags := []string{"users"}
|
webservice.Route(webservice.GET("/{resources}").
|
||||||
webservice.Route(webservice.GET("/users/{username}/kubectl").Doc("get user's kubectl pod").Param(webservice.PathParameter("username",
|
To(resources.ClusterResourceHandler).
|
||||||
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubectl))
|
Writes(models.PageableResponse{}).
|
||||||
webservice.Route(webservice.GET("/users/{username}/kubeconfig").Doc("get users' kubeconfig").Param(webservice.PathParameter("username",
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
"username").DataType("string")).Metadata(restfulspec.KeyOpenAPITags, tags).To(resources.GetKubeconfig))
|
Doc("Cluster level resource query").
|
||||||
|
Param(webservice.PathParameter("resources", "cluster level resource type"))).
|
||||||
|
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
|
||||||
|
Required(false).
|
||||||
|
DataFormat("key=value,key~value").
|
||||||
|
DefaultValue("")).
|
||||||
|
Param(webservice.QueryParameter(params.PagingParam, "page").
|
||||||
|
Required(false).
|
||||||
|
DataFormat("limit=%d,page=%d").
|
||||||
|
DefaultValue("limit=10,page=1"))
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").
|
||||||
|
To(resources.GetPvcListBySc).
|
||||||
|
Doc("get user's kubectl pod").
|
||||||
|
Param(webservice.PathParameter("username", "username")).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
|
webservice.Route(webservice.GET("/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").
|
||||||
|
To(resources.GetPodListByPvc))
|
||||||
|
|
||||||
|
tags = []string{"User resources"}
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/users/{username}/kubectl").
|
||||||
|
To(resources.GetKubectl).
|
||||||
|
Doc("get user's kubectl pod").
|
||||||
|
Param(webservice.PathParameter("username", "username")).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Writes(models.PodInfo{}))
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/users/{username}/kubeconfig").
|
||||||
|
To(resources.GetKubeconfig).
|
||||||
|
Doc("get users' kubeconfig").
|
||||||
|
Param(webservice.PathParameter("username", "username")).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
|
|
||||||
|
tags = []string{"Components"}
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/components").
|
||||||
|
To(components.GetComponents).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("").
|
||||||
|
Writes(map[string]models.Component{}))
|
||||||
|
webservice.Route(webservice.GET("/components/{component}").
|
||||||
|
To(components.GetComponentStatus).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("").
|
||||||
|
Param(webservice.PathParameter("component", "component name")).
|
||||||
|
Writes(models.Component{}))
|
||||||
|
webservice.Route(webservice.GET("/health").
|
||||||
|
To(components.GetSystemHealthStatus).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("").
|
||||||
|
Writes(map[string]int{}))
|
||||||
|
|
||||||
|
tags = []string{"Quotas"}
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/quotas").
|
||||||
|
To(quotas.GetClusterQuotas).
|
||||||
|
Doc("get whole cluster's resource usage").
|
||||||
|
Writes(models.ResourceQuota{}).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/namespaces/{namespace}/quotas").
|
||||||
|
Doc("get specified namespace's resource quota and usage").
|
||||||
|
Param(webservice.PathParameter("namespace", "namespace's name")).
|
||||||
|
Writes(models.ResourceQuota{}).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
To(quotas.GetNamespaceQuotas))
|
||||||
|
|
||||||
|
tags = []string{"Registries"}
|
||||||
|
|
||||||
|
webservice.Route(webservice.POST("registries/verify").
|
||||||
|
To(registries.RegistryVerify).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("docker registry verify").
|
||||||
|
Writes(errors.Error{}))
|
||||||
|
|
||||||
|
tags = []string{"Revision"}
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}").
|
||||||
|
To(revisions.GetDaemonSetRevision).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("Handle daemonset operation").
|
||||||
|
Param(webservice.PathParameter("daemonset", "daemonset's name")).
|
||||||
|
Param(webservice.PathParameter("namespace", "daemonset's namespace")).
|
||||||
|
Param(webservice.PathParameter("revision", "daemonset's revision")).
|
||||||
|
Writes(appsv1.DaemonSet{}))
|
||||||
|
webservice.Route(webservice.GET("/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}").
|
||||||
|
To(revisions.GetDeployRevision).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("Handle deployment operation").
|
||||||
|
Param(webservice.PathParameter("deployment", "deployment's name")).
|
||||||
|
Param(webservice.PathParameter("namespace", "deployment's namespace")).
|
||||||
|
Param(webservice.PathParameter("revision", "deployment's revision")).
|
||||||
|
Writes(appsv1.ReplicaSet{}))
|
||||||
|
webservice.Route(webservice.GET("/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}").
|
||||||
|
To(revisions.GetStatefulSetRevision).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("Handle statefulset operation").
|
||||||
|
Param(webservice.PathParameter("statefulset", "statefulset's name")).
|
||||||
|
Param(webservice.PathParameter("namespace", "statefulset's namespace")).
|
||||||
|
Param(webservice.PathParameter("revision", "statefulset's revision")).
|
||||||
|
Writes(appsv1.StatefulSet{}))
|
||||||
|
|
||||||
|
tags = []string{"Router"}
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/routers").
|
||||||
|
To(routers.GetAllRouters).
|
||||||
|
Doc("Get all routers").
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Writes(corev1.Service{}))
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/users/{username}/routers").
|
||||||
|
To(routers.GetAllRoutersOfUser).
|
||||||
|
Doc("Get routers for user").
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Param(webservice.PathParameter("username", "")).
|
||||||
|
Writes(corev1.Service{}))
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/namespaces/{namespace}/router").
|
||||||
|
To(routers.GetRouter).
|
||||||
|
Doc("Get router of a specified project").
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Param(webservice.PathParameter("namespace", "name of the project")))
|
||||||
|
|
||||||
|
webservice.Route(webservice.DELETE("/namespaces/{namespace}/router").
|
||||||
|
To(routers.DeleteRouter).
|
||||||
|
Doc("Get router of a specified project").
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Param(webservice.PathParameter("namespace", "name of the project")))
|
||||||
|
|
||||||
|
webservice.Route(webservice.POST("/namespaces/{namespace}/router").
|
||||||
|
To(routers.CreateRouter).
|
||||||
|
Doc("Create a router for a specified project").
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Param(webservice.PathParameter("namespace", "name of the project")))
|
||||||
|
|
||||||
|
webservice.Route(webservice.PUT("/namespaces/{namespace}/router").
|
||||||
|
To(routers.UpdateRouter).
|
||||||
|
Doc("Update a router for a specified project").
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Param(webservice.PathParameter("namespace", "name of the project")))
|
||||||
|
|
||||||
|
tags = []string{"WorkloadStatus"}
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/workloadstatuses").
|
||||||
|
Doc("get abnormal workloads' count of whole cluster").
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
To(workloadstatuses.GetClusterResourceStatus))
|
||||||
|
webservice.Route(webservice.GET("/namespaces/{namespace}/workloadstatuses").
|
||||||
|
Doc("get abnormal workloads' count of specified namespace").
|
||||||
|
Param(webservice.PathParameter("namespace", "the name of namespace")).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
To(workloadstatuses.GetNamespacesResourceStatus))
|
||||||
|
|
||||||
c.Add(webservice)
|
c.Add(webservice)
|
||||||
|
|
||||||
|
|||||||
@@ -22,18 +22,14 @@ import (
|
|||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/components"
|
"kubesphere.io/kubesphere/pkg/models/components"
|
||||||
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func V1Alpha2(ws *restful.WebService) {
|
func GetSystemHealthStatus(request *restful.Request, response *restful.Response) {
|
||||||
ws.Route(ws.GET("/components").To(getComponents))
|
result, err := components.GetSystemHealthStatus()
|
||||||
ws.Route(ws.GET("/components/{component}").To(getComponentStatus))
|
|
||||||
ws.Route(ws.GET("/health").To(getSystemHealthStatus))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSystemHealthStatus(request *restful.Request, response *restful.Response) {
|
if err != nil {
|
||||||
result, err := components.GetAllComponentsStatus()
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,12 +37,13 @@ func getSystemHealthStatus(request *restful.Request, response *restful.Response)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get a specific component status
|
// get a specific component status
|
||||||
func getComponentStatus(request *restful.Request, response *restful.Response) {
|
func GetComponentStatus(request *restful.Request, response *restful.Response) {
|
||||||
component := request.PathParameter("component")
|
component := request.PathParameter("component")
|
||||||
|
|
||||||
result, err := components.GetComponentStatus(component)
|
result, err := components.GetComponentStatus(component)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,11 +51,12 @@ func getComponentStatus(request *restful.Request, response *restful.Response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get all componentsHandler
|
// get all componentsHandler
|
||||||
func getComponents(request *restful.Request, response *restful.Response) {
|
func GetComponents(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
result, err := components.GetAllComponentsStatus()
|
result, err := components.GetAllComponentsStatus()
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
"github.com/emicklei/go-restful"
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/storage"
|
"kubesphere.io/kubesphere/pkg/models/storage"
|
||||||
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type scMetricsItem struct {
|
type ScMetricsItem struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Metrics *storage.ScMetrics `json:"metrics"`
|
Metrics *storage.ScMetrics `json:"metrics"`
|
||||||
}
|
}
|
||||||
@@ -35,11 +36,12 @@ func GetScMetrics(request *restful.Request, response *restful.Response) {
|
|||||||
|
|
||||||
metrics, err := storage.GetScMetrics(scName)
|
metrics, err := storage.GetScMetrics(scName)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := scMetricsItem{
|
result := ScMetricsItem{
|
||||||
Name: scName, Metrics: metrics,
|
Name: scName, Metrics: metrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,21 +53,23 @@ func GetScMetrics(request *restful.Request, response *restful.Response) {
|
|||||||
func GetScMetricsList(request *restful.Request, response *restful.Response) {
|
func GetScMetricsList(request *restful.Request, response *restful.Response) {
|
||||||
scList, err := storage.GetScList()
|
scList, err := storage.GetScList()
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set return value
|
// Set return value
|
||||||
items := make([]scMetricsItem, 0)
|
items := make([]ScMetricsItem, 0)
|
||||||
|
|
||||||
for _, v := range scList {
|
for _, v := range scList {
|
||||||
metrics, err := storage.GetScMetrics(v.GetName())
|
metrics, err := storage.GetScMetrics(v.GetName())
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
item := scMetricsItem{
|
item := ScMetricsItem{
|
||||||
Name: v.GetName(), Metrics: metrics,
|
Name: v.GetName(), Metrics: metrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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
|
package operations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/workloads"
|
"kubesphere.io/kubesphere/pkg/models/workloads"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
|
||||||
@@ -40,10 +39,11 @@ func RerunJob(req *restful.Request, resp *restful.Response) {
|
|||||||
case "rerun":
|
case "rerun":
|
||||||
err = workloads.JobReRun(namespace, job)
|
err = workloads.JobReRun(namespace, job)
|
||||||
default:
|
default:
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, fmt.Sprintf("invalid operation %s", action)))
|
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid operation %s", action)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package operations
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/nodes"
|
"kubesphere.io/kubesphere/pkg/models/nodes"
|
||||||
@@ -31,7 +32,8 @@ func DrainNode(request *restful.Request, response *restful.Response) {
|
|||||||
|
|
||||||
err := nodes.DrainNode(nodeName)
|
err := nodes.DrainNode(nodeName)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,48 +20,30 @@ package quotas
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"github.com/emicklei/go-restful-openapi"
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/quotas"
|
"kubesphere.io/kubesphere/pkg/models/quotas"
|
||||||
)
|
)
|
||||||
|
|
||||||
func V1Alpha2(ws *restful.WebService) {
|
func GetNamespaceQuotas(req *restful.Request, resp *restful.Response) {
|
||||||
|
|
||||||
tags := []string{"quotas"}
|
|
||||||
|
|
||||||
ws.Route(ws.GET("/quotas").
|
|
||||||
To(getClusterQuotas).
|
|
||||||
Doc("get whole cluster's resource usage").
|
|
||||||
Writes(quotas.ResourceQuota{}).
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
|
||||||
|
|
||||||
ws.Route(ws.GET("/namespaces/{namespace}/quotas").
|
|
||||||
Doc("get specified namespace's resource quota and usage").
|
|
||||||
Param(ws.PathParameter("namespace", "namespace's name").
|
|
||||||
DataType("string")).
|
|
||||||
Writes(quotas.ResourceQuota{}).
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
|
||||||
To(getNamespaceQuotas))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNamespaceQuotas(req *restful.Request, resp *restful.Response) {
|
|
||||||
namespace := req.PathParameter("namespace")
|
namespace := req.PathParameter("namespace")
|
||||||
quota, err := quotas.GetNamespaceQuotas(namespace)
|
quota, err := quotas.GetNamespaceQuotas(namespace)
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.WriteAsJson(quota)
|
resp.WriteAsJson(quota)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getClusterQuotas(req *restful.Request, resp *restful.Response) {
|
func GetClusterQuotas(req *restful.Request, resp *restful.Response) {
|
||||||
quota, err := quotas.GetClusterQuotas()
|
quota, err := quotas.GetClusterQuotas()
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,55 +20,29 @@ package registries
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/registries"
|
"kubesphere.io/kubesphere/pkg/models/registries"
|
||||||
)
|
)
|
||||||
|
|
||||||
func V1Alpha2(ws *restful.WebService) {
|
func RegistryVerify(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
ws.Route(ws.POST("registries/verify").To(registryVerify))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func registryVerify(request *restful.Request, response *restful.Response) {
|
|
||||||
|
|
||||||
authInfo := registries.AuthInfo{}
|
authInfo := registries.AuthInfo{}
|
||||||
|
|
||||||
err := request.ReadEntity(&authInfo)
|
err := request.ReadEntity(&authInfo)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = registries.RegistryVerify(authInfo)
|
err = registries.RegistryVerify(authInfo)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteAsJson(errors.None)
|
response.WriteAsJson(errors.None)
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (c *registriesHandler) handlerImageSearch(request *restful.Request, response *restful.Response) {
|
|
||||||
//
|
|
||||||
// registry := request.PathParameter("name")
|
|
||||||
// searchWord := request.PathParameter("searchWord")
|
|
||||||
// namespace := request.PathParameter("namespace")
|
|
||||||
//
|
|
||||||
// res := c.registries.ImageSearch(namespace, registry, searchWord)
|
|
||||||
//
|
|
||||||
// response.WriteAsJson(res)
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (c *registriesHandler) handlerGetImageTags(request *restful.Request, response *restful.Response) {
|
|
||||||
//
|
|
||||||
// registry := request.PathParameter("name")
|
|
||||||
// image := request.QueryParameter("image")
|
|
||||||
// namespace := request.PathParameter("namespace")
|
|
||||||
//
|
|
||||||
// res := c.registries.GetImageTags(namespace, registry, image)
|
|
||||||
//
|
|
||||||
// response.WriteAsJson(res)
|
|
||||||
//}
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package resources
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||||
@@ -27,14 +28,15 @@ import (
|
|||||||
|
|
||||||
func ClusterResourceHandler(req *restful.Request, resp *restful.Response) {
|
func ClusterResourceHandler(req *restful.Request, resp *restful.Response) {
|
||||||
resourceName := req.PathParameter("resources")
|
resourceName := req.PathParameter("resources")
|
||||||
conditions := req.QueryParameter(params.Conditions)
|
conditions, err := params.ParseConditions(req)
|
||||||
orderBy := req.QueryParameter(params.OrderBy)
|
orderBy := req.QueryParameter(params.OrderByParam)
|
||||||
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging))
|
limit, offset := params.ParsePaging(req)
|
||||||
reverse := params.ParseReserve(req.QueryParameter(params.Reserve))
|
reverse := params.ParseReverse(req)
|
||||||
|
|
||||||
result, err := resources.ListClusterResource(resourceName, conditions, orderBy, reverse, limit, offset)
|
result, err := resources.ListClusterResource(resourceName, conditions, orderBy, reverse, limit, offset)
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package resources
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||||
@@ -28,14 +29,15 @@ import (
|
|||||||
func NamespaceResourceHandler(req *restful.Request, resp *restful.Response) {
|
func NamespaceResourceHandler(req *restful.Request, resp *restful.Response) {
|
||||||
namespace := req.PathParameter("namespace")
|
namespace := req.PathParameter("namespace")
|
||||||
resourceName := req.PathParameter("resources")
|
resourceName := req.PathParameter("resources")
|
||||||
conditions := req.QueryParameter(params.Conditions)
|
conditions, err := params.ParseConditions(req)
|
||||||
orderBy := req.QueryParameter(params.OrderBy)
|
orderBy := req.QueryParameter(params.OrderByParam)
|
||||||
limit, offset := params.ParsePaging(req.QueryParameter(params.Paging))
|
limit, offset := params.ParsePaging(req)
|
||||||
reverse := params.ParseReserve(req.QueryParameter(params.Reserve))
|
reverse := params.ParseReverse(req)
|
||||||
|
|
||||||
result, err := resources.ListNamespaceResource(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
|
result, err := resources.ListNamespaceResource(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package resources
|
|||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/storage"
|
"kubesphere.io/kubesphere/pkg/models/storage"
|
||||||
@@ -43,7 +44,8 @@ func GetPodListByPvc(request *restful.Request, response *restful.Response) {
|
|||||||
pvcName := request.PathParameter("pvc")
|
pvcName := request.PathParameter("pvc")
|
||||||
nsName := request.PathParameter("namespace")
|
nsName := request.PathParameter("namespace")
|
||||||
pods, err := storage.GetPodListByPvc(pvcName, nsName)
|
pods, err := storage.GetPodListByPvc(pvcName, nsName)
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result := podListByPvc{Name: pvcName, Namespace: nsName, Pods: pods}
|
result := podListByPvc{Name: pvcName, Namespace: nsName, Pods: pods}
|
||||||
@@ -56,7 +58,8 @@ func GetPvcListBySc(request *restful.Request, response *restful.Response) {
|
|||||||
scName := request.PathParameter("storageclass")
|
scName := request.PathParameter("storageclass")
|
||||||
claims, err := storage.GetPvcListBySc(scName)
|
claims, err := storage.GetPvcListBySc(scName)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package resources
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
|
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
|
||||||
@@ -31,7 +32,8 @@ func GetKubectl(req *restful.Request, resp *restful.Response) {
|
|||||||
|
|
||||||
kubectlPod, err := kubectl.GetKubectlPod(user)
|
kubectlPod, err := kubectl.GetKubectlPod(user)
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +46,8 @@ func GetKubeconfig(req *restful.Request, resp *restful.Response) {
|
|||||||
|
|
||||||
kubectlConfig, err := kubeconfig.GetKubeConfig(user)
|
kubectlConfig, err := kubeconfig.GetKubeConfig(user)
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,93 +22,59 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"github.com/emicklei/go-restful-openapi"
|
|
||||||
"k8s.io/api/apps/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/revisions"
|
"kubesphere.io/kubesphere/pkg/models/revisions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func V1Alpha2(ws *restful.WebService) {
|
func GetDaemonSetRevision(req *restful.Request, resp *restful.Response) {
|
||||||
ws.Route(ws.GET("/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}").
|
|
||||||
To(getDaemonSetRevision).
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{"daemonsets", "revision"}).
|
|
||||||
Doc("Handle daemonset operation").
|
|
||||||
Param(ws.PathParameter("daemonset", "daemonset's name").
|
|
||||||
DataType("string")).
|
|
||||||
Param(ws.PathParameter("namespace", "daemonset's namespace").
|
|
||||||
DataType("string")).
|
|
||||||
Param(ws.PathParameter("revision", "daemonset's revision")).
|
|
||||||
Writes(v1.DaemonSet{}))
|
|
||||||
ws.Route(ws.GET("/namespaces/{namespace}/deployments/{deployment}/revisions/{revision}").
|
|
||||||
To(getDeployRevision).
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{"deployments", "revision"}).
|
|
||||||
Doc("Handle deployment operation").
|
|
||||||
Param(ws.PathParameter("deployment", "deployment's name").
|
|
||||||
DataType("string")).
|
|
||||||
Param(ws.PathParameter("namespace",
|
|
||||||
"deployment's namespace").
|
|
||||||
DataType("string")).
|
|
||||||
Param(ws.PathParameter("deployment", "deployment's name")).
|
|
||||||
Writes(v1.ReplicaSet{}))
|
|
||||||
ws.Route(ws.GET("/namespaces/{namespace}/statefulsets/{statefulset}/revisions/{revision}").
|
|
||||||
To(getStatefulSetRevision).
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{"statefulsets", "revisions"}).
|
|
||||||
Doc("Handle statefulset operation").
|
|
||||||
Param(ws.PathParameter("statefulset", "statefulset's name").
|
|
||||||
DataType("string")).
|
|
||||||
Param(ws.PathParameter("namespace", "statefulset's namespace").
|
|
||||||
DataType("string")).
|
|
||||||
Param(ws.PathParameter("revision", "statefulset's revision")).
|
|
||||||
Writes(v1.StatefulSet{}))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDaemonSetRevision(req *restful.Request, resp *restful.Response) {
|
|
||||||
daemonset := req.PathParameter("daemonset")
|
daemonset := req.PathParameter("daemonset")
|
||||||
namespace := req.PathParameter("namespace")
|
namespace := req.PathParameter("namespace")
|
||||||
revision, err := strconv.Atoi(req.PathParameter("revision"))
|
revision, err := strconv.Atoi(req.PathParameter("revision"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := revisions.GetDaemonSetRevision(namespace, daemonset, revision)
|
result, err := revisions.GetDaemonSetRevision(namespace, daemonset, revision)
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.WriteAsJson(result)
|
resp.WriteAsJson(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDeployRevision(req *restful.Request, resp *restful.Response) {
|
func GetDeployRevision(req *restful.Request, resp *restful.Response) {
|
||||||
deploy := req.PathParameter("deployment")
|
deploy := req.PathParameter("deployment")
|
||||||
namespace := req.PathParameter("namespace")
|
namespace := req.PathParameter("namespace")
|
||||||
revision := req.PathParameter("revision")
|
revision := req.PathParameter("revision")
|
||||||
|
|
||||||
result, err := revisions.GetDeployRevision(namespace, deploy, revision)
|
result, err := revisions.GetDeployRevision(namespace, deploy, revision)
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.WriteAsJson(result)
|
resp.WriteAsJson(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStatefulSetRevision(req *restful.Request, resp *restful.Response) {
|
func GetStatefulSetRevision(req *restful.Request, resp *restful.Response) {
|
||||||
statefulset := req.PathParameter("statefulset")
|
statefulset := req.PathParameter("statefulset")
|
||||||
namespace := req.PathParameter("namespace")
|
namespace := req.PathParameter("namespace")
|
||||||
revision, err := strconv.Atoi(req.PathParameter("revision"))
|
revision, err := strconv.Atoi(req.PathParameter("revision"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := revisions.GetStatefulSetRevision(namespace, statefulset, revision)
|
result, err := revisions.GetStatefulSetRevision(namespace, statefulset, revision)
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,58 +19,31 @@
|
|||||||
package routers
|
package routers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/routers"
|
"kubesphere.io/kubesphere/pkg/models/routers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func V1Alpha2(ws *restful.WebService) {
|
|
||||||
ws.Route(ws.GET("/routers").To(getAllRouters).
|
|
||||||
Doc("Get all routers"))
|
|
||||||
|
|
||||||
ws.Route(ws.GET("/users/{username}/routers").To(getAllRoutersOfUser).
|
|
||||||
Doc("Get routers for user"))
|
|
||||||
|
|
||||||
ws.Route(ws.GET("/namespaces/{namespace}/router").To(getRouter).
|
|
||||||
Doc("Get router of a specified project").
|
|
||||||
Param(ws.PathParameter("namespace", "name of the project").
|
|
||||||
DataType("string")))
|
|
||||||
|
|
||||||
ws.Route(ws.DELETE("/namespaces/{namespace}/router").To(deleteRouter).
|
|
||||||
Doc("Get router of a specified project").
|
|
||||||
Param(ws.PathParameter("namespace", "name of the project").
|
|
||||||
DataType("string")))
|
|
||||||
|
|
||||||
ws.Route(ws.POST("/namespaces/{namespace}/router").To(createRouter).
|
|
||||||
Doc("Create a router for a specified project").
|
|
||||||
Param(ws.PathParameter("namespace", "name of the project").
|
|
||||||
DataType("string")))
|
|
||||||
|
|
||||||
ws.Route(ws.PUT("/namespaces/{namespace}/router").To(updateRouter).
|
|
||||||
Doc("Update a router for a specified project").
|
|
||||||
Param(ws.PathParameter("namespace", "name of the project").
|
|
||||||
DataType("string")))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Router struct {
|
type Router struct {
|
||||||
RouterType string `json:"type"`
|
RouterType string `json:"type"`
|
||||||
Annotations map[string]string `json:"annotations"`
|
Annotations map[string]string `json:"annotations"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all namespace ingress controller services
|
// Get all namespace ingress controller services
|
||||||
func getAllRouters(request *restful.Request, response *restful.Response) {
|
func GetAllRouters(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
routers, err := routers.GetAllRouters()
|
routers, err := routers.GetAllRouters()
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,13 +51,14 @@ func getAllRouters(request *restful.Request, response *restful.Response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get all namespace ingress controller services for user
|
// Get all namespace ingress controller services for user
|
||||||
func getAllRoutersOfUser(request *restful.Request, response *restful.Response) {
|
func GetAllRoutersOfUser(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
username := request.PathParameter("username")
|
username := request.PathParameter("username")
|
||||||
|
|
||||||
routers, err := routers.GetAllRoutersOfUser(username)
|
routers, err := routers.GetAllRoutersOfUser(username)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,12 +66,13 @@ func getAllRoutersOfUser(request *restful.Request, response *restful.Response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get ingress controller service for specified namespace
|
// Get ingress controller service for specified namespace
|
||||||
func getRouter(request *restful.Request, response *restful.Response) {
|
func GetRouter(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
namespace := request.PathParameter("namespace")
|
namespace := request.PathParameter("namespace")
|
||||||
router, err := routers.GetRouter(namespace)
|
router, err := routers.GetRouter(namespace)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +80,7 @@ func getRouter(request *restful.Request, response *restful.Response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create ingress controller and related services
|
// Create ingress controller and related services
|
||||||
func createRouter(request *restful.Request, response *restful.Response) {
|
func CreateRouter(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
namespace := request.PathParameter("namespace")
|
namespace := request.PathParameter("namespace")
|
||||||
|
|
||||||
@@ -119,18 +94,17 @@ func createRouter(request *restful.Request, response *restful.Response) {
|
|||||||
|
|
||||||
var router *v1.Service
|
var router *v1.Service
|
||||||
|
|
||||||
serviceType, annotationMap, err := ParseParameter(newRouter)
|
serviceType, annotationMap, err := parseParameter(newRouter)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("Wrong annotations, missing key or value")
|
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("wrong annotations, missing key or value")))
|
||||||
response.WriteHeaderAndEntity(http.StatusBadRequest,
|
|
||||||
errors.New(errors.InvalidArgument, "Wrong annotations, missing key or value"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
router, err = routers.CreateRouter(namespace, serviceType, annotationMap)
|
router, err = routers.CreateRouter(namespace, serviceType, annotationMap)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,19 +112,20 @@ func createRouter(request *restful.Request, response *restful.Response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete ingress controller and services
|
// Delete ingress controller and services
|
||||||
func deleteRouter(request *restful.Request, response *restful.Response) {
|
func DeleteRouter(request *restful.Request, response *restful.Response) {
|
||||||
namespace := request.PathParameter("namespace")
|
namespace := request.PathParameter("namespace")
|
||||||
|
|
||||||
router, err := routers.DeleteRouter(namespace)
|
router, err := routers.DeleteRouter(namespace)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteAsJson(router)
|
response.WriteAsJson(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRouter(request *restful.Request, response *restful.Response) {
|
func UpdateRouter(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
namespace := request.PathParameter("namespace")
|
namespace := request.PathParameter("namespace")
|
||||||
|
|
||||||
@@ -158,23 +133,23 @@ func updateRouter(request *restful.Request, response *restful.Response) {
|
|||||||
err := request.ReadEntity(&newRouter)
|
err := request.ReadEntity(&newRouter)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error(err)
|
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||||
response.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceType, annotationMap, err := ParseParameter(newRouter)
|
serviceType, annotationMap, err := parseParameter(newRouter)
|
||||||
|
|
||||||
router, err := routers.UpdateRouter(namespace, serviceType, annotationMap)
|
router, err := routers.UpdateRouter(namespace, serviceType, annotationMap)
|
||||||
|
|
||||||
if errors.HandlerError(err, response) {
|
if err != nil {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteAsJson(router)
|
response.WriteAsJson(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseParameter(router Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) {
|
func parseParameter(router Router) (routerType v1.ServiceType, annotationMap map[string]string, err error) {
|
||||||
|
|
||||||
routerType = v1.ServiceTypeNodePort
|
routerType = v1.ServiceTypeNodePort
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ type ContainerBuilder []func(c *restful.Container) error
|
|||||||
func NewWebService(gv schema.GroupVersion) *restful.WebService {
|
func NewWebService(gv schema.GroupVersion) *restful.WebService {
|
||||||
webservice := restful.WebService{}
|
webservice := restful.WebService{}
|
||||||
|
|
||||||
webservice.Path(ApiRootPath + "/" + gv.String())
|
webservice.Path(ApiRootPath + "/" + gv.String()).
|
||||||
|
Consumes(restful.MIME_JSON).
|
||||||
|
Produces(restful.MIME_JSON)
|
||||||
|
|
||||||
return &webservice
|
return &webservice
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,39 +20,25 @@ package workloadstatuses
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"github.com/emicklei/go-restful-openapi"
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/status"
|
"kubesphere.io/kubesphere/pkg/models/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
func V1Alpha2(ws *restful.WebService) {
|
func GetClusterResourceStatus(req *restful.Request, resp *restful.Response) {
|
||||||
tags := []string{"workloadStatus"}
|
|
||||||
|
|
||||||
ws.Route(ws.GET("/workloadstatuses").
|
|
||||||
Doc("get abnormal workloads' count of whole cluster").
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
|
||||||
To(getClusterResourceStatus))
|
|
||||||
ws.Route(ws.GET("/namespaces/{namespace}/workloadstatuses").
|
|
||||||
Doc("get abnormal workloads' count of specified namespace").
|
|
||||||
Param(ws.PathParameter("namespace", "the name of namespace").
|
|
||||||
DataType("string")).
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
|
||||||
To(getNamespacesResourceStatus))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func getClusterResourceStatus(req *restful.Request, resp *restful.Response) {
|
|
||||||
res, err := status.GetClusterResourceStatus()
|
res, err := status.GetClusterResourceStatus()
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp.WriteAsJson(res)
|
resp.WriteAsJson(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNamespacesResourceStatus(req *restful.Request, resp *restful.Response) {
|
func GetNamespacesResourceStatus(req *restful.Request, resp *restful.Response) {
|
||||||
res, err := status.GetNamespacesResourceStatus(req.PathParameter("namespace"))
|
res, err := status.GetNamespacesResourceStatus(req.PathParameter("namespace"))
|
||||||
if errors.HandlerError(err, resp) {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp.WriteAsJson(res)
|
resp.WriteAsJson(res)
|
||||||
|
|||||||
@@ -16,491 +16,3 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
package workspaces
|
package workspaces
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
|
||||||
)
|
|
||||||
|
|
||||||
const UserNameHeader = "X-Token-Username"
|
|
||||||
|
|
||||||
func V1Alpha2(ws *restful.WebService) {
|
|
||||||
ws.Route(ws.GET("/workspaces").To(UserWorkspaceListHandler))
|
|
||||||
ws.Route(ws.POST("/workspaces").To(WorkspaceCreateHandler))
|
|
||||||
ws.Route(ws.DELETE("/workspaces/{name}").To(DeleteWorkspaceHandler))
|
|
||||||
ws.Route(ws.GET("/workspaces/{name}").To(WorkspaceDetailHandler))
|
|
||||||
ws.Route(ws.PUT("/workspaces/{name}").To(WorkspaceEditHandler))
|
|
||||||
ws.Route(ws.GET("/workspaces/{workspace}/namespaces").To(UserNamespaceListHandler))
|
|
||||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{username}/namespaces").To(UserNamespaceListHandler))
|
|
||||||
ws.Route(ws.POST("/workspaces/{name}/namespaces").To(NamespaceCreateHandler))
|
|
||||||
ws.Route(ws.DELETE("/workspaces/{name}/namespaces/{namespace}").To(NamespaceDeleteHandler))
|
|
||||||
ws.Route(ws.GET("/workspaces/{name}/namespaces/{namespace}").To(NamespaceCheckHandler))
|
|
||||||
ws.Route(ws.GET("/namespaces/{namespace}").To(NamespaceCheckHandler))
|
|
||||||
ws.Route(ws.GET("/workspaces/{name}/devops").To(DevOpsProjectHandler))
|
|
||||||
ws.Route(ws.GET("/workspaces/{name}/members/{username}/devops").To(DevOpsProjectHandler))
|
|
||||||
ws.Route(ws.POST("/workspaces/{name}/devops").To(DevOpsProjectCreateHandler))
|
|
||||||
ws.Route(ws.DELETE("/workspaces/{name}/devops/{id}").To(DevOpsProjectDeleteHandler))
|
|
||||||
|
|
||||||
ws.Route(ws.GET("/workspaces/{name}/members").To(MembersHandler))
|
|
||||||
ws.Route(ws.GET("/workspaces/{name}/members/{member}").To(MemberHandler))
|
|
||||||
ws.Route(ws.GET("/workspaces/{name}/roles").To(RolesHandler))
|
|
||||||
// TODO /workspaces/{name}/roles/{role}
|
|
||||||
ws.Route(ws.POST("/workspaces/{name}/members").To(MembersInviteHandler))
|
|
||||||
ws.Route(ws.DELETE("/workspaces/{name}/members").To(MembersRemoveHandler))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RolesHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
name := req.PathParameter("name")
|
|
||||||
|
|
||||||
workspace, err := workspaces.Detail(name)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
roles, err := workspaces.Roles(workspace)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(roles)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MembersHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
keyword := req.QueryParameter("keyword")
|
|
||||||
|
|
||||||
users, err := workspaces.GetWorkspaceMembers(workspace, keyword)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(users)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MemberHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
username := req.PathParameter("member")
|
|
||||||
|
|
||||||
user, err := iam.GetUser(username)
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
namespaces, err := workspaces.Namespaces(workspace)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
user.WorkspaceRole = user.WorkspaceRoles[workspace]
|
|
||||||
|
|
||||||
roles := make(map[string]string)
|
|
||||||
|
|
||||||
for _, namespace := range namespaces {
|
|
||||||
if role := user.Roles[namespace.Name]; role != "" {
|
|
||||||
roles[namespace.Name] = role
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
user.Roles = roles
|
|
||||||
user.Rules = nil
|
|
||||||
user.WorkspaceRules = nil
|
|
||||||
user.WorkspaceRoles = nil
|
|
||||||
user.ClusterRules = nil
|
|
||||||
resp.WriteAsJson(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MembersInviteHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
var users []workspaces.UserInvite
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
err := req.ReadEntity(&users)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = workspaces.Invite(workspace, users)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(errors.None)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MembersRemoveHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
query := req.QueryParameter("name")
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
|
|
||||||
names := strings.Split(query, ",")
|
|
||||||
|
|
||||||
err := workspaces.RemoveMembers(workspace, names)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(errors.None)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
namespace := req.PathParameter("namespace")
|
|
||||||
|
|
||||||
exist, err := workspaces.NamespaceExistCheck(namespace)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(map[string]bool{"exist": exist})
|
|
||||||
}
|
|
||||||
|
|
||||||
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
namespace := req.PathParameter("namespace")
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
|
|
||||||
err := workspaces.DeleteNamespace(workspace, namespace)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(errors.None)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
devops := req.PathParameter("id")
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
force := req.QueryParameter("force")
|
|
||||||
username := req.HeaderParameter(UserNameHeader)
|
|
||||||
|
|
||||||
err := workspaces.UnBindDevopsProject(workspace, devops)
|
|
||||||
|
|
||||||
if err != nil && force != "true" {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.New(errors.Internal, err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = workspaces.DeleteDevopsProject(username, devops)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(errors.None)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
username := req.HeaderParameter(UserNameHeader)
|
|
||||||
|
|
||||||
var devops workspaces.DevopsProject
|
|
||||||
|
|
||||||
err := req.ReadEntity(&devops)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(project)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
username := req.HeaderParameter(UserNameHeader)
|
|
||||||
|
|
||||||
namespace := &v1.Namespace{}
|
|
||||||
|
|
||||||
err := req.ReadEntity(namespace)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if namespace.Annotations == nil {
|
|
||||||
namespace.Annotations = make(map[string]string, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace.Annotations["creator"] = username
|
|
||||||
namespace.Annotations["workspace"] = workspace
|
|
||||||
|
|
||||||
if namespace.Labels == nil {
|
|
||||||
namespace.Labels = make(map[string]string, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace.Labels["kubesphere.io/workspace"] = workspace
|
|
||||||
|
|
||||||
namespace, err = workspaces.CreateNamespace(namespace)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(namespace)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
workspace := req.PathParameter("name")
|
|
||||||
username := req.PathParameter("username")
|
|
||||||
keyword := req.QueryParameter("keyword")
|
|
||||||
|
|
||||||
if username == "" {
|
|
||||||
username = req.HeaderParameter(UserNameHeader)
|
|
||||||
}
|
|
||||||
|
|
||||||
limit := 65535
|
|
||||||
offset := 0
|
|
||||||
orderBy := "createTime"
|
|
||||||
reverse := true
|
|
||||||
|
|
||||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
|
|
||||||
limit, _ = strconv.Atoi(groups[1])
|
|
||||||
page, _ := strconv.Atoi(groups[2])
|
|
||||||
offset = (page - 1) * limit
|
|
||||||
}
|
|
||||||
|
|
||||||
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
|
|
||||||
orderBy = groups[1]
|
|
||||||
reverse = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if q := req.QueryParameter("reverse"); q != "" {
|
|
||||||
b, err := strconv.ParseBool(q)
|
|
||||||
if err == nil {
|
|
||||||
reverse = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
result := models.PageableResponse{}
|
|
||||||
result.TotalCount = total
|
|
||||||
result.Items = make([]interface{}, 0)
|
|
||||||
for _, n := range devOpsProjects {
|
|
||||||
result.Items = append(result.Items, n)
|
|
||||||
}
|
|
||||||
resp.WriteAsJson(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
var workspace workspaces.Workspace
|
|
||||||
username := req.HeaderParameter(UserNameHeader)
|
|
||||||
err := req.ReadEntity(&workspace)
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
workspace.Path = workspace.Name
|
|
||||||
workspace.Members = nil
|
|
||||||
|
|
||||||
if workspace.Admin != "" {
|
|
||||||
workspace.Creator = workspace.Admin
|
|
||||||
} else {
|
|
||||||
workspace.Creator = username
|
|
||||||
}
|
|
||||||
|
|
||||||
created, err := workspaces.Create(&workspace)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(created)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
name := req.PathParameter("name")
|
|
||||||
|
|
||||||
if name == "" || strings.Contains(name, ":") {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
workspace, err := workspaces.Detail(name)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = workspaces.Delete(workspace)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(errors.None)
|
|
||||||
}
|
|
||||||
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
var workspace workspaces.Workspace
|
|
||||||
name := req.PathParameter("name")
|
|
||||||
err := req.ReadEntity(&workspace)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if name != workspace.Name {
|
|
||||||
resp.WriteError(http.StatusBadRequest, fmt.Errorf("the name of workspace (%s) does not match the name on the URL (%s)", workspace.Name, name))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(errors.InvalidArgument, "invalid workspace name"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
workspace.Path = workspace.Name
|
|
||||||
|
|
||||||
workspace.Members = nil
|
|
||||||
|
|
||||||
edited, err := workspaces.Edit(&workspace)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(edited)
|
|
||||||
}
|
|
||||||
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
name := req.PathParameter("name")
|
|
||||||
|
|
||||||
workspace, err := workspaces.Detail(name)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(workspace)
|
|
||||||
}
|
|
||||||
|
|
||||||
// List all workspaces for the current user
|
|
||||||
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
keyword := req.QueryParameter("keyword")
|
|
||||||
username := req.HeaderParameter(UserNameHeader)
|
|
||||||
|
|
||||||
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(ws, func(i, j int) bool {
|
|
||||||
t1, err := ws[i].GetCreateTime()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t2, err := ws[j].GetCreateTime()
|
|
||||||
if err != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return t1.After(t2)
|
|
||||||
})
|
|
||||||
|
|
||||||
resp.WriteAsJson(ws)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
|
|
||||||
withMetrics, err := strconv.ParseBool(req.QueryParameter("metrics"))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
withMetrics = false
|
|
||||||
}
|
|
||||||
|
|
||||||
username := req.PathParameter("username")
|
|
||||||
keyword := req.QueryParameter("keyword")
|
|
||||||
if username == "" {
|
|
||||||
username = req.HeaderParameter(UserNameHeader)
|
|
||||||
}
|
|
||||||
limit := 65535
|
|
||||||
offset := 0
|
|
||||||
orderBy := "createTime"
|
|
||||||
reverse := true
|
|
||||||
|
|
||||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
|
|
||||||
limit, _ = strconv.Atoi(groups[1])
|
|
||||||
page, _ := strconv.Atoi(groups[2])
|
|
||||||
if page < 0 {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
offset = (page - 1) * limit
|
|
||||||
}
|
|
||||||
|
|
||||||
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
|
|
||||||
orderBy = groups[1]
|
|
||||||
reverse = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if q := req.QueryParameter("reverse"); q != "" {
|
|
||||||
b, err := strconv.ParseBool(q)
|
|
||||||
if err == nil {
|
|
||||||
reverse = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
workspaceName := req.PathParameter("workspace")
|
|
||||||
|
|
||||||
total, namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username, keyword, orderBy, reverse, limit, offset)
|
|
||||||
|
|
||||||
if withMetrics {
|
|
||||||
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
|
|
||||||
}
|
|
||||||
|
|
||||||
if errors.HandlerError(err, resp) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
result := models.PageableResponse{}
|
|
||||||
result.TotalCount = total
|
|
||||||
result.Items = make([]interface{}, 0)
|
|
||||||
for _, n := range namespaces {
|
|
||||||
result.Items = append(result.Items, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(result)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,51 +1,56 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2018 The KubeSphere Authors.
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Copyright 2019 The KubeSphere Authors.
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
you may not use this file except in compliance with the License.
|
||||||
Unless required by applicable law or agreed to in writing, software
|
You may obtain a copy of the License at
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
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
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"flag"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
var dbClient *gorm.DB
|
var (
|
||||||
|
dbClientOnce sync.Once
|
||||||
|
dbClient *gorm.DB
|
||||||
|
dsn string
|
||||||
|
)
|
||||||
|
|
||||||
func NewDBClient() *gorm.DB {
|
func init() {
|
||||||
conn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", "", "", "", "")
|
flag.StringVar(&dsn, "database-connection", "root@tcp(localhost:3306)/kubesphere?charset=utf8&parseTime=True", "data source name")
|
||||||
|
|
||||||
db, err := gorm.Open("mysql", conn)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
glog.Error(err)
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return db
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSharedDBClient() *gorm.DB {
|
func DBClient() *gorm.DB {
|
||||||
|
dbClientOnce.Do(func() {
|
||||||
|
var err error
|
||||||
|
dbClient, err = gorm.Open("mysql", dsn)
|
||||||
|
|
||||||
if dbClient != nil {
|
if err != nil {
|
||||||
err := dbClient.DB().Ping()
|
log.Fatalln(err)
|
||||||
if err == nil {
|
|
||||||
return dbClient
|
|
||||||
} else {
|
|
||||||
glog.Error(err)
|
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return NewDBClient()
|
if err := dbClient.DB().Ping(); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return dbClient
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,25 +19,31 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
KubeConfigFile string
|
kubeConfigFile string
|
||||||
k8sClient *kubernetes.Clientset
|
k8sClient *kubernetes.Clientset
|
||||||
k8sClientOnce sync.Once
|
k8sClientOnce sync.Once
|
||||||
KubeConfig *rest.Config
|
KubeConfig *rest.Config
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&kubeConfigFile, "kubeconfig", fmt.Sprintf("%s/.kube/config", os.Getenv("HOME")), "path to kubeconfig file")
|
||||||
|
}
|
||||||
|
|
||||||
func K8sClient() *kubernetes.Clientset {
|
func K8sClient() *kubernetes.Clientset {
|
||||||
|
|
||||||
k8sClientOnce.Do(func() {
|
k8sClientOnce.Do(func() {
|
||||||
@@ -45,14 +51,10 @@ func K8sClient() *kubernetes.Clientset {
|
|||||||
config, err := getKubeConfig()
|
config, err := getKubeConfig()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("cannot load kubeconfig: %v", err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
k8sClient, err = kubernetes.NewForConfig(config)
|
k8sClient = kubernetes.NewForConfigOrDie(config)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("cannot create k8s client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
KubeConfig = config
|
KubeConfig = config
|
||||||
})
|
})
|
||||||
@@ -62,36 +64,28 @@ func K8sClient() *kubernetes.Clientset {
|
|||||||
|
|
||||||
func getKubeConfig() (kubeConfig *rest.Config, err error) {
|
func getKubeConfig() (kubeConfig *rest.Config, err error) {
|
||||||
|
|
||||||
if KubeConfigFile == "" {
|
if kubeConfigFile == "" {
|
||||||
if env := os.Getenv("KUBECONFIG"); env != "" {
|
if env := os.Getenv("KUBECONFIG"); env != "" {
|
||||||
KubeConfigFile = env
|
kubeConfigFile = env
|
||||||
} else {
|
} else {
|
||||||
if home, err := homedir.Dir(); err == nil {
|
if home, err := homedir.Dir(); err == nil {
|
||||||
KubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
|
kubeConfigFile = fmt.Sprintf("%s/.kube/config", home)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if KubeConfigFile != "" {
|
if _, err = os.Stat(kubeConfigFile); err == nil {
|
||||||
|
kubeConfig, err = clientcmd.BuildConfigFromFlags("", kubeConfigFile)
|
||||||
kubeConfig, err = clientcmd.BuildConfigFromFlags("", KubeConfigFile)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
kubeConfig, err = rest.InClusterConfig()
|
kubeConfig, err = rest.InClusterConfig()
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeConfig.QPS = 1e6
|
kubeConfig.QPS = 1e6
|
||||||
kubeConfig.Burst = 1e6
|
kubeConfig.Burst = 1e6
|
||||||
|
|
||||||
return kubeConfig, nil
|
return kubeConfig, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
188
pkg/client/ldap/channel.go
Normal file
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");
|
Copyright 2019 The KubeSphere Authors.
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
you may not use this file except in compliance with the License.
|
||||||
Unless required by applicable law or agreed to in writing, software
|
You may obtain a copy of the License at
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
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
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -20,31 +26,23 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultScheme = "http"
|
DefaultQueryStep = "10m"
|
||||||
DefaultPrometheusPort = "9090"
|
DefaultQueryTimeout = "10s"
|
||||||
PrometheusApiPath = "/api/v1/"
|
RangeQueryType = "query_range?"
|
||||||
DefaultQueryStep = "10m"
|
DefaultQueryType = "query?"
|
||||||
DefaultQueryTimeout = "10s"
|
|
||||||
RangeQueryType = "query_range?"
|
|
||||||
DefaultQueryType = "query?"
|
|
||||||
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
|
var (
|
||||||
var PrometheusEndpointUrl string
|
prometheusAPIEndpoint string
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if env := os.Getenv(PrometheusAPIServerEnv); env != "" {
|
flag.StringVar(&prometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "prometheus api endpoint")
|
||||||
PrometheusAPIServer = env
|
|
||||||
}
|
|
||||||
PrometheusEndpointUrl = DefaultScheme + "://" + PrometheusAPIServer + ":" + DefaultPrometheusPort + PrometheusApiPath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MonitoringRequestParams struct {
|
type MonitoringRequestParams struct {
|
||||||
@@ -72,11 +70,10 @@ type MonitoringRequestParams struct {
|
|||||||
WorkloadKind string
|
WorkloadKind string
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = &http.Client{}
|
|
||||||
|
|
||||||
func SendMonitoringRequest(queryType string, params string) string {
|
func SendMonitoringRequest(queryType string, params string) string {
|
||||||
epurl := PrometheusEndpointUrl + queryType + params
|
epurl := prometheusAPIEndpoint + queryType + params
|
||||||
response, err := client.Get(epurl)
|
|
||||||
|
response, err := http.DefaultClient.Get(epurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
} else {
|
} else {
|
||||||
@@ -116,11 +113,11 @@ func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestPa
|
|||||||
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
|
metricsName := strings.Trim(request.QueryParameter("metrics_name"), " ")
|
||||||
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
|
workloadName := strings.Trim(request.QueryParameter("workload_name"), " ")
|
||||||
|
|
||||||
nodeId := strings.Trim(request.PathParameter("node_id"), " ")
|
nodeId := strings.Trim(request.PathParameter("node"), " ")
|
||||||
wsName := strings.Trim(request.PathParameter("workspace_name"), " ")
|
wsName := strings.Trim(request.PathParameter("workspace"), " ")
|
||||||
nsName := strings.Trim(request.PathParameter("ns_name"), " ")
|
nsName := strings.Trim(request.PathParameter("namespace"), " ")
|
||||||
podName := strings.Trim(request.PathParameter("pod_name"), " ")
|
podName := strings.Trim(request.PathParameter("pod"), " ")
|
||||||
containerName := strings.Trim(request.PathParameter("container_name"), " ")
|
containerName := strings.Trim(request.PathParameter("container"), " ")
|
||||||
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
|
workloadKind := strings.Trim(request.PathParameter("workload_kind"), " ")
|
||||||
|
|
||||||
var requestParams = MonitoringRequestParams{
|
var requestParams = MonitoringRequestParams{
|
||||||
|
|||||||
56
pkg/client/redis.go
Normal file
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 (
|
const (
|
||||||
APIVersion = "v1alpha1"
|
APIVersion = "v1alpha1"
|
||||||
@@ -24,32 +39,18 @@ const (
|
|||||||
DevopsOwner = "owner"
|
DevopsOwner = "owner"
|
||||||
DevopsReporter = "reporter"
|
DevopsReporter = "reporter"
|
||||||
|
|
||||||
DevopsAPIServerEnv = "DEVOPS_API_SERVER"
|
envDevopsAPIServer = "DEVOPS_API_SERVER"
|
||||||
AccountAPIServerEnv = "ACCOUNT_API_SERVER"
|
envAccountAPIServer = "ACCOUNT_API_SERVER"
|
||||||
DevopsProxyTokenEnv = "DEVOPS_PROXY_TOKEN"
|
envDevopsProxyToken = "DEVOPS_PROXY_TOKEN"
|
||||||
OpenPitrixProxyTokenEnv = "OPENPITRIX_PROXY_TOKEN"
|
envOpenPitrixProxyToken = "OPENPITRIX_PROXY_TOKEN"
|
||||||
|
|
||||||
|
UserNameHeader = "X-Token-Username"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
||||||
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
|
SystemWorkspace = "system-workspace"
|
||||||
AccountAPIServer = "ks-account.kubesphere-system.svc"
|
DevopsAPIServer = "ks-devops-apiserver.kubesphere-system.svc"
|
||||||
DevopsProxyToken = ""
|
AccountAPIServer = "ks-account.kubesphere-system.svc"
|
||||||
OpenPitrixProxyToken = ""
|
SystemNamespaces = []string{KubeSystemNamespace, OpenPitrixNamespace, KubeSystemNamespace}
|
||||||
SystemNamespaces = []string{KubeSystemNamespace, OpenPitrixNamespace, KubeSystemNamespace}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
if env := os.Getenv(DevopsAPIServerEnv); env != "" {
|
|
||||||
DevopsAPIServer = env
|
|
||||||
}
|
|
||||||
if env := os.Getenv(AccountAPIServerEnv); env != "" {
|
|
||||||
AccountAPIServer = env
|
|
||||||
}
|
|
||||||
if env := os.Getenv(DevopsProxyTokenEnv); env != "" {
|
|
||||||
DevopsProxyToken = env
|
|
||||||
}
|
|
||||||
if env := os.Getenv(OpenPitrixProxyTokenEnv); env != "" {
|
|
||||||
OpenPitrixProxyToken = env
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
package errors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
k8sError "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
"github.com/go-sql-driver/mysql"
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
Code Code `json:"code"`
|
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var None = New(OK, "success")
|
var None = Error{Message: "success"}
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
func (e *Error) Error() string {
|
||||||
return fmt.Sprintf("error: %v,message: %v", e.Code.String(), e.Message)
|
return e.Message
|
||||||
}
|
|
||||||
func (e *Error) HttpStatusCode() int {
|
|
||||||
switch e.Code {
|
|
||||||
case OK:
|
|
||||||
return http.StatusOK
|
|
||||||
case InvalidArgument:
|
|
||||||
return http.StatusBadRequest
|
|
||||||
case AlreadyExists:
|
|
||||||
return http.StatusConflict
|
|
||||||
case Unavailable:
|
|
||||||
return http.StatusServiceUnavailable
|
|
||||||
case NotImplement:
|
|
||||||
return http.StatusNotImplemented
|
|
||||||
case VerifyFailed:
|
|
||||||
return http.StatusBadRequest
|
|
||||||
case Conflict:
|
|
||||||
return http.StatusConflict
|
|
||||||
case Internal:
|
|
||||||
fallthrough
|
|
||||||
case Unknown:
|
|
||||||
fallthrough
|
|
||||||
default:
|
|
||||||
return http.StatusInternalServerError
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(code Code, message string) error {
|
func Wrap(err error) Error {
|
||||||
if message == "" {
|
return Error{Message: err.Error()}
|
||||||
message = code.String()
|
|
||||||
}
|
|
||||||
return &Error{Code: code, Message: message}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandlerError(err error, resp *restful.Response) bool {
|
func Parse(data []byte) error {
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.Errorln(reflect.TypeOf(err), err)
|
|
||||||
|
|
||||||
resp.WriteHeaderAndEntity(wrapper(err))
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapper(err error) (int, interface{}) {
|
|
||||||
switch err.(type) {
|
|
||||||
case *Error:
|
|
||||||
case *json.UnmarshalTypeError:
|
|
||||||
err = New(InvalidArgument, err.Error())
|
|
||||||
case *mysql.MySQLError:
|
|
||||||
err = wrapperMysqlError(err.(*mysql.MySQLError))
|
|
||||||
case *net.OpError:
|
|
||||||
err = New(Internal, err.Error())
|
|
||||||
default:
|
|
||||||
if k8sError.IsNotFound(err) {
|
|
||||||
err = New(NotFound, err.Error())
|
|
||||||
} else {
|
|
||||||
err = New(Unknown, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return err.(*Error).HttpStatusCode(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapperMysqlError(sqlError *mysql.MySQLError) error {
|
|
||||||
switch sqlError.Number {
|
|
||||||
case 1062:
|
|
||||||
return New(AlreadyExists, sqlError.Message)
|
|
||||||
default:
|
|
||||||
return New(Unknown, sqlError.Message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Wrap(data []byte) error {
|
|
||||||
var j map[string]string
|
var j map[string]string
|
||||||
err := json.Unmarshal(data, &j)
|
err := json.Unmarshal(data, &j)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -18,47 +18,27 @@
|
|||||||
package components
|
package components
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/core/v1"
|
"kubesphere.io/kubesphere/pkg/client"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
coreV1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Component struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Namespace string `json:"namespace"`
|
|
||||||
SelfLink string `json:"selfLink"`
|
|
||||||
Label interface{} `json:"label"`
|
|
||||||
StartedAt time.Time `json:"startedAt"`
|
|
||||||
TotalBackends int `json:"totalBackends"`
|
|
||||||
HealthyBackends int `json:"healthyBackends"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
componentStatusLister lister.ComponentStatusLister
|
|
||||||
serviceLister lister.ServiceLister
|
|
||||||
podLister lister.PodLister
|
|
||||||
nodeLister lister.NodeLister
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
componentStatusLister = informers.SharedInformerFactory().Core().V1().ComponentStatuses().Lister()
|
|
||||||
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
|
|
||||||
podLister = informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
|
||||||
nodeLister = informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetComponentStatus(name string) (interface{}, error) {
|
func GetComponentStatus(name string) (interface{}, error) {
|
||||||
|
|
||||||
var service *coreV1.Service
|
var service *corev1.Service
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||||
|
|
||||||
for _, ns := range constants.SystemNamespaces {
|
for _, ns := range constants.SystemNamespaces {
|
||||||
service, err = serviceLister.Services(ns).Get(name)
|
service, err = serviceLister.Services(ns).Get(name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -70,13 +50,15 @@ func GetComponentStatus(name string) (interface{}, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||||
|
|
||||||
pods, err := podLister.Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
|
pods, err := podLister.Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
component := Component{
|
component := models.Component{
|
||||||
Name: service.Name,
|
Name: service.Name,
|
||||||
Namespace: service.Namespace,
|
Namespace: service.Namespace,
|
||||||
SelfLink: service.SelfLink,
|
SelfLink: service.SelfLink,
|
||||||
@@ -102,11 +84,11 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
|||||||
|
|
||||||
status := make(map[string]interface{})
|
status := make(map[string]interface{})
|
||||||
|
|
||||||
componentStatuses, err := componentStatusLister.List(labels.Everything())
|
componentStatuses, err := client.K8sClient().CoreV1().ComponentStatuses().List(meta_v1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, cs := range componentStatuses {
|
for _, cs := range componentStatuses.Items {
|
||||||
status[cs.Name] = cs.Conditions[0]
|
status[cs.Name] = cs.Conditions[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +101,8 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
|||||||
for k, v := range systemComponentStatus {
|
for k, v := range systemComponentStatus {
|
||||||
status[k] = v
|
status[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||||
// get node status
|
// get node status
|
||||||
nodes, err := nodeLister.List(labels.Everything())
|
nodes, err := nodeLister.List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -132,7 +116,7 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
|||||||
for _, nodes := range nodes {
|
for _, nodes := range nodes {
|
||||||
totalNodes++
|
totalNodes++
|
||||||
for _, condition := range nodes.Status.Conditions {
|
for _, condition := range nodes.Status.Conditions {
|
||||||
if condition.Type == coreV1.NodeReady && condition.Status == coreV1.ConditionTrue {
|
if condition.Type == corev1.NodeReady && condition.Status == corev1.ConditionTrue {
|
||||||
healthyNodes++
|
healthyNodes++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,11 +131,12 @@ func GetSystemHealthStatus() (map[string]interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetAllComponentsStatus() (map[string]interface{}, error) {
|
func GetAllComponentsStatus() (map[string]interface{}, error) {
|
||||||
|
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||||
|
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||||
|
|
||||||
status := make(map[string]interface{})
|
status := make(map[string]interface{})
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
for _, ns := range constants.SystemNamespaces {
|
for _, ns := range constants.SystemNamespaces {
|
||||||
|
|
||||||
nsStatus := make(map[string]interface{})
|
nsStatus := make(map[string]interface{})
|
||||||
@@ -164,7 +149,7 @@ func GetAllComponentsStatus() (map[string]interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, service := range services {
|
for _, service := range services {
|
||||||
component := Component{
|
component := models.Component{
|
||||||
Name: service.Name,
|
Name: service.Name,
|
||||||
Namespace: service.Namespace,
|
Namespace: service.Namespace,
|
||||||
SelfLink: service.SelfLink,
|
SelfLink: service.SelfLink,
|
||||||
|
|||||||
822
pkg/models/iam/am.go
Normal file
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
|
package iam
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,38 +24,22 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
v12 "k8s.io/client-go/listers/rbac/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"k8s.io/api/rbac/v1"
|
"k8s.io/api/rbac/v1"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
|
||||||
"k8s.io/kubernetes/pkg/util/slice"
|
"k8s.io/kubernetes/pkg/util/slice"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
ksErr "kubesphere.io/kubesphere/pkg/errors"
|
kserr "kubesphere.io/kubesphere/pkg/errors"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ClusterRoleKind = "ClusterRole"
|
const ClusterRoleKind = "ClusterRole"
|
||||||
|
|
||||||
var (
|
|
||||||
clusterRoleBindingLister v12.ClusterRoleBindingLister
|
|
||||||
clusterRoleLister v12.ClusterRoleLister
|
|
||||||
roleBindingLister v12.RoleBindingLister
|
|
||||||
roleLister v12.RoleLister
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
clusterRoleBindingLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
|
||||||
clusterRoleLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
|
||||||
roleBindingLister = informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
|
|
||||||
roleLister = informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get user list based on workspace role
|
// Get user list based on workspace role
|
||||||
func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
|
func WorkspaceRoleUsers(workspace string, roleName string) ([]models.User, error) {
|
||||||
|
|
||||||
|
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||||
|
|
||||||
workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName))
|
workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName))
|
||||||
|
|
||||||
@@ -67,11 +68,11 @@ func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
|
|||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUsers(names []string) ([]User, error) {
|
func GetUsers(names []string) ([]models.User, error) {
|
||||||
var users []User
|
var users []models.User
|
||||||
|
|
||||||
if names == nil || len(names) == 0 {
|
if names == nil || len(names) == 0 {
|
||||||
return make([]User, 0), nil
|
return make([]models.User, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
|
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
|
||||||
@@ -88,7 +89,7 @@ func GetUsers(names []string) ([]User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if result.StatusCode > 200 {
|
if result.StatusCode > 200 {
|
||||||
return nil, ksErr.Wrap(data)
|
return nil, kserr.Parse(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(data, &users)
|
err = json.Unmarshal(data, &users)
|
||||||
@@ -100,7 +101,7 @@ func GetUsers(names []string) ([]User, error) {
|
|||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUser(name string) (*User, error) {
|
func GetUser(name string) (*models.User, error) {
|
||||||
|
|
||||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
|
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
|
||||||
|
|
||||||
@@ -116,10 +117,10 @@ func GetUser(name string) (*User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if result.StatusCode > 200 {
|
if result.StatusCode > 200 {
|
||||||
return nil, ksErr.Wrap(data)
|
return nil, kserr.Parse(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
var user User
|
var user models.User
|
||||||
|
|
||||||
err = json.Unmarshal(data, &user)
|
err = json.Unmarshal(data, &user)
|
||||||
|
|
||||||
@@ -187,16 +188,8 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
|
|||||||
return false, namespaces, nil
|
return false, namespaces, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRole(namespace string, name string) (*v1.Role, error) {
|
|
||||||
role, err := roleLister.Roles(namespace).Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return role.DeepCopy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) {
|
func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) {
|
||||||
|
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||||
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
|
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -213,108 +206,6 @@ func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error)
|
|||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetClusterRole(name string) (*v1.ClusterRole, error) {
|
|
||||||
|
|
||||||
role, err := clusterRoleLister.Get(name)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return role.DeepCopy(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetRoles(namespace string, username string) ([]v1.Role, error) {
|
|
||||||
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
roles := make([]v1.Role, 0)
|
|
||||||
|
|
||||||
for _, roleBinding := range roleBindings {
|
|
||||||
|
|
||||||
for _, subject := range roleBinding.Subjects {
|
|
||||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
|
||||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
|
||||||
clusterRole, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
|
|
||||||
if err == nil {
|
|
||||||
var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules}
|
|
||||||
role.Namespace = roleBinding.Namespace
|
|
||||||
roles = append(roles, role)
|
|
||||||
break
|
|
||||||
} else if apierrors.IsNotFound(err) {
|
|
||||||
glog.Infoln(err.Error())
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
|
||||||
role, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name)
|
|
||||||
if err == nil {
|
|
||||||
roles = append(roles, *role)
|
|
||||||
break
|
|
||||||
} else if apierrors.IsNotFound(err) {
|
|
||||||
glog.Infoln(err.Error())
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return roles, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get cluster roles by username
|
|
||||||
func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
|
||||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
roles := make([]v1.ClusterRole, 0)
|
|
||||||
|
|
||||||
for _, roleBinding := range clusterRoleBindings {
|
|
||||||
for _, subject := range roleBinding.Subjects {
|
|
||||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
|
||||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
|
||||||
role, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
|
|
||||||
if err == nil {
|
|
||||||
role = role.DeepCopy()
|
|
||||||
if role.Annotations == nil {
|
|
||||||
role.Annotations = make(map[string]string, 0)
|
|
||||||
}
|
|
||||||
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = roleBinding.Name
|
|
||||||
if roleBinding.Annotations != nil &&
|
|
||||||
roleBinding.Annotations["rbac.authorization.k8s.io/clusterrole"] == roleBinding.RoleRef.Name {
|
|
||||||
role.Annotations["rbac.authorization.k8s.io/clusterrole"] = "true"
|
|
||||||
}
|
|
||||||
roles = append(roles, *role)
|
|
||||||
break
|
|
||||||
} else if apierrors.IsNotFound(err) {
|
|
||||||
glog.Warning(err)
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return roles, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
if ruleMatchesRequired(rule, required) {
|
if ruleMatchesRequired(rule, required) {
|
||||||
@@ -323,139 +214,3 @@ func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func ruleMatchesRequired(rule v1.PolicyRule, required v1.PolicyRule) bool {
|
|
||||||
|
|
||||||
if len(required.NonResourceURLs) == 0 {
|
|
||||||
for _, apiGroup := range required.APIGroups {
|
|
||||||
for _, resource := range required.Resources {
|
|
||||||
resources := strings.Split(resource, "/")
|
|
||||||
resource = resources[0]
|
|
||||||
var subsource string
|
|
||||||
if len(resources) > 1 {
|
|
||||||
subsource = resources[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(required.ResourceNames) == 0 {
|
|
||||||
for _, verb := range required.Verbs {
|
|
||||||
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, "", verb) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, resourceName := range required.ResourceNames {
|
|
||||||
for _, verb := range required.Verbs {
|
|
||||||
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, resourceName, verb) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, apiGroup := range required.APIGroups {
|
|
||||||
for _, nonResourceURL := range required.NonResourceURLs {
|
|
||||||
for _, verb := range required.Verbs {
|
|
||||||
if !ruleMatchesRequest(rule, apiGroup, nonResourceURL, "", "", "", verb) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
|
|
||||||
|
|
||||||
if resource == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, v1.ResourceAll) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(rule.ResourceNames) > 0 && !hasString(rule.ResourceNames, resourceName) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
combinedResource := resource
|
|
||||||
|
|
||||||
if subresource != "" {
|
|
||||||
combinedResource = combinedResource + "/" + subresource
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, res := range rule.Resources {
|
|
||||||
|
|
||||||
// match "*"
|
|
||||||
if res == v1.ResourceAll || res == combinedResource {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// match "*/subresource"
|
|
||||||
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// match "resource/*"
|
|
||||||
if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func ruleMatchesRequest(rule v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
|
|
||||||
|
|
||||||
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, v1.VerbAll) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if nonResourceURL == "" {
|
|
||||||
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
|
|
||||||
} else {
|
|
||||||
return ruleMatchesNonResource(rule, nonResourceURL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ruleMatchesNonResource(rule v1.PolicyRule, nonResourceURL string) bool {
|
|
||||||
|
|
||||||
if nonResourceURL == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, spec := range rule.NonResourceURLs {
|
|
||||||
if pathMatches(nonResourceURL, spec) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func pathMatches(path, spec string) bool {
|
|
||||||
// Allow wildcard match
|
|
||||||
if spec == "*" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Allow exact match
|
|
||||||
if spec == path {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Allow a trailing * subpath match
|
|
||||||
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasString(slice []string, value string) bool {
|
|
||||||
for _, s := range slice {
|
|
||||||
if s == value {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
1155
pkg/models/iam/im.go
Normal file
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}
|
configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: user}, Data: data}
|
||||||
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
|
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
|
||||||
if err != nil && !errors.IsAlreadyExists(err) {
|
if err != nil && !errors.IsAlreadyExists(err) {
|
||||||
glog.Errorf("create user %s's kubeConfig failed, reason: %s", user, err)
|
glog.Errorf("create user %s's kubeConfig failed, reason: %v", user, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ func GetKubeConfig(user string) (string, error) {
|
|||||||
k8sClient := client.K8sClient()
|
k8sClient := client.K8sClient()
|
||||||
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{})
|
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("cannot get user %s's kubeConfig, reason: %s", user, err)
|
glog.Errorf("cannot get user %s's kubeConfig, reason: %v", user, err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return configMap.Data[kubectlConfigKey], nil
|
return configMap.Data[kubectlConfigKey], nil
|
||||||
@@ -287,7 +287,7 @@ func DelKubeConfig(user string) error {
|
|||||||
deletePolicy := metaV1.DeletePropagationBackground
|
deletePolicy := metaV1.DeletePropagationBackground
|
||||||
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(user, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(user, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("delete user %s's kubeConfig failed, reason: %s", user, err)
|
glog.Errorf("delete user %s's kubeConfig failed, reason: %v", user, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package kubectl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@@ -38,18 +39,12 @@ const (
|
|||||||
namespace = constants.KubeSphereControlNamespace
|
namespace = constants.KubeSphereControlNamespace
|
||||||
)
|
)
|
||||||
|
|
||||||
type PodInfo struct {
|
func GetKubectlPod(username string) (models.PodInfo, error) {
|
||||||
Namespace string `json:"namespace"`
|
|
||||||
Pod string `json:"pod"`
|
|
||||||
Container string `json:"container"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetKubectlPod(username string) (PodInfo, error) {
|
|
||||||
k8sClient := client.K8sClient()
|
k8sClient := client.K8sClient()
|
||||||
deploy, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(username, metav1.GetOptions{})
|
deploy, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(username, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorln(err)
|
glog.Errorln(err)
|
||||||
return PodInfo{}, err
|
return models.PodInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
selectors := deploy.Spec.Selector.MatchLabels
|
selectors := deploy.Spec.Selector.MatchLabels
|
||||||
@@ -57,16 +52,16 @@ func GetKubectlPod(username string) (PodInfo, error) {
|
|||||||
podList, err := k8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
|
podList, err := k8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorln(err)
|
glog.Errorln(err)
|
||||||
return PodInfo{}, err
|
return models.PodInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pod, err := selectCorrectPod(namespace, podList.Items)
|
pod, err := selectCorrectPod(namespace, podList.Items)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorln(err)
|
glog.Errorln(err)
|
||||||
return PodInfo{}, err
|
return models.PodInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := PodInfo{Namespace: pod.Namespace, Pod: pod.Name, Container: pod.Status.ContainerStatuses[0].Name}
|
info := models.PodInfo{Namespace: pod.Namespace, Pod: pod.Name, Container: pod.Status.ContainerStatuses[0].Name}
|
||||||
|
|
||||||
return info, nil
|
return info, nil
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,13 @@ package metrics
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
v12 "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
"kubesphere.io/kubesphere/pkg/models/components"
|
"kubesphere.io/kubesphere/pkg/models/components"
|
||||||
@@ -50,7 +49,6 @@ import (
|
|||||||
var (
|
var (
|
||||||
jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
nodeStatusDelLabel = []string{"endpoint", "instance", "job", "namespace", "pod", "service"}
|
nodeStatusDelLabel = []string{"endpoint", "instance", "job", "namespace", "pod", "service"}
|
||||||
nodeLister v12.NodeLister
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -126,10 +124,6 @@ type OneComponentStatus struct {
|
|||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
nodeLister = informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAllWorkspaceNames(formatedMetric *FormatedMetric) map[string]int {
|
func getAllWorkspaceNames(formatedMetric *FormatedMetric) map[string]int {
|
||||||
|
|
||||||
var wsMap = make(map[string]int)
|
var wsMap = make(map[string]int)
|
||||||
@@ -197,12 +191,12 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
|||||||
var timestampMap = make(map[float64]bool)
|
var timestampMap = make(map[float64]bool)
|
||||||
|
|
||||||
if fmtMetrics.Data.ResultType == ResultTypeMatrix {
|
if fmtMetrics.Data.ResultType == ResultTypeMatrix {
|
||||||
for i, _ := range fmtMetrics.Data.Result {
|
for i := range fmtMetrics.Data.Result {
|
||||||
values, exist := fmtMetrics.Data.Result[i][ResultItemValues]
|
values, exist := fmtMetrics.Data.Result[i][ResultItemValues]
|
||||||
if exist {
|
if exist {
|
||||||
valueArray, sure := values.([]interface{})
|
valueArray, sure := values.([]interface{})
|
||||||
if sure {
|
if sure {
|
||||||
for j, _ := range valueArray {
|
for j := range valueArray {
|
||||||
timeAndValue := valueArray[j].([]interface{})
|
timeAndValue := valueArray[j].([]interface{})
|
||||||
timestampMap[float64(timeAndValue[0].(uint64))] = true
|
timestampMap[float64(timeAndValue[0].(uint64))] = true
|
||||||
}
|
}
|
||||||
@@ -213,7 +207,7 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
|||||||
|
|
||||||
timestampArray := make([]float64, len(timestampMap))
|
timestampArray := make([]float64, len(timestampMap))
|
||||||
i := 0
|
i := 0
|
||||||
for timestamp, _ := range timestampMap {
|
for timestamp := range timestampMap {
|
||||||
timestampArray[i] = timestamp
|
timestampArray[i] = timestamp
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@@ -230,7 +224,7 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
|||||||
formatValueArray := make([][]interface{}, len(timestampArray))
|
formatValueArray := make([][]interface{}, len(timestampArray))
|
||||||
j := 0
|
j := 0
|
||||||
|
|
||||||
for k, _ := range timestampArray {
|
for k := range timestampArray {
|
||||||
valueItem, sure := valueArray[j].([]interface{})
|
valueItem, sure := valueArray[j].([]interface{})
|
||||||
if sure && float64(valueItem[0].(uint64)) == timestampArray[k] {
|
if sure && float64(valueItem[0].(uint64)) == timestampArray[k] {
|
||||||
formatValueArray[k] = []interface{}{int64(timestampArray[k]), valueItem[1]}
|
formatValueArray[k] = []interface{}{int64(timestampArray[k]), valueItem[1]}
|
||||||
@@ -294,7 +288,7 @@ func GetMetric(queryType, params, metricName string) *FormatedMetric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetNodeAddressInfo() *map[string][]v1.NodeAddress {
|
func GetNodeAddressInfo() *map[string][]v1.NodeAddress {
|
||||||
|
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||||
nodes, err := nodeLister.List(labels.Everything())
|
nodes, err := nodeLister.List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -938,7 +932,7 @@ func MonitorComponentStatus(monitoringRequest *client.MonitoringRequestParams) *
|
|||||||
nsStatus, exist := Components[ns]
|
nsStatus, exist := Components[ns]
|
||||||
if exist {
|
if exist {
|
||||||
for _, nsStatusItem := range nsStatus.(map[string]interface{}) {
|
for _, nsStatusItem := range nsStatus.(map[string]interface{}) {
|
||||||
component := nsStatusItem.(components.Component)
|
component := nsStatusItem.(models.Component)
|
||||||
namespaceComponentTotalMap[ns] += 1
|
namespaceComponentTotalMap[ns] += 1
|
||||||
if component.HealthyBackends != 0 && component.HealthyBackends == component.TotalBackends {
|
if component.HealthyBackends != 0 && component.HealthyBackends == component.TotalBackends {
|
||||||
namespaceComponentHealthyMap[ns] += 1
|
namespaceComponentHealthyMap[ns] += 1
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/client"
|
"kubesphere.io/kubesphere/pkg/client"
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func DrainNode(nodename string) (err error) {
|
func DrainNode(nodename string) (err error) {
|
||||||
@@ -45,7 +44,7 @@ func DrainNode(nodename string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.Spec.Unschedulable {
|
if node.Spec.Unschedulable {
|
||||||
return errors.New(errors.Conflict, fmt.Sprintf("node %s have been drained", nodename))
|
return fmt.Errorf("node %s have been drained", nodename)
|
||||||
}
|
}
|
||||||
|
|
||||||
data := []byte(" {\"spec\":{\"unschedulable\":true}}")
|
data := []byte(" {\"spec\":{\"unschedulable\":true}}")
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ import (
|
|||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
v12 "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -51,27 +51,17 @@ var (
|
|||||||
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
|
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
|
||||||
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles,
|
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles,
|
||||||
jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs}
|
jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs}
|
||||||
resouceQuotaLister v12.ResourceQuotaLister
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ResourceQuota struct {
|
|
||||||
Namespace string `json:"namespace"`
|
|
||||||
Data v1.ResourceQuotaStatus `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUsage(namespace, resource string) (int, error) {
|
func getUsage(namespace, resource string) (int, error) {
|
||||||
list, err := resources.ListNamespaceResource(namespace, resource, "", "", false, -1, 0)
|
list, err := resources.ListNamespaceResource(namespace, resource, ¶ms.Conditions{}, "", false, -1, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return list.TotalCount, nil
|
return list.TotalCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func GetClusterQuotas() (*models.ResourceQuota, error) {
|
||||||
resouceQuotaLister = informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetClusterQuotas() (*ResourceQuota, error) {
|
|
||||||
|
|
||||||
quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
||||||
|
|
||||||
@@ -85,11 +75,11 @@ func GetClusterQuotas() (*ResourceQuota, error) {
|
|||||||
quota.Used[v1.ResourceName(k)] = quantity
|
quota.Used[v1.ResourceName(k)] = quantity
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ResourceQuota{Namespace: "\"\"", Data: quota}, nil
|
return &models.ResourceQuota{Namespace: "\"\"", Data: quota}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetNamespaceQuotas(namespace string) (*ResourceQuota, error) {
|
func GetNamespaceQuotas(namespace string) (*models.ResourceQuota, error) {
|
||||||
quota, err := getNamespaceResourceQuota(namespace)
|
quota, err := getNamespaceResourceQuota(namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
@@ -115,7 +105,7 @@ func GetNamespaceQuotas(namespace string) (*ResourceQuota, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ResourceQuota{Namespace: namespace, Data: *quota}, nil
|
return &models.ResourceQuota{Namespace: namespace, Data: *quota}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
||||||
@@ -135,7 +125,8 @@ func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
|
func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
|
||||||
quotaList, err := resouceQuotaLister.ResourceQuotas(namespace).List(labels.Everything())
|
resourceQuotaLister := informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
|
||||||
|
quotaList, err := resourceQuotaLister.ResourceQuotas(namespace).List(labels.Everything())
|
||||||
if err != nil || len(quotaList) == 0 {
|
if err != nil || len(quotaList) == 0 {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,11 @@ package registries
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthInfo struct {
|
type AuthInfo struct {
|
||||||
@@ -62,6 +61,6 @@ func RegistryVerify(authInfo AuthInfo) error {
|
|||||||
if resp.Status == loginSuccess {
|
if resp.Status == loginSuccess {
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return errors.New(errors.VerifyFailed, resp.Status)
|
return fmt.Errorf(resp.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
rbac "k8s.io/api/rbac/v1"
|
rbac "k8s.io/api/rbac/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/client-go/listers/rbac/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type clusterRoleSearcher struct {
|
type clusterRoleSearcher struct {
|
||||||
clusterRoleLister v1.ClusterRoleLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
|
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -45,7 +45,7 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
|
func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -86,8 +86,8 @@ func (*clusterRoleSearcher) compare(a, b *rbac.ClusterRole, orderBy string) bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *clusterRoleSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *clusterRoleSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
clusterRoles, err := s.clusterRoleLister.List(labels.Everything())
|
clusterRoles, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister().List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -95,11 +95,11 @@ func (s *clusterRoleSearcher) search(conditions *conditions, orderBy string, rev
|
|||||||
|
|
||||||
result := make([]*rbac.ClusterRole, 0)
|
result := make([]*rbac.ClusterRole, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = clusterRoles
|
result = clusterRoles
|
||||||
} else {
|
} else {
|
||||||
for _, item := range clusterRoles {
|
for _, item := range clusterRoles {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type configMapSearcher struct {
|
type configMapSearcher struct {
|
||||||
configMapLister lister.ConfigMapLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
|
func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -46,7 +45,7 @@ func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) boo
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
|
func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -91,8 +90,8 @@ func (*configMapSearcher) compare(a, b *v1.ConfigMap, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *configMapSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *configMapSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
configMaps, err := s.configMapLister.ConfigMaps(namespace).List(labels.Everything())
|
configMaps, err := informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister().ConfigMaps(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -100,11 +99,11 @@ func (s *configMapSearcher) search(namespace string, conditions *conditions, ord
|
|||||||
|
|
||||||
result := make([]*v1.ConfigMap, 0)
|
result := make([]*v1.ConfigMap, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = configMaps
|
result = configMaps
|
||||||
} else {
|
} else {
|
||||||
for _, item := range configMaps {
|
for _, item := range configMaps {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,28 +18,28 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/batch/v2alpha1"
|
"k8s.io/api/batch/v1beta1"
|
||||||
|
|
||||||
"k8s.io/api/batch/v2alpha1"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cronJobSearcher struct {
|
type cronJobSearcher struct {
|
||||||
cronJobLister lister.CronJobLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func cronJobStatus(item *v2alpha1.CronJob) string {
|
func cronJobStatus(item *v1beta1.CronJob) string {
|
||||||
if item.Spec.Suspend != nil && *item.Spec.Suspend {
|
if item.Spec.Suspend != nil && *item.Spec.Suspend {
|
||||||
return paused
|
return paused
|
||||||
}
|
}
|
||||||
return running
|
return running
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exactly match
|
// Exactly Match
|
||||||
func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) bool {
|
func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
case status:
|
case status:
|
||||||
@@ -53,7 +53,7 @@ func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) b
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v2alpha1.CronJob) bool {
|
func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.CronJob) bool {
|
||||||
|
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -88,7 +88,7 @@ func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v2alpha1.CronJob) b
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*cronJobSearcher) compare(a, b *v2alpha1.CronJob, orderBy string) bool {
|
func (*cronJobSearcher) compare(a, b *v1beta1.CronJob, orderBy string) bool {
|
||||||
switch orderBy {
|
switch orderBy {
|
||||||
case createTime:
|
case createTime:
|
||||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||||
@@ -99,20 +99,20 @@ func (*cronJobSearcher) compare(a, b *v2alpha1.CronJob, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cronJobSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *cronJobSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
cronJobs, err := s.cronJobLister.CronJobs(namespace).List(labels.Everything())
|
cronJobs, err := informers.SharedInformerFactory().Batch().V1beta1().CronJobs().Lister().CronJobs(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]*v2alpha1.CronJob, 0)
|
result := make([]*v1beta1.CronJob, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = cronJobs
|
result = cronJobs
|
||||||
} else {
|
} else {
|
||||||
for _, item := range cronJobs {
|
for _, item := range cronJobs {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,16 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/apps/v1"
|
|
||||||
|
|
||||||
"k8s.io/api/apps/v1"
|
"k8s.io/api/apps/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type daemonSetSearcher struct {
|
type daemonSetSearcher struct {
|
||||||
daemonSetLister lister.DaemonSetLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func daemonSetStatus(item *v1.DaemonSet) string {
|
func daemonSetStatus(item *v1.DaemonSet) string {
|
||||||
@@ -41,7 +40,7 @@ func daemonSetStatus(item *v1.DaemonSet) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exactly match
|
// Exactly Match
|
||||||
func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool {
|
func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -102,8 +101,8 @@ func (*daemonSetSearcher) compare(a, b *v1.DaemonSet, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *daemonSetSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *daemonSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
daemonSets, err := s.daemonSetLister.DaemonSets(namespace).List(labels.Everything())
|
daemonSets, err := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister().DaemonSets(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -111,11 +110,11 @@ func (s *daemonSetSearcher) search(namespace string, conditions *conditions, ord
|
|||||||
|
|
||||||
result := make([]*v1.DaemonSet, 0)
|
result := make([]*v1.DaemonSet, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = daemonSets
|
result = daemonSets
|
||||||
} else {
|
} else {
|
||||||
for _, item := range daemonSets {
|
for _, item := range daemonSets {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,18 +18,17 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/apps/v1"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
|
||||||
"k8s.io/api/apps/v1"
|
"k8s.io/api/apps/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type deploymentSearcher struct {
|
type deploymentSearcher struct {
|
||||||
deploymentLister lister.DeploymentLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func deploymentStatus(item *v1.Deployment) string {
|
func deploymentStatus(item *v1.Deployment) string {
|
||||||
@@ -45,7 +44,7 @@ func deploymentStatus(item *v1.Deployment) string {
|
|||||||
return stopped
|
return stopped
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exactly match
|
// Exactly Match
|
||||||
func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool {
|
func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -106,8 +105,8 @@ func (*deploymentSearcher) compare(a, b *v1.Deployment, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *deploymentSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *deploymentSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
deployments, err := s.deploymentLister.Deployments(namespace).List(labels.Everything())
|
deployments, err := informers.SharedInformerFactory().Apps().V1().Deployments().Lister().Deployments(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -115,11 +114,11 @@ func (s *deploymentSearcher) search(namespace string, conditions *conditions, or
|
|||||||
|
|
||||||
result := make([]*v1.Deployment, 0)
|
result := make([]*v1.Deployment, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = deployments
|
result = deployments
|
||||||
} else {
|
} else {
|
||||||
for _, item := range deployments {
|
for _, item := range deployments {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,21 +18,20 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/extensions/v1beta1"
|
|
||||||
|
|
||||||
extensions "k8s.io/api/extensions/v1beta1"
|
extensions "k8s.io/api/extensions/v1beta1"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ingressSearcher struct {
|
type ingressSearcher struct {
|
||||||
ingressLister lister.IngressLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress) bool {
|
func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -47,7 +46,7 @@ func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress)
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress) bool {
|
func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -92,8 +91,8 @@ func (*ingressSearcher) compare(a, b *extensions.Ingress, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ingressSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *ingressSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
ingresses, err := s.ingressLister.Ingresses(namespace).List(labels.Everything())
|
ingresses, err := informers.SharedInformerFactory().Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -101,11 +100,11 @@ func (s *ingressSearcher) search(namespace string, conditions *conditions, order
|
|||||||
|
|
||||||
result := make([]*extensions.Ingress, 0)
|
result := make([]*extensions.Ingress, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = ingresses
|
result = ingresses
|
||||||
} else {
|
} else {
|
||||||
for _, item := range ingresses {
|
for _, item := range ingresses {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,37 +18,36 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/batch/v1"
|
batchv1 "k8s.io/api/batch/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
batchV1 "k8s.io/api/batch/v1"
|
|
||||||
coreV1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type jobSearcher struct {
|
type jobSearcher struct {
|
||||||
jobLister lister.JobLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func jobStatus(item *batchV1.Job) string {
|
func jobStatus(item *batchv1.Job) string {
|
||||||
status := ""
|
status := ""
|
||||||
|
|
||||||
for _, condition := range item.Status.Conditions {
|
for _, condition := range item.Status.Conditions {
|
||||||
if condition.Type == batchV1.JobFailed && condition.Status == coreV1.ConditionTrue {
|
if condition.Type == batchv1.JobFailed && condition.Status == corev1.ConditionTrue {
|
||||||
status = failed
|
status = failed
|
||||||
}
|
}
|
||||||
if condition.Type == batchV1.JobComplete && condition.Status == coreV1.ConditionTrue {
|
if condition.Type == batchv1.JobComplete && condition.Status == corev1.ConditionTrue {
|
||||||
status = complete
|
status = complete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exactly match
|
// Exactly Match
|
||||||
func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool {
|
func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
case status:
|
case status:
|
||||||
@@ -62,7 +61,7 @@ func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchV1.Job) bool {
|
func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchv1.Job) bool {
|
||||||
|
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -97,7 +96,7 @@ func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchV1.Job) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func jobUpdateTime(item *batchV1.Job) time.Time {
|
func jobUpdateTime(item *batchv1.Job) time.Time {
|
||||||
updateTime := item.CreationTimestamp.Time
|
updateTime := item.CreationTimestamp.Time
|
||||||
for _, condition := range item.Status.Conditions {
|
for _, condition := range item.Status.Conditions {
|
||||||
if updateTime.Before(condition.LastProbeTime.Time) {
|
if updateTime.Before(condition.LastProbeTime.Time) {
|
||||||
@@ -110,7 +109,7 @@ func jobUpdateTime(item *batchV1.Job) time.Time {
|
|||||||
return updateTime
|
return updateTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*jobSearcher) compare(a, b *batchV1.Job, orderBy string) bool {
|
func (*jobSearcher) compare(a, b *batchv1.Job, orderBy string) bool {
|
||||||
switch orderBy {
|
switch orderBy {
|
||||||
case updateTime:
|
case updateTime:
|
||||||
return jobUpdateTime(a).After(jobUpdateTime(b))
|
return jobUpdateTime(a).After(jobUpdateTime(b))
|
||||||
@@ -121,20 +120,20 @@ func (*jobSearcher) compare(a, b *batchV1.Job, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *jobSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *jobSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
jobs, err := s.jobLister.Jobs(namespace).List(labels.Everything())
|
jobs, err := informers.SharedInformerFactory().Batch().V1().Jobs().Lister().Jobs(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]*batchV1.Job, 0)
|
result := make([]*batchv1.Job, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = jobs
|
result = jobs
|
||||||
} else {
|
} else {
|
||||||
for _, item := range jobs {
|
for _, item := range jobs {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
lister "k8s.io/client-go/listers/core/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type namespaceSearcher struct {
|
type namespaceSearcher struct {
|
||||||
namespaceLister lister.NamespaceLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -45,7 +45,7 @@ func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) boo
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -90,8 +90,8 @@ func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *namespaceSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *namespaceSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
namespaces, err := s.namespaceLister.List(labels.Everything())
|
namespaces, err := informers.SharedInformerFactory().Core().V1().Namespaces().Lister().List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -99,11 +99,11 @@ func (s *namespaceSearcher) search(conditions *conditions, orderBy string, rever
|
|||||||
|
|
||||||
result := make([]*v1.Namespace, 0)
|
result := make([]*v1.Namespace, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = namespaces
|
result = namespaces
|
||||||
} else {
|
} else {
|
||||||
for _, item := range namespaces {
|
for _, item := range namespaces {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
lister "k8s.io/client-go/listers/core/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type nodeSearcher struct {
|
type nodeSearcher struct {
|
||||||
nodeLister lister.NodeLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
|
func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -45,7 +45,7 @@ func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
|
func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -90,8 +90,8 @@ func (*nodeSearcher) compare(a, b *v1.Node, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *nodeSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *nodeSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
nodes, err := s.nodeLister.List(labels.Everything())
|
nodes, err := informers.SharedInformerFactory().Core().V1().Nodes().Lister().List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -99,11 +99,11 @@ func (s *nodeSearcher) search(conditions *conditions, orderBy string, reverse bo
|
|||||||
|
|
||||||
result := make([]*v1.Node, 0)
|
result := make([]*v1.Node, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = nodes
|
result = nodes
|
||||||
} else {
|
} else {
|
||||||
for _, item := range nodes {
|
for _, item := range nodes {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type persistentVolumeClaimSearcher struct {
|
type persistentVolumeClaimSearcher struct {
|
||||||
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
|
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -46,7 +45,7 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool {
|
func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -91,8 +90,8 @@ func (*persistentVolumeClaimSearcher) compare(a, b *v1.PersistentVolumeClaim, or
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
persistentVolumeClaims, err := s.persistentVolumeClaimLister.PersistentVolumeClaims(namespace).List(labels.Everything())
|
persistentVolumeClaims, err := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister().PersistentVolumeClaims(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -100,11 +99,11 @@ func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *con
|
|||||||
|
|
||||||
result := make([]*v1.PersistentVolumeClaim, 0)
|
result := make([]*v1.PersistentVolumeClaim, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = persistentVolumeClaims
|
result = persistentVolumeClaims
|
||||||
} else {
|
} else {
|
||||||
for _, item := range persistentVolumeClaims {
|
for _, item := range persistentVolumeClaims {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
v12 "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type podSearcher struct {
|
type podSearcher struct {
|
||||||
podLister v12.PodLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -46,7 +45,7 @@ func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
|
func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -91,9 +90,9 @@ func (*podSearcher) compare(a, b *v1.Pod, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *podSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *podSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
|
|
||||||
pods, err := s.podLister.Pods(namespace).List(labels.Everything())
|
pods, err := informers.SharedInformerFactory().Core().V1().Pods().Lister().Pods(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -101,11 +100,11 @@ func (s *podSearcher) search(namespace string, conditions *conditions, orderBy s
|
|||||||
|
|
||||||
result := make([]*v1.Pod, 0)
|
result := make([]*v1.Pod, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = pods
|
result = pods
|
||||||
} else {
|
} else {
|
||||||
for _, item := range pods {
|
for _, item := range pods {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,74 +18,35 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"fmt"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
namespacedResources[ConfigMaps] = &configMapSearcher{
|
namespacedResources[ConfigMaps] = &configMapSearcher{}
|
||||||
configMapLister: informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister(),
|
namespacedResources[CronJobs] = &cronJobSearcher{}
|
||||||
}
|
namespacedResources[DaemonSets] = &daemonSetSearcher{}
|
||||||
namespacedResources[CronJobs] = &cronJobSearcher{
|
namespacedResources[Deployments] = &deploymentSearcher{}
|
||||||
cronJobLister: informers.SharedInformerFactory().Batch().V2alpha1().CronJobs().Lister(),
|
namespacedResources[Ingresses] = &ingressSearcher{}
|
||||||
}
|
namespacedResources[Jobs] = &jobSearcher{}
|
||||||
namespacedResources[DaemonSets] = &daemonSetSearcher{
|
namespacedResources[PersistentVolumeClaims] = &persistentVolumeClaimSearcher{}
|
||||||
daemonSetLister: informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister(),
|
namespacedResources[Secrets] = &secretSearcher{}
|
||||||
}
|
namespacedResources[Services] = &serviceSearcher{}
|
||||||
namespacedResources[Deployments] = &deploymentSearcher{
|
namespacedResources[StatefulSets] = &statefulSetSearcher{}
|
||||||
deploymentLister: informers.SharedInformerFactory().Apps().V1().Deployments().Lister(),
|
namespacedResources[Pods] = &podSearcher{}
|
||||||
}
|
namespacedResources[Roles] = &roleSearcher{}
|
||||||
namespacedResources[Ingresses] = &ingressSearcher{
|
|
||||||
ingressLister: informers.SharedInformerFactory().Extensions().V1beta1().Ingresses().Lister(),
|
|
||||||
}
|
|
||||||
namespacedResources[Jobs] = &jobSearcher{
|
|
||||||
jobLister: informers.SharedInformerFactory().Batch().V1().Jobs().Lister(),
|
|
||||||
}
|
|
||||||
namespacedResources[PersistentVolumeClaims] = &persistentVolumeClaimSearcher{
|
|
||||||
persistentVolumeClaimLister: informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister(),
|
|
||||||
}
|
|
||||||
namespacedResources[Secrets] = &secretSearcher{
|
|
||||||
secretLister: informers.SharedInformerFactory().Core().V1().Secrets().Lister(),
|
|
||||||
}
|
|
||||||
namespacedResources[Services] = &serviceSearcher{
|
|
||||||
serviceLister: informers.SharedInformerFactory().Core().V1().Services().Lister(),
|
|
||||||
}
|
|
||||||
namespacedResources[StatefulSets] = &statefulSetSearcher{
|
|
||||||
statefulSetLister: informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister(),
|
|
||||||
}
|
|
||||||
namespacedResources[Pods] = &podSearcher{
|
|
||||||
podLister: informers.SharedInformerFactory().Core().V1().Pods().Lister(),
|
|
||||||
}
|
|
||||||
namespacedResources[Roles] = &roleSearcher{
|
|
||||||
roleLister: informers.SharedInformerFactory().Rbac().V1().Roles().Lister(),
|
|
||||||
}
|
|
||||||
|
|
||||||
clusterResources[Nodes] = &nodeSearcher{
|
clusterResources[Nodes] = &nodeSearcher{}
|
||||||
nodeLister: informers.SharedInformerFactory().Core().V1().Nodes().Lister(),
|
clusterResources[Namespaces] = &namespaceSearcher{}
|
||||||
}
|
clusterResources[ClusterRoles] = &clusterRoleSearcher{}
|
||||||
clusterResources[Namespaces] = &namespaceSearcher{
|
clusterResources[StorageClasses] = &storageClassesSearcher{}
|
||||||
namespaceLister: informers.SharedInformerFactory().Core().V1().Namespaces().Lister(),
|
|
||||||
}
|
|
||||||
clusterResources[ClusterRoles] = &clusterRoleSearcher{
|
|
||||||
clusterRoleLister: informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister(),
|
|
||||||
}
|
|
||||||
clusterResources[StorageClasses] = &storageClassesSearcher{
|
|
||||||
storageClassesLister: informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var namespacedResources = make(map[string]namespacedSearcherInterface)
|
var namespacedResources = make(map[string]namespacedSearcherInterface)
|
||||||
var clusterResources = make(map[string]clusterSearcherInterface)
|
var clusterResources = make(map[string]clusterSearcherInterface)
|
||||||
|
|
||||||
type conditions struct {
|
|
||||||
match map[string]string
|
|
||||||
fuzzy map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
name = "name"
|
name = "name"
|
||||||
label = "label"
|
label = "label"
|
||||||
@@ -123,33 +84,26 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type namespacedSearcherInterface interface {
|
type namespacedSearcherInterface interface {
|
||||||
search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error)
|
search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||||
}
|
}
|
||||||
type clusterSearcherInterface interface {
|
type clusterSearcherInterface interface {
|
||||||
search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error)
|
search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListNamespaceResource(namespace, resource, conditionStr, orderBy string, reverse bool, limit, offset int) (*ResourceList, error) {
|
func ListNamespaceResource(namespace, resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||||
items := make([]interface{}, 0)
|
items := make([]interface{}, 0)
|
||||||
total := 0
|
total := 0
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
conditions, err := parseToConditions(conditionStr)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []interface{}
|
var result []interface{}
|
||||||
|
|
||||||
if searcher, ok := namespacedResources[resource]; ok {
|
if searcher, ok := namespacedResources[resource]; ok {
|
||||||
result, err = searcher.search(namespace, conditions, orderBy, reverse)
|
result, err = searcher.search(namespace, conditions, orderBy, reverse)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New(errors.NotImplement, "not support")
|
return nil, fmt.Errorf("not support")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(errors.Internal, err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
total = len(result)
|
total = len(result)
|
||||||
@@ -160,16 +114,14 @@ func ListNamespaceResource(namespace, resource, conditionStr, orderBy string, re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ResourceList{TotalCount: total, Items: items}, nil
|
return &models.PageableResponse{TotalCount: total, Items: items}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, limit, offset int) (*ResourceList, error) {
|
func ListClusterResource(resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||||
items := make([]interface{}, 0)
|
items := make([]interface{}, 0)
|
||||||
total := 0
|
total := 0
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
conditions, err := parseToConditions(conditionStr)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -179,11 +131,11 @@ func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, l
|
|||||||
if searcher, ok := clusterResources[resource]; ok {
|
if searcher, ok := clusterResources[resource]; ok {
|
||||||
result, err = searcher.search(conditions, orderBy, reverse)
|
result, err = searcher.search(conditions, orderBy, reverse)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New(errors.NotImplement, "not support")
|
return nil, fmt.Errorf("not support")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(errors.Internal, err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
total = len(result)
|
total = len(result)
|
||||||
@@ -194,36 +146,7 @@ func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, l
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ResourceList{TotalCount: total, Items: items}, nil
|
return &models.PageableResponse{TotalCount: total, Items: items}, nil
|
||||||
}
|
|
||||||
|
|
||||||
func parseToConditions(str string) (*conditions, error) {
|
|
||||||
conditions := &conditions{match: make(map[string]string, 0), fuzzy: make(map[string]string, 0)}
|
|
||||||
|
|
||||||
if str == "" {
|
|
||||||
return conditions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range strings.Split(str, ",") {
|
|
||||||
if strings.Count(item, "=") > 1 || strings.Count(item, "~") > 1 {
|
|
||||||
return nil, errors.New(errors.InvalidArgument, "invalid condition")
|
|
||||||
}
|
|
||||||
if groups := regexp.MustCompile(`(\S+)([=~])(\S+)`).FindStringSubmatch(item); len(groups) == 4 {
|
|
||||||
if groups[2] == "=" {
|
|
||||||
conditions.match[groups[1]] = groups[3]
|
|
||||||
} else {
|
|
||||||
conditions.fuzzy[groups[1]] = groups[3]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, errors.New(errors.InvalidArgument, "invalid condition")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return conditions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResourceList struct {
|
|
||||||
TotalCount int `json:"total_count"`
|
|
||||||
Items []interface{} `json:"items"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchFuzzy(m map[string]string, key, value string) bool {
|
func searchFuzzy(m map[string]string, key, value string) bool {
|
||||||
|
|||||||
@@ -18,20 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
rbac "k8s.io/api/rbac/v1"
|
rbac "k8s.io/api/rbac/v1"
|
||||||
lister "k8s.io/client-go/listers/rbac/v1"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type roleSearcher struct {
|
type roleSearcher struct {
|
||||||
roleLister lister.RoleLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
|
func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -46,7 +45,7 @@ func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
|
func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -87,8 +86,8 @@ func (*roleSearcher) compare(a, b *rbac.Role, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *roleSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *roleSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
roles, err := s.roleLister.Roles(namespace).List(labels.Everything())
|
roles, err := informers.SharedInformerFactory().Rbac().V1().Roles().Lister().Roles(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -96,11 +95,11 @@ func (s *roleSearcher) search(namespace string, conditions *conditions, orderBy
|
|||||||
|
|
||||||
result := make([]*rbac.Role, 0)
|
result := make([]*rbac.Role, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = roles
|
result = roles
|
||||||
} else {
|
} else {
|
||||||
for _, item := range roles {
|
for _, item := range roles {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type secretSearcher struct {
|
type secretSearcher struct {
|
||||||
secretLister lister.SecretLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
|
func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -50,7 +49,7 @@ func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
|
func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -95,8 +94,8 @@ func (*secretSearcher) compare(a, b *v1.Secret, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *secretSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *secretSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
secrets, err := s.secretLister.Secrets(namespace).List(labels.Everything())
|
secrets, err := informers.SharedInformerFactory().Core().V1().Secrets().Lister().Secrets(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -104,11 +103,11 @@ func (s *secretSearcher) search(namespace string, conditions *conditions, orderB
|
|||||||
|
|
||||||
result := make([]*v1.Secret, 0)
|
result := make([]*v1.Secret, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = secrets
|
result = secrets
|
||||||
} else {
|
} else {
|
||||||
for _, item := range secrets {
|
for _, item := range secrets {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type serviceSearcher struct {
|
type serviceSearcher struct {
|
||||||
serviceLister lister.ServiceLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
|
func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -46,7 +45,7 @@ func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
|
func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -91,8 +90,8 @@ func (*serviceSearcher) compare(a, b *v1.Service, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *serviceSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
services, err := s.serviceLister.Services(namespace).List(labels.Everything())
|
services, err := informers.SharedInformerFactory().Core().V1().Services().Lister().Services(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -100,11 +99,11 @@ func (s *serviceSearcher) search(namespace string, conditions *conditions, order
|
|||||||
|
|
||||||
result := make([]*v1.Service, 0)
|
result := make([]*v1.Service, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = services
|
result = services
|
||||||
} else {
|
} else {
|
||||||
for _, item := range services {
|
for _, item := range services {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,16 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
lister "k8s.io/client-go/listers/apps/v1"
|
|
||||||
|
|
||||||
"k8s.io/api/apps/v1"
|
"k8s.io/api/apps/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
type statefulSetSearcher struct {
|
type statefulSetSearcher struct {
|
||||||
statefulSetLister lister.StatefulSetLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func statefulSetStatus(item *v1.StatefulSet) string {
|
func statefulSetStatus(item *v1.StatefulSet) string {
|
||||||
@@ -44,7 +43,7 @@ func statefulSetStatus(item *v1.StatefulSet) string {
|
|||||||
return stopped
|
return stopped
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exactly match
|
// Exactly Match
|
||||||
func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool {
|
func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -105,8 +104,8 @@ func (*statefulSetSearcher) compare(a, b *v1.StatefulSet, orderBy string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *statefulSetSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *statefulSetSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
statefulSets, err := s.statefulSetLister.StatefulSets(namespace).List(labels.Everything())
|
statefulSets, err := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister().StatefulSets(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -114,11 +113,11 @@ func (s *statefulSetSearcher) search(namespace string, conditions *conditions, o
|
|||||||
|
|
||||||
result := make([]*v1.StatefulSet, 0)
|
result := make([]*v1.StatefulSet, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = statefulSets
|
result = statefulSets
|
||||||
} else {
|
} else {
|
||||||
for _, item := range statefulSets {
|
for _, item := range statefulSets {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,19 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/api/storage/v1"
|
"k8s.io/api/storage/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
lister "k8s.io/client-go/listers/storage/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type storageClassesSearcher struct {
|
type storageClassesSearcher struct {
|
||||||
storageClassesLister lister.StorageClassLister
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// exactly match
|
// exactly Match
|
||||||
func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool {
|
func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -45,7 +45,7 @@ func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageCl
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzy searchInNamespace
|
// Fuzzy searchInNamespace
|
||||||
func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool {
|
func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool {
|
||||||
for k, v := range fuzzy {
|
for k, v := range fuzzy {
|
||||||
switch k {
|
switch k {
|
||||||
@@ -86,8 +86,8 @@ func (*storageClassesSearcher) compare(a, b *v1.StorageClass, orderBy string) bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storageClassesSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
func (s *storageClassesSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||||
storageClasses, err := s.storageClassesLister.List(labels.Everything())
|
storageClasses, err := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister().List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -95,11 +95,11 @@ func (s *storageClassesSearcher) search(conditions *conditions, orderBy string,
|
|||||||
|
|
||||||
result := make([]*v1.StorageClass, 0)
|
result := make([]*v1.StorageClass, 0)
|
||||||
|
|
||||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||||
result = storageClasses
|
result = storageClasses
|
||||||
} else {
|
} else {
|
||||||
for _, item := range storageClasses {
|
for _, item := range storageClasses {
|
||||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) {
|
||||||
result = append(result, item)
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,29 +24,11 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/api/apps/v1"
|
"k8s.io/api/apps/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
lister "k8s.io/client-go/listers/apps/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
daemonSetLister lister.DaemonSetLister
|
|
||||||
deploymentLister lister.DeploymentLister
|
|
||||||
replicaSetLister lister.ReplicaSetLister
|
|
||||||
statefulSetLister lister.StatefulSetLister
|
|
||||||
controllerRevisionLister lister.ControllerRevisionLister
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
daemonSetLister = informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister()
|
|
||||||
deploymentLister = informers.SharedInformerFactory().Apps().V1().Deployments().Lister()
|
|
||||||
replicaSetLister = informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
|
|
||||||
statefulSetLister = informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister()
|
|
||||||
controllerRevisionLister = informers.SharedInformerFactory().Apps().V1().ControllerRevisions().Lister()
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error) {
|
func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error) {
|
||||||
|
deploymentLister := informers.SharedInformerFactory().Apps().V1().Deployments().Lister()
|
||||||
deploy, err := deploymentLister.Deployments(namespace).Get(name)
|
deploy, err := deploymentLister.Deployments(namespace).Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("get deployment %s failed, reason: %s", name, err)
|
glog.Errorf("get deployment %s failed, reason: %s", name, err)
|
||||||
@@ -56,6 +38,7 @@ func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error)
|
|||||||
labelMap := deploy.Spec.Template.Labels
|
labelMap := deploy.Spec.Template.Labels
|
||||||
labelSelector := labels.Set(labelMap).AsSelector()
|
labelSelector := labels.Set(labelMap).AsSelector()
|
||||||
|
|
||||||
|
replicaSetLister := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
|
||||||
rsList, err := replicaSetLister.ReplicaSets(namespace).List(labelSelector)
|
rsList, err := replicaSetLister.ReplicaSets(namespace).List(labelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -67,11 +50,11 @@ func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("revision not found %v#%v", name, revision))
|
return nil, fmt.Errorf("revision not found %v#%v", name, revision)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
|
func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
|
||||||
|
daemonSetLister := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister()
|
||||||
ds, err := daemonSetLister.DaemonSets(namespace).Get(name)
|
ds, err := daemonSetLister.DaemonSets(namespace).Get(name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -84,7 +67,7 @@ func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.Controll
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
|
func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
|
||||||
|
statefulSetLister := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister()
|
||||||
st, err := statefulSetLister.StatefulSets(namespace).Get(name)
|
st, err := statefulSetLister.StatefulSets(namespace).Get(name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -97,7 +80,7 @@ func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.Contro
|
|||||||
func getControllerRevision(namespace, name string, labelMap map[string]string, revision int) (*v1.ControllerRevision, error) {
|
func getControllerRevision(namespace, name string, labelMap map[string]string, revision int) (*v1.ControllerRevision, error) {
|
||||||
|
|
||||||
labelSelector := labels.Set(labelMap).AsSelector()
|
labelSelector := labels.Set(labelMap).AsSelector()
|
||||||
|
controllerRevisionLister := informers.SharedInformerFactory().Apps().V1().ControllerRevisions().Lister()
|
||||||
revisions, err := controllerRevisionLister.ControllerRevisions(namespace).List(labelSelector)
|
revisions, err := controllerRevisionLister.ControllerRevisions(namespace).List(labelSelector)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -110,5 +93,5 @@ func getControllerRevision(namespace, name string, labelMap map[string]string, r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("revision not found %v#%v", name, revision))
|
return nil, fmt.Errorf("revision not found %v#%v", name, revision)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,15 +23,12 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
v12 "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
coreV1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
extensionsV1beta1 "k8s.io/api/extensions/v1beta1"
|
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
|
||||||
"k8s.io/api/rbac/v1"
|
"k8s.io/api/rbac/v1"
|
||||||
@@ -43,18 +40,10 @@ import (
|
|||||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func GetAllRouters() ([]*corev1.Service, error) {
|
||||||
serviceLister v12.ServiceLister
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAllRouters() ([]*coreV1.Service, error) {
|
|
||||||
|
|
||||||
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend"})
|
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend"})
|
||||||
|
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||||
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
|
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -65,7 +54,7 @@ func GetAllRouters() ([]*coreV1.Service, error) {
|
|||||||
return services, nil
|
return services, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
func GetAllRoutersOfUser(username string) ([]*corev1.Service, error) {
|
||||||
allNamespace, namespaces, err := iam.GetUserNamespaces(username, v1.PolicyRule{
|
allNamespace, namespaces, err := iam.GetUserNamespaces(username, v1.PolicyRule{
|
||||||
Verbs: []string{"get", "list"},
|
Verbs: []string{"get", "list"},
|
||||||
APIGroups: []string{""},
|
APIGroups: []string{""},
|
||||||
@@ -82,7 +71,7 @@ func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
|||||||
return GetAllRouters()
|
return GetAllRouters()
|
||||||
}
|
}
|
||||||
|
|
||||||
routers := make([]*coreV1.Service, 0)
|
routers := make([]*corev1.Service, 0)
|
||||||
|
|
||||||
for _, namespace := range namespaces {
|
for _, namespace := range namespaces {
|
||||||
router, err := GetRouter(namespace)
|
router, err := GetRouter(namespace)
|
||||||
@@ -99,11 +88,11 @@ func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get router from a namespace
|
// Get router from a namespace
|
||||||
func GetRouter(namespace string) (*coreV1.Service, error) {
|
func GetRouter(namespace string) (*corev1.Service, error) {
|
||||||
serviceName := constants.IngressControllerPrefix + namespace
|
serviceName := constants.IngressControllerPrefix + namespace
|
||||||
|
|
||||||
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend", "project": namespace})
|
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend", "project": namespace})
|
||||||
|
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||||
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
|
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -116,7 +105,7 @@ func GetRouter(namespace string) (*coreV1.Service, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("resources not found %s", serviceName))
|
return nil, fmt.Errorf("resources not found %s", serviceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all resource yamls
|
// Load all resource yamls
|
||||||
@@ -148,11 +137,11 @@ func LoadYamls() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a ingress controller in a namespace
|
// Create a ingress controller in a namespace
|
||||||
func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) {
|
func CreateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
|
||||||
|
|
||||||
k8sClient := client.K8sClient()
|
k8sClient := client.K8sClient()
|
||||||
|
|
||||||
var router *coreV1.Service
|
var router *corev1.Service
|
||||||
|
|
||||||
yamls, err := LoadYamls()
|
yamls, err := LoadYamls()
|
||||||
|
|
||||||
@@ -170,8 +159,8 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *coreV1.Service:
|
case *corev1.Service:
|
||||||
service := obj.(*coreV1.Service)
|
service := obj.(*corev1.Service)
|
||||||
|
|
||||||
service.SetAnnotations(annotations)
|
service.SetAnnotations(annotations)
|
||||||
service.Spec.Type = routerType
|
service.Spec.Type = routerType
|
||||||
@@ -190,8 +179,8 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
|||||||
|
|
||||||
router = service
|
router = service
|
||||||
|
|
||||||
case *extensionsV1beta1.Deployment:
|
case *extensionsv1beta1.Deployment:
|
||||||
deployment := obj.(*extensionsV1beta1.Deployment)
|
deployment := obj.(*extensionsv1beta1.Deployment)
|
||||||
deployment.Name = constants.IngressControllerPrefix + namespace
|
deployment.Name = constants.IngressControllerPrefix + namespace
|
||||||
|
|
||||||
// Add project label
|
// Add project label
|
||||||
@@ -204,7 +193,7 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
|||||||
// Choose self as master
|
// Choose self as master
|
||||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
|
||||||
|
|
||||||
if routerType == coreV1.ServiceTypeLoadBalancer {
|
if routerType == corev1.ServiceTypeLoadBalancer {
|
||||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
|
||||||
} else {
|
} else {
|
||||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
|
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
|
||||||
@@ -224,11 +213,11 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
|||||||
|
|
||||||
// DeleteRouter is used to delete ingress controller related resources in namespace
|
// DeleteRouter is used to delete ingress controller related resources in namespace
|
||||||
// It will not delete ClusterRole resource cause it maybe used by other controllers
|
// It will not delete ClusterRole resource cause it maybe used by other controllers
|
||||||
func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
func DeleteRouter(namespace string) (*corev1.Service, error) {
|
||||||
k8sClient := client.K8sClient()
|
k8sClient := client.K8sClient()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var router *coreV1.Service
|
var router *corev1.Service
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
@@ -236,9 +225,9 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
|||||||
|
|
||||||
// delete controller service
|
// delete controller service
|
||||||
serviceName := constants.IngressControllerPrefix + namespace
|
serviceName := constants.IngressControllerPrefix + namespace
|
||||||
deleteOptions := metaV1.DeleteOptions{}
|
deleteOptions := meta_v1.DeleteOptions{}
|
||||||
|
|
||||||
listOptions := metaV1.ListOptions{
|
listOptions := meta_v1.ListOptions{
|
||||||
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
||||||
FieldSelector: "metadata.name=" + serviceName}
|
FieldSelector: "metadata.name=" + serviceName}
|
||||||
|
|
||||||
@@ -259,7 +248,7 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
|||||||
// delete controller deployment
|
// delete controller deployment
|
||||||
deploymentName := constants.IngressControllerPrefix + namespace
|
deploymentName := constants.IngressControllerPrefix + namespace
|
||||||
|
|
||||||
listOptions = metaV1.ListOptions{
|
listOptions = meta_v1.ListOptions{
|
||||||
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
||||||
}
|
}
|
||||||
deployments, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).List(listOptions)
|
deployments, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).List(listOptions)
|
||||||
@@ -279,10 +268,10 @@ func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update Ingress Controller Service, change type from NodePort to Loadbalancer or vice versa.
|
// Update Ingress Controller Service, change type from NodePort to Loadbalancer or vice versa.
|
||||||
func UpdateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) {
|
func UpdateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
|
||||||
k8sClient := client.K8sClient()
|
k8sClient := client.K8sClient()
|
||||||
|
|
||||||
var router *coreV1.Service
|
var router *corev1.Service
|
||||||
|
|
||||||
router, err := GetRouter(namespace)
|
router, err := GetRouter(namespace)
|
||||||
|
|
||||||
@@ -293,7 +282,7 @@ func UpdateRouter(namespace string, routerType coreV1.ServiceType, annotations m
|
|||||||
|
|
||||||
if router == nil {
|
if router == nil {
|
||||||
glog.Error("Trying to update a non-existed router")
|
glog.Error("Trying to update a non-existed router")
|
||||||
return nil, errors.New(errors.Internal, "router not created yet")
|
return nil, fmt.Errorf("router not created yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
// from LoadBalancer to NodePort, or vice-versa
|
// from LoadBalancer to NodePort, or vice-versa
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
package status
|
package status
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||||
)
|
)
|
||||||
@@ -31,7 +32,7 @@ type workLoadStatus struct {
|
|||||||
|
|
||||||
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
||||||
res := workLoadStatus{Count: make(map[string]int), Namespace: namespace, Items: make(map[string]interface{})}
|
res := workLoadStatus{Count: make(map[string]int), Namespace: namespace, Items: make(map[string]interface{})}
|
||||||
var notReadyList *resources.ResourceList
|
var notReadyList *models.PageableResponse
|
||||||
var err error
|
var err error
|
||||||
for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims} {
|
for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims} {
|
||||||
notReadyStatus := "updating"
|
notReadyStatus := "updating"
|
||||||
@@ -39,7 +40,7 @@ func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
|||||||
notReadyStatus = "pending"
|
notReadyStatus = "pending"
|
||||||
}
|
}
|
||||||
|
|
||||||
notReadyList, err = resources.ListNamespaceResource(namespace, resource, fmt.Sprintf("status=%s", notReadyStatus), "", false, -1, 0)
|
notReadyList, err = resources.ListNamespaceResource(namespace, resource, ¶ms.Conditions{Match: map[string]string{"status": notReadyStatus}}, "", false, -1, 0)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ import (
|
|||||||
storageV1 "k8s.io/api/storage/v1"
|
storageV1 "k8s.io/api/storage/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
lister "k8s.io/client-go/listers/core/v1"
|
|
||||||
lister2 "k8s.io/client-go/listers/storage/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,18 +33,12 @@ type ScMetrics struct {
|
|||||||
PvcNumber string `json:"pvcNumber"`
|
PvcNumber string `json:"pvcNumber"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
|
|
||||||
persistentVolumeLister lister.PersistentVolumeLister
|
|
||||||
sotrageClassesLister lister2.StorageClassLister
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
persistentVolumeClaimLister = informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
|
|
||||||
persistentVolumeLister = informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
|
func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
|
||||||
|
persistentVolumeClaimLister := informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
|
||||||
all, err := persistentVolumeClaimLister.List(labels.Everything())
|
all, err := persistentVolumeClaimLister.List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -70,6 +61,7 @@ func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
|
|||||||
|
|
||||||
// Get info of metrics
|
// Get info of metrics
|
||||||
func GetScMetrics(scName string) (*ScMetrics, error) {
|
func GetScMetrics(scName string) (*ScMetrics, error) {
|
||||||
|
persistentVolumeLister := informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
|
||||||
pvList, err := persistentVolumeLister.List(labels.Everything())
|
pvList, err := persistentVolumeLister.List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -102,7 +94,7 @@ func GetScMetrics(scName string) (*ScMetrics, error) {
|
|||||||
func GetScList() ([]*storageV1.StorageClass, error) {
|
func GetScList() ([]*storageV1.StorageClass, error) {
|
||||||
|
|
||||||
// Get StorageClass list
|
// Get StorageClass list
|
||||||
scList, err := sotrageClassesLister.List(labels.Everything())
|
scList, err := informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister().List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -20,19 +20,12 @@ package storage
|
|||||||
import (
|
import (
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
v12 "k8s.io/client-go/listers/core/v1"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
)
|
)
|
||||||
|
|
||||||
var podLister v12.PodLister
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
podLister = informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
|
||||||
}
|
|
||||||
|
|
||||||
// List pods of a specific persistent volume claims
|
// List pods of a specific persistent volume claims
|
||||||
func GetPodListByPvc(pvc string, ns string) (res []*v1.Pod, err error) {
|
func GetPodListByPvc(pvc string, ns string) (res []*v1.Pod, err error) {
|
||||||
|
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||||
podList, err := podLister.Pods(ns).List(labels.Everything())
|
podList, err := podLister.Pods(ns).List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user